1. What’s the difference between String, StringBuffer, and StringBuilder?
String
is an immutable class. In older JDKs the recommendation when programmatically building a String was to use StringBuffer
since this was optimized to concatenate multiple Strings together.
However, the methods StringBuffer
were marked as synchronized, which meant that there was a performance penalty, hence StringBuilder
was introduced to provide a non-synchronized way to efficiently concatenate and modify Strings
.
2. How do you run a Java application on the command line and set the classpath with multiple jars?
This is one of those Java interview questions where some people will be thinking what!? But, I’ve met a lot of Java developers who’ve not run a Java application outside of an IDE for years.
java -cp /dev/myapp.jar:/dev/mydependency.jar com.arc.MyApp
3. What is the difference between final, finalize and finally?
final
is a Java keyword used to indicate that either a method can not override in a subclass, or a class can not be extended or a field can not be modified. finalize
is a method that gets called on an instance of an Object when it is garbage collected. finally
is a Java keyword used in exception handling to indicate a block of code that should always be run whether an exception is thrown or not.
4. How does Garbage Collection prevent a Java application from going out of memory?
This is a tricky Java interview question… it doesn’t have to be!
Garbage Collection simply cleans up unused memory when an object goes out of scope and is no longer needed. However, an application could create a huge number of large objects that causes an OutOfMemoryError.
5. What’s the difference between a ClassNotFoundException and NoClassDefFoundError?
A ClassNotFoundException means the class file for a requested class is not on the classpath of the application. A NoClassDefFoundErrormeans that the class file existed at runtime, but for some reason the class could not be turned into a Class definition.
A common cause is an exception being thrown in static initialization blocks.
6. Why isn’t String‘s .length() accurate?
It isn’t accurate because it will only account for the number of characters within the String. In other words, it will fail to account for code points outside of what is called the BMP (Basic Multilingual Plane), that is, code points with a value of U+10000
or greater.
The reason is historical: when Java was first defined, one of its goal was to treat all text as Unicode; but at this time, Unicode did not define code points outside of the BMP. By the time Unicode defined such code points, it was too late for char to be changed.
This means that code points outside the BMP are represented with two chars in Java, in what is called a surrogate pair. Technically, a char in Java is a UTF-16 code unit.
The correct way to count the real numbers of characters within a String, i.e. the number of code points, is either:
someString.codePointCount(0, someString.length())
or, with Java 8:
someString.codePoints().count()
7. Given two double values d1, d2, why isn’t it reliable to test their equality using:
d1 == d2
Because of Double.NaN
(literally: “Not a Number”).
This code:
final double d1 = Double.NaN;
final double d2 = Double.NaN;
System.out.println(d1 == d2);
will print false
.
The most accurate way to tell whether two double values are equal to one another is to use Double.compare()
and test against 0, as in:
System.out.println(Double.compare(d1, d2) == 0);
8. What is the problem with this code:
final byte[] bytes = someString.getBytes();
There are, in fact, two problems:
- the code relies on the default Charset of the JVM;
- it supposes that this default Charset can handle all characters.
While the second problem is rarely a concern, the first certainly is a concern.
For instance, in most Windows installations, the default charset is CP1252
; but on Linux installations, the default charset will be UTF-8.
As such, such a simple string as “é” will give a different result for this operation depending on whether this code is run on Windows or Linux.
The solution is to always specify a Charset, as in, for instance:
final byte[] bytes = someString.getBytes(StandardCharsets.UTF_8);
The what is the problem with this code? question is one of the most popular Java interview questions, but it’s not necessarily going to be this one above, of course. Be prepared to do some detective work to identify the issue.
Also, keep in mind: while the problem may be exception handling, method overloading, an access specifier issue, or something else, it could also be nothing at all! This is one of those trick Java interview questions where the answer will rely on your gut that everything is perfect with the code already.
9. What is the JIT?
The JIT is the JVM’s mechanism by which it can optimize code at runtime.
JIT means Just In Time. It is a central feature of any JVM. Among other optimizations, it can perform code inlining, lock coarsening or lock eliding, escape analysis etc.
The main benefit of the JIT is on the programmer’s side: code should be written so that it just works; if the code can be optimized at runtime, more often than not, the JIT will find a way.
(On a more advanced note: the JIT is such a complex piece of machinery that it makes it complicated to do accurate performance benchmarks for JVM code; this is why such frameworks as JMH exist.)
10. How do you make this code print 0.5 instead of 0?
This code:
final double d = 1 / 2;
System.out.println(d);
prints 0
. Why? How do you make this code print 0.5
instead?
The problem here is that this expression:
1 / 2
has integer literals on both sides of the operator: 1
and 2
. As a consequence, an integer division will be performed, and the result of 1
divided by 2
in an integer division is 0
.
In order for the result to be a double as expected, at least one operand of the operation needs to be a double. For instance:
final double d = 1 / 2.0;
or:
final double d = 1.0 / 2;