This design decision appears mostly driven by naming.
Name ArrayList suggests to reader a functionality similar to arrays - and it is natural for Java Collections Framework designers to expect that vast majority of API users will rely on it functioning similar to arrays.
This in particular, involves treatment of null elements. API user knowing that below works OK:
array[0] = null; // NPE won't happen here
would be quite surprised to find out if similar code for ArrayList would throw NPE:
arrayList.set(0, null); // NPE => WTF?
Reasoning like above is presented in JCF tutorial stressing points that suggest close similarity between ArrayList and plain arrays:
ArrayList... offers constant-time positional access and is just plain fast...
If you would want a List implementation disallowing nulls, it would better be called like NonNullableArrayList
or something like that, to avoid confusing API users.
Side note there is an auxiliary discussion in comments below, along with additional considerations supporting the reasoning laid out here.
Technically speaking, Java does have type inferencing when using generics. With a generic method like
public <T> T foo(T t) {
return t;
}
The compiler will analyze and understand that when you write
// String
foo("bar");
// Integer
foo(new Integer(42));
A String is going to be returned for the first call and an Integer for the second call based on what was input as an argument. You will get the proper compile-time checking as a result. Additionally, in Java 7, one can get some additional type inferencing when instantiating generics like so
Map<String, String> foo = new HashMap<>();
Java is kind enough to fill in the blank angle brackets for us. Now why doesn't Java support type inferencing as a part of variable assignment? At one point, there was an RFE for type inferencing in variable declarations, but this was closed as "Will not fix" because
Humans benefit from the redundancy of the type declaration in two ways.
First, the redundant type serves as valuable documentation - readers do
not have to search for the declaration of getMap() to find out what type
it returns.
Second, the redundancy allows the programmer to declare the intended type,
and thereby benefit from a cross check performed by the compiler.
The contributor who closed this also noted that it just feels "un-java-like", which I am one to agree with. Java's verbosity can be both a blessing and a curse, but it does make the language what it is.
Of course that particular RFE was not the end of that conversation. During Java 7, this feature was again considered, with some test implementations being created, including one by James Gosling himself. Again, this feature was ultimately shot down.
With the release of Java 8, we now get type inference as a part of lambdas as such:
List<String> names = Arrays.asList("Tom", "Dick", "Harry");
Collections.sort(names, (first, second) -> first.compareTo(second));
The Java compiler is able to look at the method Collections#sort(List<T>, Comparator<? super T>)
and then the interface of Comparator#compare(T o1, T o2)
and determine that first
and second
should be a String
thus allowing the programmer to forgo having to restate the type in the lambda expression.
Best Answer
1. C and Java are different languages
The fact that they behave differently should not be terribly surprising.
2. C is not doing any conversion from
int
tobool
How could it? C didn't even have a true
bool
type to convert to until 1999. C was created in the early 1970s, andif
was part of it before it was even C, back when it was just a series of modifications to B1.if
wasn't simply aNOP
in C for nearly 30 years. It directly acted on numeric values. The verbiage in the C standard (PDF link), even over a decade after the introduction ofbool
s to C, still specifies the behavior ofif
(p 148) and?:
(p 100) using the terms "unequal to 0" and "equal to 0" rather than the Boolean terms "true" or "false" or something similar.Conveniently, ...
3. ...numbers just happen to be what the processor's instructions operate on.
JZ
andJNZ
are your basic x86 assembly instructions for conditional branching. The abbreviations are "Jump if Zero" and "Jump if Not Zero". The equivalents for the PDP-11, where C originated, areBEQ
("Branch if EQual") andBNE
("Branch if Not Equal").These instructions check if the previous operation resulted in a zero or not and jump (or not) accordingly.
4. Java has a much higher emphasis on safety than C ever did2
And, with safety in mind, they decided that restricting
if
toboolean
s was worth the cost (both of implementing such a restriction and the resulting opportunity costs).1. B doesn't even have types at all. Assembly languages generally don't, either. Yet B and assembly languages manage to handle branching just fine.
2. In the words of Dennis Ritchie when describing the planned modifications to B that became C (emphasis mine):