As a type system, purely formally speaking, Java is... well, it's just kind of OK.
It has parametric polymorphism. It gets subtyping & co-/contra-variance right -- for generic types only, not arrays, and requires explicit annotations ("extends", "super"). It can express higher-order functions. Its primary formal weakness compared with, say, Haskell98 or SML, is the lack of higher-kinded types (ignoring for the moment the issue of Haskell-style typeclasses or ML-style modules & functors), which is a pretty big weakness but not a game-killer (see: Rust, Elm).
But pragmatically, it's a pain in the ass to work with. (Possibly this has improved since I worked with it. I hope it has!) It has a weird "everything must be an object" view of the world; it requires a file for every type I wish to define (barring nested classes, and anonymous classes - the latter of which is a notable but late improvement). Expressing HOFs is possible, but very unpleasant (AIUI it's gotten better lately). And just to top it all off, it doesn't have type inference, which just makes everything a chore.
The way I see it, Java is playing catch-up with the innovations introduced by more forward-thinking languages. It seems doomed to being forever a middle-of-the-road language. Which is... well, it's just kind of OK.
But it's not gonna inspire devotion, and people who worked with it when it really did suck (perhaps it still does, I dunno) are gonna remember that and hate it.
That is, a higher-kinded type is a type which takes a type constructor as one of its parameters, in the same way that a higher-order function is a function that takes a function as one of its parameters.
It has parametric polymorphism. It gets subtyping & co-/contra-variance right -- for generic types only, not arrays, and requires explicit annotations ("extends", "super"). It can express higher-order functions. Its primary formal weakness compared with, say, Haskell98 or SML, is the lack of higher-kinded types (ignoring for the moment the issue of Haskell-style typeclasses or ML-style modules & functors), which is a pretty big weakness but not a game-killer (see: Rust, Elm).
But pragmatically, it's a pain in the ass to work with. (Possibly this has improved since I worked with it. I hope it has!) It has a weird "everything must be an object" view of the world; it requires a file for every type I wish to define (barring nested classes, and anonymous classes - the latter of which is a notable but late improvement). Expressing HOFs is possible, but very unpleasant (AIUI it's gotten better lately). And just to top it all off, it doesn't have type inference, which just makes everything a chore.
The way I see it, Java is playing catch-up with the innovations introduced by more forward-thinking languages. It seems doomed to being forever a middle-of-the-road language. Which is... well, it's just kind of OK.
But it's not gonna inspire devotion, and people who worked with it when it really did suck (perhaps it still does, I dunno) are gonna remember that and hate it.