Sketch 1. “A seemingly simple method”
Write how you would implement a method that returns the result of dividing number a by number b. The interviewer writes on a piece of paperint divide(int a, int b) {
}
*I glanced incredulously at the piece of paper with the method signature. What's the catch?* I write:
int divide(int a, int b) {
return a/b;
}
Are there any problems with this method? *I'm catching a really stupid dumbass* Apparently not.. Next comes a legitimate question: What if b=0? *Whoa, I'm about to be kicked out of this office if I continue like this!* Oh yes, of course. Here we have arguments of type int, so an Arithmetic Exception will be thrown. If the arguments were of type float or double, the result would be Infinity. What are we going to do about this? I'm starting to write try/catch
int divide(int a, int b) {
try {
return a/b;
} catch (Exception e) {
e.printStackTrace();
return ... // ??? what the hack?
}
}
*I get to return and freeze: something needs to be returned in case of an error. But how can this “something” be distinguished from the result of the calculation?* What will we return? Hm... I would change the type of the return variable to Integer and in case of an exception I would return null. Let's imagine that we can't change the type. Can we somehow get out? Maybe we can do something else with the exception? *Here it comes* We can also forward it to the calling method! Right. What will it look like?
int divide(int a, int b) throws ArithmeticException{
return a/b;
}
void callDivide(int a, int b) {
try {
divide(a, b);
} catch (ArithmeticException e) {
e.printStackTrace();
}
}
Is it necessary to handle the exception? Yes, because we explicitly forward it from the divide method. (*I was wrong here! What follows are leading questions from the interviewer to arrive at the correct answer*) And Arithmetic Exception - what kind of exception is it - checked or unchecked? This is a Runtime exception, which means unchecked. *Here comes the killer question* So it turns out, in your words, if we specified throws Arithmetic Exception in the method signature, then it became a checked exception? *Ugh!* Probably... no. Yes, it's gone. If we indicate throws /unchecked exception/ in the signature, we only warn that the method can throw an exception, but it is not necessary to handle it in the calling method. That's sorted out. Is there anything else we can do to avoid mistakes? *After some thought* Yes, we can also check if (b==0). And perform some logic. Right. So we can go 3 ways:
- try/catch
- throws – forwarding to the calling method
- argument checking
divide
which method do you think is preferable? I would choose to forward the exception to the calling method, because... in the divide method it is not clear how to process this exception and what type of result int
to return in case of an error. And in the calling method, I would use the argument b to check if it is equal to zero. It seems that this answer satisfied the interviewee, but to be honest, I’m not sure that this answer is unambiguous))
Sketch 2. “Who is faster?”
After the standard question, how does an ArrayList differ from a LinkedList, came this: What will happen faster - inserting an element into the middleArrayList
or into the middle LinkedList
? *Here I jumped, I remembered that everywhere I read something like “use LinkedList
to insert or remove elements in the middle of the list.” At home I even double-checked the JavaRush lectures, there is a phrase: “if you are going to insert (or delete) many elements into the middle of a collection, then you better use LinkedList
. In all other cases - ArrayList
.” Automatically answered* It will be faster with LinkedList
. Clarify please
- In order to insert an element in the middle
ArrayList
, we find the element in the list in constant time, and then recalculate the indices of the elements to the right of the inserted one, in linear time. - For
LinkedList
.. We first reach the middle in linear time and then insert an element in constant time, changing links for neighboring elements.
LinkedList
faster? It turns out that when we insert it into the first half of the list. For example, if you insert it at the very beginning, you ArrayList
will have to recalculate all the indices up to the very tail, but you LinkedList
will only have to change the reference of the first element. Moral: do not believe literally everything that is written, even in JavaRush!)
Sketch 3. “Where would we be without equals and hashcode!”
The conversation about equals and hashcode was very long - how to override it, what implementation inObject
, what happens under the hood, when an element is inserted into HashMap
, etc. I will just cite a number of points that are interesting in my opinion* Imagine that we have created a class
public class A {
int id;
public A(int id) {
this.id = id;
}
}
And they didn't override equals
and hashcode
. Describe what will happen when the code is executed
A a1 = new A(1);
A a2 = new A(1);
Map<A, String> hash = new HashMap<>();
hash.put(a1, "1");
hash.get(a2);
*It’s good that before the interview I specifically spent a couple of days understanding the basic algorithms, their complexity and data structures - it helped a lot, thanks CS50!*
-
Create two instances of class A
-
We create an empty map, which by default has 16 baskets. The key is an object of class A, in which the
equals
and methods are not overriddenhashcode
. -
Put it
a1
in the map. To do this, we first calculate the hasha1
.What will the hash be equal to?
The address of a cell in memory is an implementation of a method from a class
Object
-
Based on the hash, we calculate the basket index.
How can we calculate it?
*Unfortunately, I did not give a clear answer here. You have a long number - a hash, and there are 16 buckets - how to define an index so that objects with different hashes are evenly distributed across the buckets? I could imagine that the index is calculated like this:
int index = hash % buckets.length
Already at home I saw that the original implementation in the source code is slightly different:
static int indexFor(int h, int length) { return h & (length - 1); }
-
We check that there are no collisions and insert a1.
-
Let's move on to the method
get
. Instances a1 and a2 are guaranteed to have a differenthash
(different address in memory), so we will not find anything for this keyWhat if we redefine it only
hashcode
in class A and try to insert into the hashmap first a pair with key a1, and then with a2?Then first we will find the desired basket by
hashcode
- this operation will be performed correctly. Next, let's start going through the objectsEntry
in the LinkedList attached to the cart and compare the keys byequals
. Becauseequals
is not overridden, then the base implementation is taken from the classObject
- comparison by reference. a1 and a2 are guaranteed to have different links, so we will “miss” the inserted element a1, and a2 will be placed in the LinkedList as a new node.What is the conclusion? Is it possible to use it as a key in
HashMap
an object with non-overriddenequalshashcode
?No you can not.
Sketch 4. “Let’s break it on purpose!”
After the questions about Error and Exception, the following question followed: Write a simple example where a function will throw StackOverflow. *Then I remembered how this error plagued me when I was trying to write some recursive function* This will probably happen in the case of a recursive call, if the condition for exiting the recursion is incorrectly specified. *Then I began to try something clever, in the end the interviewer helped, everything turned out to be simple*void sof() {
sof();
}
How is this error different from OutOfMemory
? *I didn’t answer here, only later I realized that this was a question about knowledge Stack
of Heap
Java memory (calls and references to objects are stored in the Stack, and the objects themselves are stored in Heap memory). Accordingly, StackOverflow is thrown out when there is no more space in Stack
memory for the next method call, and OutOfMemory
the space for objects has run out in Heap
memory*
These are the moments from the interview that I remember. In the end, I was accepted for an internship, so I have 2.5 months of training ahead of me and, if everything goes well, a job in the company) If there is interest, I can write another article, this time smaller, with an analysis of a simple but illustrative problem that I was given an interview at another company. That's all for me, I hope this article will help someone deepen or organize their knowledge. Happy learning everyone!