Ten Java Myths and Misconceptions
Advanced Java Questions
These questions delve into Java's more intricate behaviors and are often too advanced for typical interviews, as they might be discouraging for candidates. However, they are excellent for deepening your understanding of Java's core workings in your own time.
Myth 1: System.exit(0)
Prevents finally
Block Execution
Consider the following code:
// many frameworks have a SecurityManager
System.setSecurityManager(new SecurityManager() {
@Override
public void checkExit(int status) {
throw new ThreadDeath();
}
});
try {
System.exit(0);
} finally {
System.out.println("In the finally block");
}
This code will output:
In the finally block
Explanation: The System.exit(0)
call triggers the checkExit
method in the custom SecurityManager
. By throwing a ThreadDeath
exception instead of terminating, the finally
block is allowed to execute, explaining the "In the finally block"
output. Since ThreadDeath
is not an error that generates a stack trace by default, no stack trace is printed.
Myth 2: String str = "Hello";
Creates a String Object
Unlike C++, Java variables can only be primitives or references, not actual objects. For instance:
String str = "Hello";
String text = "Bye";
str == text; // Compares two references, not their contents.
str = text; // Assigns the reference held by text to str.
This distinction between objects and references can sometimes be subtle, but it often causes confusion in cases like this:
final StringBuilder sb = new StringBuilder();
sb.append("Hello"); // The reference sb is final, but the instance it references is not.
method(sb); // The method can alter the instance but cannot change the reference.
Explanation: In this example, sb
is a final reference to a StringBuilder
instance. The final
modifier only applies to the reference, meaning sb
cannot be reassigned, but the object it references (the StringBuilder
instance) can be modified, such as by appending text. This is a critical distinction to grasp for understanding immutability and reference manipulation in Java.
Myth 3: Java Has Memory Leaks Like C++
According to Wikipedia, a memory leak is defined as: "In computer science, a memory leak occurs when a computer program incorrectly manages memory allocations. In object-oriented programming, a memory leak may happen when an object is stored in memory but cannot be accessed by the running code."
In Java, however, memory leaks differ from the traditional C++ understanding. Java’s garbage collector automatically cleans up objects that are no longer strongly referenced, meaning objects that are inaccessible to the running code are eventually removed. Still, memory leaks can occur in Java when objects are unintentionally retained, often in collections, long after they are needed, leading to an undesirable increase in retained memory. In this context, a Java memory leak refers to any unintentional memory retention that could degrade performance over time.
Myth 4: Multi-Threading Is Hard
Multi-threading can indeed be challenging—if not approached with discipline. Creating a multi-threaded program without a clear structure or organization often leads to complexity and hard-to-resolve issues.
However, with a disciplined approach, multi-threading can be made manageable. By limiting thread creation to only those required, controlling interactions between threads, and adopting well-understood patterns, multi-threaded programming can be straightforward. The key challenge often lies in ensuring that the entire team consistently follows these best practices. With teamwork and a shared understanding, multi-threading can be made efficient and reliable.
Myth 5: I Don't Need to Understand the Relative Performance of Different Operations to Care About Performance
Performance optimization isn't just about making everything "faster"—it's about understanding the relative cost of different operations. I recently came across a situation where someone was trying to optimize an integer addition by using more expensive operations, like memory access, modulus, and printing to the console. Despite the fact that each of these operations is an order of magnitude slower than addition, the individual was focusing on speeding up the fastest operation while ignoring the larger bottlenecks.
When optimizing for performance, the goal is to replace expensive operations with cheaper ones. If your bottleneck lies in hardware, for example, if you’re reading millions of files from a hard drive, optimizing the software won’t solve the problem—it's not the software causing the slowdown.
Myth 6: Random Numbers Always Look Random
It’s a common misconception that random numbers always appear random. In fact, specific combinations of random numbers are just as likely as those that seem to follow a pattern. This myth was highlighted in a question I posed on this blog, where many people couldn’t believe that a random number generator could produce sequences that look far from random. In reality, the way a pseudo-random number generator works can result in sequences that appear non-random, especially over short intervals, though they are statistically valid.
Myth 7: Floating Point Should Be Avoided Because It Has Random Errors
Floating point arithmetic can be misunderstood, especially when people assume it produces random errors. In reality, the error introduced by floating point operations is predictable—it will be the same every time for the same operation. This predictability makes floating point errors manageable, as long as you understand the behavior and take simple precautions, such as rounding results when necessary.
Moreover, floating point is not inherently less reliable than BigDecimal
—in fact, it is easier to read and about 100 times faster, without generating any additional garbage. When used correctly, floating point operations are just as deterministic and precise as BigDecimal
, but they are more efficient for most use cases.
Myth 8: Timezones Are Timeless
A common source of confusion arises from the fact that timezones are not fixed—they change over time. For instance, the timezone for Europe/London at the epoch (January 1, 1970) was 01:00, not 00:00. This is because London observed Daylight Saving Time (DST) from 1968 to 1970, which shifted the time by one hour during that period.
Many other timezones have undergone changes in recent years. For example, Moscow was previously GMT+4, but as of March 27, 2011, it switched to GMT+3. If you check the time for Moscow in 2010, it would have been GMT+4, not GMT+3.
These changes in timezones may seem strange, but history provides even more unusual examples:
- In Sweden, 1721, there was a February 30th.
- In England, 1751, the first day of the year was March 25th, and there was an 11-day difference between England and France.
- When the USA adopted the Gregorian calendar, they did so retrospectively, which caused historical dates to refer to either the Julian or Gregorian calendar, often requiring both dates to be given. For instance, George Washington's birthday was changed from February 11, 1731 (Julian) to February 22, 1732 (Gregorian).
Myth 9: When You Read a Non-Volatile Value in One Thread, You Will Eventually See an Updated Value
This myth came up recently on StackOverflow, and it's crucial to understand how the Java JIT compiler works. The JIT can optimize code by in-lining non-volatile fields that are not modified by other threads. As a result, when the code compiles (you can observe this using -XX:+PrintCompilation
), a thread may never see changes made to a non-volatile variable in another thread.
To force visibility of changes between threads, you must use the volatile
keyword. Without it, a thread may never see updated values, even if another thread modifies them. Adding random synchronized blocks or print statements can sometimes interfere with the JIT optimization, causing it to either delay or entirely skip the optimization, thus ensuring the value is read correctly.
Myth 10: Most Content on Java Interview Questions Is Accurate
A significant portion of Java interview questions found online are outdated, misleading, or simply wrong. Many of these questions are recycled without checking the accuracy of the answers, which often only apply to older versions of Java (more than ten years ago) and no longer reflect modern Java practices.
Comments
Post a Comment