There are several differences between HashMap
and Hashtable
in Java:
Hashtable
is synchronized, whereas HashMap
is not. This makes HashMap
better for non-threaded applications, as unsynchronized Objects typically perform better than synchronized ones.
Hashtable
does not allow null
keys or values. HashMap
allows one null
key and any number of null
values.
One of HashMap's subclasses is LinkedHashMap
, so in the event that you'd want predictable iteration order (which is insertion order by default), you could easily swap out the HashMap
for a LinkedHashMap
. This wouldn't be as easy if you were using Hashtable
.
Since synchronization is not an issue for you, I'd recommend HashMap
. If synchronization becomes an issue, you may also look at ConcurrentHashMap
.
Java is always pass-by-value. Unfortunately, when we deal with objects we are really dealing with object-handles called references which are passed-by-value as well. This terminology and semantics easily confuse many beginners.
It goes like this:
public static void main(String[] args) {
Dog aDog = new Dog("Max");
Dog oldDog = aDog;
// we pass the object to foo
foo(aDog);
// aDog variable is still pointing to the "Max" dog when foo(...) returns
aDog.getName().equals("Max"); // true
aDog.getName().equals("Fifi"); // false
aDog == oldDog; // true
}
public static void foo(Dog d) {
d.getName().equals("Max"); // true
// change d inside of foo() to point to a new Dog instance "Fifi"
d = new Dog("Fifi");
d.getName().equals("Fifi"); // true
}
In the example above aDog.getName()
will still return "Max"
. The value aDog
within main
is not changed in the function foo
with the Dog
"Fifi"
as the object reference is passed by value. If it were passed by reference, then the aDog.getName()
in main
would return "Fifi"
after the call to foo
.
Likewise:
public static void main(String[] args) {
Dog aDog = new Dog("Max");
Dog oldDog = aDog;
foo(aDog);
// when foo(...) returns, the name of the dog has been changed to "Fifi"
aDog.getName().equals("Fifi"); // true
// but it is still the same dog:
aDog == oldDog; // true
}
public static void foo(Dog d) {
d.getName().equals("Max"); // true
// this changes the name of d to be "Fifi"
d.setName("Fifi");
}
In the above example, Fifi
is the dog's name after call to foo(aDog)
because the object's name was set inside of foo(...)
. Any operations that foo
performs on d
are such that, for all practical purposes, they are performed on aDog
, but it is not possible to change the value of the variable aDog
itself.
For more information on pass by reference and pass by value, consult the following SO answer: https://stackoverflow.com/a/430958/6005228. This explains more thoroughly the semantics and history behind the two and also explains why Java and many other modern languages appear to do both in certain cases.
Best Answer
Since JSR 305 (whose goal was to standardize
@NonNull
and@Nullable
) has been dormant for several years, I'm afraid there is no good answer. All we can do is to find a pragmatic solution and mine is as follows:Syntax
From a purely stylistic standpoint I would like to avoid any reference to IDE, framework or any toolkit except Java itself.
This rules out:
android.support.annotation
edu.umd.cs.findbugs.annotations
org.eclipse.jdt.annotation
org.jetbrains.annotations
org.checkerframework.checker.nullness.qual
lombok.NonNull
Which leaves us with either
javax.validation.constraints
orjavax.annotation
. The former comes with JEE. If this is better thanjavax.annotation
, which might come eventually with JSE or never at all, is a matter of debate. I personally preferjavax.annotation
because I wouldn't like the JEE dependency.This leaves us with
javax.annotation
which is also the shortest one.
There is only one syntax which would even be better:
java.annotation.Nullable
. As other packages graduated fromjavax
tojava
in the past, the javax.annotation would be a step in the right direction.Implementation
I was hoping that they all have basically the same trivial implementation, but a detailed analysis showed that this is not true.
First for the similarities:
The
@NonNull
annotations all have the lineexcept for
org.jetbrains.annotations
which calls it@NotNull
and has a trivial implementationjavax.annotation
which has a longer implementationjavax.validation.constraints
which also calls it@NotNull
and has an implementationThe
@Nullable
annotations all have the lineexcept for (again) the
org.jetbrains.annotations
with their trivial implementation.For the differences:
A striking one is that
javax.annotation
javax.validation.constraints
org.checkerframework.checker.nullness.qual
all have runtime annotations (
@Retention(RUNTIME)
), whileandroid.support.annotation
edu.umd.cs.findbugs.annotations
org.eclipse.jdt.annotation
org.jetbrains.annotations
are only compile time (
@Retention(CLASS)
).As described in this SO answer the impact of runtime annotations is smaller than one might think, but they have the benefit of enabling tools to do runtime checks in addition to the compile time ones.
Another important difference is where in the code the annotations can be used. There are two different approaches. Some packages use JLS 9.6.4.1 style contexts. The following table gives an overview:
org.eclipse.jdt.annotation
,javax.annotation
andorg.checkerframework.checker.nullness.qual
use the contexts defined in JLS 4.11, which is in my opinion the right way to do it.This leaves us with
javax.annotation
org.checkerframework.checker.nullness.qual
in this round.
Code
To help you to compare further details yourself I list the code of every annotation below. To make comparison easier I removed comments, imports and the
@Documented
annotation. (they all had@Documented
except for the classes from the Android package). I reordered the lines and@Target
fields and normalized the qualifications.For completeness, here are the
@Nullable
implementations:The following two packages have no
@Nullable
, so I list them separately; Lombok has a pretty boring@NonNull
. Injavax.validation.constraints
the@NonNull
is actually a@NotNull
and it has a longish implementation.Support
From my experience,
javax.annotation
is at least supported by Eclipse and the Checker Framework out of the box.Summary
My ideal annotation would be the
java.annotation
syntax with the Checker Framework implementation.If you don't intend to use the Checker Framework the
javax.annotation
(JSR-305) is still your best bet for the time being.If you are willing to buy into the Checker Framework just use their
org.checkerframework.checker.nullness.qual
.Sources
android.support.annotation
fromandroid-5.1.1_r1.jar
edu.umd.cs.findbugs.annotations
fromfindbugs-annotations-1.0.0.jar
org.eclipse.jdt.annotation
fromorg.eclipse.jdt.annotation_2.1.0.v20160418-1457.jar
org.jetbrains.annotations
fromjetbrains-annotations-13.0.jar
javax.annotation
fromgwt-dev-2.5.1-sources.jar
org.checkerframework.checker.nullness.qual
fromchecker-framework-2.1.9.zip
lombok
fromlombok
commitf6da35e4c4f3305ecd1b415e2ab1b9ef8a9120b4
javax.validation.constraints
fromvalidation-api-1.0.0.GA-sources.jar