Which feature of the Java-language is the source of the most misunderstandings and bugs in your experience? The scope of this question is about the language, not the class-library.
Reflection?
Allows you to do pretty much anything and break all rules.
Threading and concurrency, hands down.
This isn't just Java-specific though. Multithreading is by nature difficult.
As a source of bugs: concurrency. Since 1.5 life for the programmer is a lot easier thanks to java.util.concurrent though.
For misunderstanding: writing a good hashCode() method, serialization and class versions.
Misunderstandings and source for bugs? Here:
((aString == anotherString) && (aString.equals(anotherString))
// can be true or false - you never know
and another classic one:
aString.equals("I love NPE"); // **Boom** if aString == null
The fact that Integer
, Boolean
and so on are immutable. With Autoboxing it can get especially weird:
public static void test(Integer i)
{
++i;
}
This method actually does nothing, except creating a new Integer
and assigning it to i
. It doesn't modify the object pointed to by i
.
The take-first-found approach to class search is also risky. It's not frequently a problem, but when it is, it's a bi*tch to debug.
I'm talking about how classes are searched in the specified classpath; too easy to end up with conflicting versions when using different libraries that are out of synch and include (and export) too many common classes.
The implementation of inner classes seems to be a good candidate. This article has a detailed discussion.
The belief that finalize() will be executed in a timely manner is a great way to run out of resources other than just memory.
Synchronization. Too often 'synchronized' is stuck on a method in an attempt to make a critical section.
Allow for invoking non-final methods in constructor is a big pitfall!
I wrote a similar code 4 years ago:
abstract class BasicModel {
public BasicModel(int id) {
initModel(id);
}
abstract protected void initModel(int id);
}
class AdvancedModel extends BasicModel {
private int id = 0;
public AdvancedModel(int id) {
super(id);
}
protected void initModel(int id) {
this.id = id;
}
public int getId() {
return id;
}
public static void main(String[] args) {
AdvancedModel model = new AdvancedModel(10);
System.out.println("id = " + model.getId());
}
}
Gotcha, it printed "id = 0" to the standard output!!
The fact that object variables are actually object references (and only references) is so fundamental and pervasive in Java that it should be at the top of this list.
The corollary: since everything in Java is passed by value objects are never passed at all. This fact alone makes Java very dangerous when forgotten.
Autoboxing and Unboxing.
Makes for the following code to be legal (resulting in poor performance):
Long result = 0L;
for(Integer i = 0; i < 100000; i++)
{
result = i * i + result /2;
}