|
I think Java is a pretty bad language, but most of your points are provably wrong. You're either grossly misinformed (some of what you say was true about a decade ago, but hasn't been since around the 1.5 release in ~'04) or purposefully spreading lies. You're factually wrong about the open-source thing: the primary impl of Java is open source (http://hg.openjdk.java.net/jdk7u/jdk7u). Sure, some impls like Azul might not be - but that's the joy of an Open language with a real spec, anyone can write an impl under any license they choose. The claim that Objects have 'too much' overhead is subjective - but also basically wrong. Generally Objects in Java have 8 bytes of straight book-keeping overhead, plus padding to get the size of the fields to the nearest multiple of 8 bytes. That's expensive relative to C, but cheap compared to almost any other object oriented, GCd language (and can often be avoided via primitives, escape analysis, etc). For reference, CPython (the main Python impl) has ~30 bytes of overhead on an Int between tag bits, book keeping, etc last time I investigated. How do you think the Java concurrency model is flawed? Almost any concurrency model I can think of, from Erlang-style message passing (see: Akka) to the new Fork/Join framework can be implemented in Java since its concurrency primitives are complete. I've even done basic impls of STM on AtomicRefs. Frankly, Java has one of the better defined and fine-grained concurrency models I know of. C++ just got a well-defined memory model in the '11 standard IIRC (vs '04 for the JVM). I'm with you on the functional programming thing - syntax on anonymous inner classes and a lack of type inference make it way too verbose. But it's (largely) fixed via Project Lambda in Java 8. And, in the meantime, there are plenty of great JVM languages (Scala, Clojure, etc) with better support. |
I don't know if this is what the author originally intended, but as a most-of-the-time .NET programmer, I do see one glaring flaw to Java that falls along these lines, and which I believe is inherited from the JVM (I've heard of it being a problem for people trying to write a C# compiler that targets the JVM): There's no concept of a user defined pass-by-value type. There are only primitive types and reference types (i.e., objects).
This does create some overhead. It means that for any instance of a user-defined type you have to use additional resources in two ways which may be unnecessary: First, it goes on the heap, so it invariably adds to the garbage collector's workload. Second, it's always going to be internally referenced indirectly via a pointer. That's an extra 4-8 bytes that could be significant overhead for a sufficiently small type - say, a struct that represents an RGBA value as four separate bytes. That's also poorer locality of reference, in a way that I suspect could bite when you're dealing with large collections of small elements.