3 ms·
> That's just such a Java thing to do. "Oh we failed to design the perfect solution, so we are not going to change anything until we find that perfect solution.
by mrkeen 2y ago
> That's just such a Java thing to do. "Oh we failed to design the perfect solution, so we are not going to change anything until we find that perfect solution."
Disagree.
* Lambdas shipped without playing nice with checked exceptions
* Streams shipped while failing to terminate in cases where they should. (Do they still? I try it out every few years and so far I've been able to produce an infinite-loop or stack/heap space problem when asking for the first number of a well-defined series.)
* CompletableFutures shipped with this gem (still current I believe):
public boolean cancel(boolean mayInterruptIfRunning) {
boolean cancelled = (result == null) &&
internalComplete(new AltResult(new CancellationException()));
postComplete();
return cancelled || isCancelled();
}
Spot the unused bool. They've also pivoted away from CompletableFutures towards green threads. Which also reportedly lock up under some thread-starving scenarios (but shipped anyway.)
* Not to mention all the newer features that I haven't kept up with that enter "preview status 1", "preview status 2", etc.
- doctor_eval 2y agoI’m yet to forgive them for type erasure. And optionals. But I stopped using Java about 5 years ago, after 20 years of being increasingly frustrated with it, and I couldn’t be happier.
- klauserc 2y agoI'm super torn about type erasure in Java. On the one hand, it is super hacky and requires ugly workarounds (passing Class<T> references around). At the same time, it also made creative abuses of the type system possible (e.g., heterogeneous lists). All while remaining type safe (albeit with runtime type checks). It is also very noticeable how Java can iterate more quickly on its type system (only partially embedded in its VM) whereas C# generics are more or less set in stone (deeply embedded in its runtime).
- neonsunset 2y agoWhat do you have in mind by "set in stone"? The emit strategy is implementation defined but pursuing true generics, particularly when using structs which are identical to Rust generics, allows C# to have optimal (monomorhpized) codegen when needed.
- mrkeen 2y ago> I’m yet to forgive them for type erasure. I could agree or disagree depending on how 'type erasure' is defined. I'm firmly in the static-typing camp: Do the type-checking. Use the type information to generate good code, then throw away the types. > And optionals. What's your beef with Optionals? They didn't exactly go all-in on it. All the standard library stuff still returns nulls. I have one or two small beefs with Optionals, but my current peeve is IntelliJ warning me that I use them. (I KNOW I use them! I'm telling my callers which parameters they can include and which ones they can leave out.)
- btbuilder 2y agoWhile it’s more how they are used, imo optional is abused to the point it adds complexity. You don’t avoid handling null, but now you have to deal with present or not. Therefore you’ve gone from 2 states to 3. Use of value or null is simpler to me and use of optional can be via Optional.of() rather than parameters and properties for the vast majority of cases.
- doctor_eval 2y agoThe thing with type erasure is that reflection is a big part of Java - but it doesn’t work too well with generics. With optionals, I had hoped they would be a huge benefit to catching potential NPEs at compile time. But it was just lipstick. It was half assed. The reasoning was as you say - telling the caller about nulls - but IMO it adds complexity without benefit. They could have just defined a standard annotation. Or… made the compiler enforce them.
- kaba0 2y agoCan you give an example for streams not terminating when they should? As for that cancel method, why is it a problem if it doesn’t use a variable? Like, there are also no-op methods inside standard libraries, these are very different to how you write ordinary code. Also, Futures and green threads are not something to pivot between, they are different abstractions. And virtual threads locking up is pretty overblown of an issue, and always happened under some stupid workload, where normal threads would have locked up just as well. Does java ship bugs? Of course, there is zero chance of shipping such a large project without bugs. But I do think that they have a tendency to re-think and wait for new features, before committing to them, and they actually commit to such decisions, remarkably so.
- mrkeen 2y agohttps://bugs.openjdk.org/browse/JDK-8225328 https://bugs.openjdk.org/browse/JDK-8225328
- MeetingsBrowser 2y agomaybe I misunderstood > so far I've been able to produce an infinite-loop or stack/heap space problem The linked issue was resolved 5 years ago
- mrkeen 2y agoHaha I bet it was! "Java great" according to Java. Anyway, it's a been a while, so, I downloaded the latest Adoptium - that's the one you don't get sued for using right? ./javac --version javac 21.0.3 Full source code for pulling the first number out of a big stream: import java.util.stream.Stream; public class Main { public static void main(String[] args) { Stream.iterate(0, a -> a + 1) .flatMap(b -> Stream.iterate(b, c -> c + 1) .flatMap(d -> Stream.iterate(d, e -> e + 1))) .limit(1L) .findFirst() .get(); } } Run it: ./javac Main.java && time ./java Main Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.base/java.lang.Integer.valueOf(Integer.java:1073) at Main.lambda$main$2(Main.java:7) {...} at java.base/java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:647) at Main.main(Main.java:9) real 0m9,911s user 1m31,992s sys 0m1,423s