4 ms·
Java is a quite awful language honestly. And I use it everyday at work. Generics implementation with type erasure is a pain and complicates things a lot. There
by tigershark 10y ago
Java is a quite awful language honestly. And I use it everyday at work. Generics implementation with type erasure is a pain and complicates things a lot. There is no automatic static type inference and before Java 7 you had to specify twice the generic types in the same statement. This adds a lot of "complexity" or noise when reading some code. Checked exceptions..do we want to speak about all the complexity that they add?
Before Java 8 there was absolutely no first class support to closures, and if you wanted to have something equivalent you had to use an anonymous inner class... Very simple, eh?
All the streams (as in input/output streams) are heavily used and while sometime they are useful, they complicate needlessly the code.
The streams implementation (as in the Linq-like feature) is more complex than Linq.
Honestly I can't say that Java is a simple language.
It may be true if you just use loops and basic statements, but you can say the same for pretty much every other high level language.
Finally I'm quite perplexed for the reasons why you want to kill inheritance.
While it is true that when it is abused is bad, ditching it completely is wrong because used in the right way can make you code simpler.
- jdmichal 10y agoI think there's two definitions of simple being used between you and I. Let's use different words instead: obviousness and terseness. Obviousness is how clear the goal of the code is; terseness is how much typing it takes to get there. I'm using simple to mean obviousness; this seems to be in line with the article, as being "clever" typically means exchanging obviousness for terseness. You seem to be taking terseness as your definition of simple. Now Java is the king of obviousness; it's very clear exactly what is being done on every line of code. It pays for it in being very wordy. I don't like inheritance because it breaks obviousness; it's no longer obvious where a virtual call is actually going to be served. With composition, the immediate object has to serve the call, even if it's just to delegate it. The only virtual calls would be dispatching calls to interface methods. And this style isn't expensive after JIT; inlining these kinds of delegations is its primary optimization. (Think getter-method chains that return a field value, a common pattern in Java.) Lambdas were a step towards terseness, but they sacrifice obviousness to get there. It hides things... What SAM type is a lambda implementing? You have to check to call site; the lambda itself won't tell you. The anonymous class syntax tells you exactly what is being implemented, but that means you have to type more to get there. Now, I like properties because IMO they optimize both obviousness and terseness. You are obviously making a single property with a getter and a setter, as opposed to defining each separately. And you are more terse by removing the need to define each separately.
- tigershark 10y agoI don't think Java is obvious at all apart the aforementioned simple statements. With generics you have actually no idea of what type you receive at runtime, you receive just an object. If the goal of the code is to return some sensible default for a specific type in Java you cannot use generics. And it's not obvious at all for anyone that doesn't know the generics implementation details. About closures, do you think that it is more obvious to define an entire anonymous inner class when you really just need to define a method delegate or an anonymous method? For me it's completely counterintuitive other than it makes my eyes bleed. If I need a local variable I obviously define it, I don't create a class which exposes an encapsulated field and use it. And it's exactly the same thing when I need an anonymous method. When the goal is reading a file why should be more obvious to create a buffered reader that encapsulates a file reader that wraps a file and use it to read when I can just do File.ReadAllLines() in C#? What is the added value of calling stream() on everything before using any enumerable? In C# obviously you just call Extension Methods on an IEnumerable. You even get IntelliSense. Why should be obvious to call stream() on an object that is already a collection?
- jdmichal 10y ago> With generics you have actually no idea of what type you receive at runtime, you receive just an object. That's kind of the point of generics? I don't understand this argument at all. If you need a specific kind of type, then bound the generic using `extend` and you can use the bounding type's methods and fields. [0] You're still using a different definition of obvious, despite my having defined it for this use case. For instance: > Why should be obvious to call stream() on an object that is already a collection? That's the very definition of obvious. You are making it quite clear that you intend to use this collection as a stream. It's extremely obvious. Same with the buffered reader; Readers are unbuffered, and it's very obvious that you are buffering the reader when you wrap it. (Also, Java has `java.nio.Files.readAllLines` [1], so I'm not sure what you're going on about.) Extention methods are very non-obvious; where is an extension method defined? The answer is anywhere; it can live in any type you imported. It's not obvious looking at the line of code where execution is going to flow. (And yes, an IDE will track it down for you. Just because an IDE can do the work for you, doesn't mean that there's not work to be done.) [0] http://docs.oracle.com/javase/tutorial/java/generics/bounded.html http://docs.oracle.com/javase/tutorial/java/generics/bounded... [1] http://docs.oracle.com/javase/7/docs/api/java/nio/file/Files.html#readAllLines%28java.nio.file.Path,%20java.nio.charset.Charset%29 http://docs.oracle.com/javase/7/docs/api/java/nio/file/Files...