Live data from Hacker News

Java 27

mail.openjdk.org

251–260 of 427 posts

Re: Java 27

#251
post #205

Earlier quoted context omitted.

Quite the opposite, and the reason is that you can't extrapolate from small programs to large ones. Low-level languages (like C++) incur some significant overheads as they grow large (because of essential constraints of low-level languages that prevent them from doing certain optimisations that matter mostly in large programs), and these are exactly the overheads the JVM is designed to reduce. In small or short-lived…

> because of essential constraints of low-level languages that prevent them from doing certain optimisations that matter mostly in large programs Which specific optimizations are you referring to? In my experience, this is largely a myth; compared to Rust, you actually get even faster code right away. JIT is effective for languages where the source code lacks sufficient information (dynamic typing, where anything can…

> Which specific optimizations are you referring to?

A JIT with speculative optimisation and a moving GC.

There are two constraints in low-level languages that trump any of their performance goals, one technical and one a matter of preference.

The technical limitation is that they must use stable pointers (because they need to be low-level and so having an FFI layer that separates "hardware pointers" from "language pointers", as we have in Java defeats their main purpose). This means that you need to translate data storage or code storage to hardware addresses, and that interferes with both moving collection and with JIT compilation.

The other constraint is that low-level languages value worst-case performance over the average-case and even amortised performance. These languages prefer an operation (e.g. dynamic dispatch) to be slow as long as it's never too slow. With a JIT (and I describe more later), virtual dispatch can be super-fast almost all the time, but occassionally, you'll hit a trap because the speculation was wrong, and then you need to deoptimise and recompile.

> In my experience, this is largely a myth; compared to Rust, you actually get even faster code right away.

We wouldn't be doing it in the first place if it was a myth. In a low-level language, you can get very fast code if you do some manual optimisations, but they don't easily scale as the program grows and evolves, because they're viral. The two most basic examples are dynamic dispatch (which is the most general mechanism, which scales the best in terms of program evolution) and shared heap objects (again, the most general mechanism). These become more common and less easily avoided over time, and they're slow in low-level languages because of the constraints I mentioned.

That low-level languages make it harder and harder to preserve good performance over time as they evolve and grow is a problem familiar to those who've worked for years on large software written in a low level language (as I have). The JVM was designed, among other things, to solve this performance problem in large programs.

> JIT is effective for languages where the source code lacks sufficient information (dynamic typing, where anything can be null).

A JIT can make such languages decently fast, but that's not how it's used in Java. In Java it is used for speculative optimisation, which allows far more aggressive optimisation than an AOT compiler can do. E.g. by default, Java inlines and specialises virtual calls 15 levels deep. An AOT compiler can't do that or its code will explode. We get around it with selective use of templates in C++ (or comptime in Zig), but it has to be selective, and it's viral.

Re: Java 27

#252
post #241

Earlier quoted context omitted.

When you work at a Java shop. Kotlin is much nicer if you have to run on the JVM but aren't restricted to Java.

I don't understand the point of Kotlin anymore, now that Java has virtual threads and other stuff.

Once it gets nullness types, hackernews is gonna explode!

Re: Java 27

#253
post #44

Earlier quoted context omitted.

> there is nearly no magic I agree with the rest, but there's definitely a lot of magic in Java. This is from both what features the languages makes available (many) and how the community uses them (often). I've had so many hard-to-debug issues in Java over the years due to reflection, annotations, and bytecode manipulation shenanigans. And another positive point for Java: checked exceptions. It's verbose, but knowin…

I agree, to name a few: - Annotation processing: if you know Lombok, MapStruct. - Class loader. - Reflection. - Garbage collection.

You forgot runtime agents!

IMO compile-time annotation processors such as Lombok and MapStruct are far from the most magic part of Java. They're straightforward code generators. Their impacts is localized to where they get applied and you can actually see the code that's generated. They're very good for diminishing boilerplate. They're no worse than Rust's very standard #[derive(xyz)] proc macros.

Having the code being generated on the fly (instead of a one-shot) means it follows the rest of the structure it's derived from i.e. equals() and hashCode() don't risk to be forgotten when adding a field to a class (hello maddening Map lookup errors)

Also, yes, Lombok is _funky_ in how it works but there are "pure" alternatives like AutoBuilder and AutoValue if one cares.

Re: Java 27

#254
post #101

Earlier quoted context omitted.

Why not Go, Rust, or C#?

They lack in performance, stability (compatibility), observability (telemetry), productivity, or some combination thereof. They are chosen, of course (especially C#; Go and Rust are far behind), but not as much as Java.

While Java can outperform Go in some cases, the situation is very much the opposite when it comes to Rust.

I also don't see the case for stability. Yes, if you're still on JDK 8, it would probably chug on for a couple of years. But we were talking about greenfield projects and newer JDK go EOL much faster. If you want patches, you'll have to run your app to a newer JDK, which may break a couple of things. Rust (within the same edition) or Go (within the same major version) break less than that.

As far as runtime compatibility goes, Rust and Go apps ship with the runtime. This can be better or worse for you, depending on what is your upgrade story, but I don't see a clear winner here. What I would give to Java over Rust is that you will have far fewer dependencies to take care of if you need to upgrade. But the same goes for Go.

For observability, I feel that with Rust you have a bit less that you need to observe (no GC to worry about). Tokio tracing is great, but observability requires a bit more effort. The go observability story is far worse. So Java probably has an edge here, but not something that ever felt like a game changer. My impression is that for most of the enterprise shops that love Java, observability means collecting unstructured log files through NFS and trying to find a needle in the haystack with primitive tools, but I've been out of touch with this world for a couple of years.

Productivity is something that is dead if you are AI-heavy. Sure, many shops are still wary about AI, and I totally get why, but this is a battle that's already been lost. Without AI, I would say I was about 3 to 4 times more productive in Rust than I was in Java, but ramping up that productivity took at least 1 year of practice. It's not time most companies are willing to spend. With AI, this doesn't matter anymore, for better or worse.

I'm not arguing that Java is not chosen often for greenfield projects. It's clearly extremely popular in many circles, especially outside startups and big tech. But I think the reason Java is chosen have little to do with the reasons you've mentioned above and more with organizational preferences.

Re: Java 27

#255
post #205

Earlier quoted context omitted.

Quite the opposite, and the reason is that you can't extrapolate from small programs to large ones. Low-level languages (like C++) incur some significant overheads as they grow large (because of essential constraints of low-level languages that prevent them from doing certain optimisations that matter mostly in large programs), and these are exactly the overheads the JVM is designed to reduce. In small or short-lived…

I use Java every day but just to point out that your info about Go‘s GC seems out of date. They switched to Green Tea in 1.25 (I think?) - new GC that even has AVX-512 optimizations. Not sure what you mean by basic about the compiler but it‘s very fast and supports a large set of platforms. That‘s not basic to me. We are using JDK25 and are considering rewriting parts of our product to Go because of lower memory pres…

> I use Java every day but just to point out that your info about Go‘s GC seems out of date.

I'm well aware that Go's GC has improved, but the moving algorithm was designed not just to be fast for a GC, but to be faster than no GC. So Go's new GC is good - for a mark and sweep collector. But it can't compete with a moving collector (the only thing that can is arenas, which are user-friendly only in Zig).

> We are using JDK25 and are considering rewriting parts of our product to Go because of lower memory pressure and faster startup time, i.e., cloud friendly.

Java probably will never have perfect warmup, but it's getting very good - https://openjdk.org/jeps/544 - probably in JDK 28.

As for memory, I think Java's memory strategy is generally misunderstood and I've given a talk about it: https://youtu.be/xr73mR7ii9M The footprint overhead exists to compensate for CPU utilisation when the CPU utilisation is more disruptive than memory usage. The problem is that many Java developers - and I'm not blaming them - don't understand this tradeoff and how to configure the JVM for optimal resource usage, but the great news is that a solution is coming soon, too - https://openjdk.org/jeps/8377305 - also possibly in JDK 28.

So it's very likely that both of these issues will be resolved six months from today, and you'd still get to enjoy better performance and telemetry than all alternatives.

Re: Java 27

#256
post #14
post #10

Project Valhalla will go into Java 28 (next year, and preview version). Fingers crossed I'll manage to use null type safety in my lifetime.

universal null type safety has sadly been discarded as a core concept of Valhalla in my Understanding; that being said, the proposals in Valhalla have null-safety as a side effect, but only under certain conditions.

Really? I don't thinks so. There is a reason JEP 539 is in preview. There is a reason internal annotations exists in current valhalla jdk prototype and upcoming java 28 such as @jdk.internal.vm.annotation.NullRestricted, @jdk.internal.value.ValueClass.newNullRestrictedNonAtomicArray. Also, there is a reason value classes are allowed to be null. This is because nullness types will be a key factor to the java language.

Re: Java 27

#257
post #205

Earlier quoted context omitted.

Quite the opposite, and the reason is that you can't extrapolate from small programs to large ones. Low-level languages (like C++) incur some significant overheads as they grow large (because of essential constraints of low-level languages that prevent them from doing certain optimisations that matter mostly in large programs), and these are exactly the overheads the JVM is designed to reduce. In small or short-lived…

I use Java every day but just to point out that your info about Go‘s GC seems out of date. They switched to Green Tea in 1.25 (I think?) - new GC that even has AVX-512 optimizations. Not sure what you mean by basic about the compiler but it‘s very fast and supports a large set of platforms. That‘s not basic to me. We are using JDK25 and are considering rewriting parts of our product to Go because of lower memory pres…

Go's compiler is fast because it doesn't do as many advanced (read: computationally expensive) optimizations as other compilers do. No clue about Green Tea and how awesome it is :-).

Lower memory pressure is certainly a difficult thing to beat Go at, Java (OpenJDK) is probably never gonna get there. You get a lot of other stuff, like better peak performance, instead.

Btw, have you tried Leyden/AOT for better startup times? Curious about your experiences with that.

Re: Java 27

#258

Earlier quoted context omitted.

It’s still missing null safety, right? Which means it’s still a hard no for me.

We have a java monorepo of relatively large size and sophistication, driving our entire fintech, and I haven't seen a NPE for years. Use NullAway and it basically makes the problem go away. Our application won't build if it detects a potential NPE.

Congratulations. You've added another build tool and sprinkled your code with ugly annotations and ifs and Optional Optional.of(x).map(y) all over the place to get the same thing you'd get by moving to Kotlin.

I get it why this seems like a less drastic change, but this saddens me. Kotlin solves more issues with the type system (smart casts, reified types, immutability by default), without sacrificing readability. Unless I can see a solution in Java that makes dealing with NPEs as easier for lazy developers as ignoring them, I don't consider it a solved issue.

Re: Java 27

#260

Earlier quoted context omitted.

Same here with go, then Again go doesn't throw!

Golang doesn't have solutions like these: * https://jspecify.dev/docs/user-guide/ * https://openjdk.org/jeps/8303099

Sure it does:

https://github.com/uber-go/nilaway

Not exactly the same solution as JSpecify, since it doesn't rely on annotations, but it's also more ergonomic.

I'm not comparing this to "null-restricted types", since that's a draft JEP that hasn't made it even into a preview feature. Go also had multiple proposals for explicit nilability in types, and while they probably have less prospect of ever seeing the light of day compared to Project Valhalla, as things currently stand, Go is in the same position as Java: They are both extremely prone to NEPs out-of-the-box and they both have external tooling that can help you avoid them.

Java null checkers have more comprehensive coverage potential compared to Go, but Go is the more ergonomic one here. You don't need a single extra annotation on your code.

Post reply on HN