I am curious as to why float literals must be declared as so:
float f = 0.1f;
Instead of
float f = 0.1;
Ha, this is just the tip of the iceberg my friend.
Programmers coming from other languages certainly don't mind having to add a little F to a literal compared to:
SomeReallyLongClassName x = new SomeReallyLongClassName();
Pretty redundant, right?
It's true that you'd have to talk to core Java developers themselves to get more background. But as a pure surface-level explanation, one important concept to understand is what an expression is. In Java (I'm no expert so take this with a grain of salt), I believe at the compiler level your code is analyzed in terms of expressions; so:
float f
has a type, and
0.1f
also has a type (float).
Generally speaking, if you're going to assign one expression to another, the types must agree. There are a few very specific cases where this rule is relaxed (e.g., boxing a primitive like int in a reference type such as Integer); but in general it holds.
It might seem silly in this case, but here's a very similar case where it doesn't seem so silly:
double getDouble() {
// some logic to return a double
}
void example() {
float f = getDouble();
}
Now in this case, we can see that it makes sense for the compiler to spot something wrong. The value returned by getDouble will have 64 bits of precision whereas f can only contain 32 bits; so, without an explicit cast, it's possible the programmer has made a mistake.
These two scenarios are clearly different from a human point of view; but my point about expressions is that when code is first broken down into expressions and then analyzed, they are the same.
I'm sure the compiler authors could have written some not-so-clever logic to re-interpret literals based on the types of expressions they're assigned to; they simply didn't. Probably it wasn't considered worth the effort in comparison to other features.
For perspective, plenty of languages are able to do type inference; in C#, for example, you can do this:
var x = new SomeReallyLongClassName();
And the type of x will be inferred by the compiler based on that assignment.
For literals, though, C# is the same as Java in this respect.