| ▲ | Growing the Java Language [video](youtube.com) |
| 73 points by JackFr 4 days ago | 53 comments |
| |
|
| ▲ | elric 18 hours ago | parent | next [-] |
| Brian Goetz mentions Guy Steele's 1998 lecture "Growing a language" [1]. It's worth a watch if you haven't watched it yet. It's been discussed on HN several times [2]. Java gets a lot of flack in these parts, mostly by people who don't use Java and pull opinions out of their arse, but you'd be hard pressed watching both talks and not being impressed by the effort that's going into continuously improving the language. [1] https://www.youtube.com/watch?v=_ahvzDzKdB0 [2] https://hn.algolia.com/?q=growing+a+language |
| |
| ▲ | gorset 15 hours ago | parent [-] | | I enjoyed both talks a lot. I really appreciate the work done to evolve Java. They seem to be able to both fix earlier mistakes (and there were many!) and new ones from happening. While I see other languages struggling with the weight of complexity added over time, Java seems to get simpler and easier even with significant updates to the language spec. |
|
|
| ▲ | sgt 19 hours ago | parent | prev | next [-] |
| This is great, should we all rush back towards Java to build our startups on? |
| |
| ▲ | vbezhenar 16 hours ago | parent | next [-] | | I'm concerned about Spring Framework shenanigans. It's under Broadcom now, which feels like a dangerous steward. Just few weeks ago Broadcom discontinued newly acquired bitnami images. It's hard to imagine Java without Spring, everyone uses Spring. | | |
| ▲ | guidedlight 15 hours ago | parent [-] | | Broadcom just want to milk corporates. That is their business model. I’m sure they will commercialise the Spring framework and force fragmentation. Not unlike what happened to Java and Docker. |
| |
| ▲ | winrid 19 hours ago | parent | prev | next [-] | | Quarkus and Vaadin is pretty productive. | | |
| ▲ | mands 4 hours ago | parent | next [-] | | Modern Java (21+), Spring Boot backend, and Vaadin Hilla (https://vaadin.com/hilla) frontend is a great startup combo | |
| ▲ | kitd 16 hours ago | parent | prev | next [-] | | Quarkus is just a little too much like magic for me. Too many annotations hides what's going on underneath, which makes me feel a bit uncomfortable. But I'll accept that's probably just me. Vertx on the other hand, which it is built on and which itself builds on Netty, is excellent, and very performant for typical backend services. It now has support for virtual threads too. | | |
| ▲ | winrid 9 hours ago | parent | next [-] | | Please DO NOT build a large application on raw Vertx. Quarkus gives you things like auto generated openapi specs etc. Quarkus is just compile time stuff around vertx, and you write simple synchronous code. Again, DO NOT use vertx directly for building APIs. It'd be like using just expressjs and writing your api specs manually... in 2025... | |
| ▲ | vram22 14 hours ago | parent | prev [-] | | >Vertx on the other hand, which it is built on and which itself builds on Netty What does the highlighted part above mean? I know what Netty is, but did not understand that phrase above, | | |
| ▲ | kitd 12 hours ago | parent [-] | | Vertx uses Netty as the event loop handler for concurrent IO. Vertx adds a simplified asynchronous API on top of Netty (whose API can be pretty complicated), making backend services that need to handle large numbers of concurrent connections easy to implement. HTH |
|
| |
| ▲ | p2detar 17 hours ago | parent | prev [-] | | I don't know. I still find Vaadin's pricing way over what I could spend on a startup project. But it could just be me. edit: People also forget that Eclipse RAP still exists and although it's probably not that "modern", it works. https://eclipse.dev/rap | | |
| ▲ | fredu81 16 hours ago | parent | next [-] | | The vast majority of people don't pay anything for Vaadin as it's Apache 2 licensed. Out of curiosity: Why do you feel you have to spend on it – is it some part of the tooling or are the support alternatives the reason? (I work for the company behind Vaadin, thus honestly curious). | | |
| ▲ | p2detar 15 hours ago | parent [-] | | AFAIR, it was the "Grid Pro" and "Dashboard" features that were needed, but they were out of budget for our infant phase of the product and we went with React. It was a long time ago anyway, I last worked with Vaadin 7. I will however say, that I really enjoyed working with it at that time. | | |
| ▲ | sebak82 14 hours ago | parent [-] | | If you used React back then, what do you miss from the Vaadin world and what was easier in React in comparison ? Have you tried one of the latest versions? Disclaimer: I work for Vaadin. |
|
| |
| ▲ | winrid 9 hours ago | parent | prev [-] | | I can't imagine seriously showing RAP to a CEO and saying we're using that. I don't pay for Vaadin, you don't need to unless you want the extra components, and even if you do it's affordable, much cheaper than building the same system in React. |
|
| |
| ▲ | ludovicianul 19 hours ago | parent | prev [-] | | Yes :) |
|
|
| ▲ | seunosewa 19 hours ago | parent | prev | next [-] |
| Getting rid of checked exceptions would be very beneficial for Java's popularity. No modern JVM language has kept that annoying feature. Just stop checking them at compile time, or make it an optional feature. |
| |
| ▲ | Defletter 19 hours ago | parent | next [-] | | Checked exceptions are not the problem. In fact, I don't think there should be ANY unchecked exceptions outside of OOM and other JVM exceptions. I will die on this hill. The actual problem is that handling exceptions in Java is obnoxious and verbose. I cannot stress enough how bad it feels going from Zig back to Java, error-handling wise. If Java had Zig-style inline catching, there wouldn't nearly be as much humming and hawing over checked exceptions. | | |
| ▲ | xmodem 17 hours ago | parent [-] | | A hot take I have is that Java's checked exceptions - which everyone hates - are semantically very similar to Rust's Result<T, E> and ? error handling - which is broadly liked. The syntax makes or breaks the feature. | | |
| ▲ | lock1 17 hours ago | parent | next [-] | | It shares the same important property (short-circuiting, explicit & type checkable) with Rust's `Result<>`, yes. I don't think it's a direct equivalent though - Java's exception creates stack trace by default - Type erasure which prevents you from doing anything "fancy" with try-catch + generic's type parameter - You can only throw something that extends `Throwable` rather than any type `E` - etc But yeah sure, if Java somehow provided a standard interface & an associated operator like Rust's Try trait to handle checked exception, it would probably have a much better reputation than it has now. | |
| ▲ | redditor98654 15 hours ago | parent | prev [-] | | A while ago, I had attempted to do it the Rust style with a Result type in Java (where it is called Data oriented programming) and the result is not great. I was fighting a losing battle in a naive attempt to replace checked exceptions but still retain compile time type safety. https://www.reddit.com/r/java/s/AbjDEo6orq | | |
| ▲ | lock1 13 hours ago | parent | next [-] | | Interesting anecdote. At $DAYJOB, I'm currently migrating a non-performance sensitive system to a functional style, which requires defining basic functional types like Option<> and Result<>. So far I think it works pretty well and certainly improves edge case handling through explicit type declaration. My current stable incarnation is something like this: sealed interface Result<T,E> {
record Ok<T,E>(T value) implements Result<T,E> {}
record Error<T,E>(E error) implements Result<T,E> {}
}
Some additional thoughts:- Using only 1 type parameter in `Result<T>` & `Ok<T>` hides the possible failure state. `Result<Integer>` contain less information in type signature than `Integer throwing() throws CustomException`, leaving you fall back on catching `Exception` and handling them manually. Which kind of defeats the typechecking value of `Result<>` - A Java developer might find it unusual to see `Ok<T,E>` and realize that the type `E` is never used in `Ok`. It's called "phantom types" in other language. While Java's generic prevents something like C++'s template specialization or due to type erasure, in this case, it helps the type system track which type is which. - I would suggest removing the type constraint `E extends Exception`, mirroring Rust's Result<> & Haskell's Either. This restriction also prohibits using a sum type `E` for an error. - In case you want to rethrow type `Result<?,E>` where `E extends CustomException`, maybe use a static function with an appropriate type constraint on `E` sealed class Result<T,E> {
public static <E extends Exception> void throwIfAnyError(Result<?,E>... );
}
- I like the fact that overriding a method with reference type args + functional interface args triggers an "ambiguous type method call" error if you try to use bare null. This behavior is pretty handy to ensure anti-null behavior on `Option.orElse(T)` & `Option.orElse(Supplier<T>)`. Leaving `Option.get()` as a way to "get the nullable value" and a "code smell indicator" | |
| ▲ | Defletter 14 hours ago | parent | prev [-] | | Yeah, Java's generic-type erasure makes result types difficult, though as you mention in your code example, this can be mitigated some using switch guards. But you could also go into another switch: switch (result) {
case Ok(var value) -> println(value);
case Err(var ex) -> switch (ex) {
case HttpException httpEx -> {
// do something like a retry
}
default -> {
// if not, do something else
}
}
}
|
|
|
| |
| ▲ | elric 17 hours ago | parent | prev | next [-] | | I disagree entirely, but I'd love to hear your arguments (other than vague allusions to "popularity" and other languages). Improved checked exception handling in Streams would be nice, but that's my only gripe with them. They force you to stop and think, which is a good thing. There are some checked exceptions that should probably be unchecked, like UnsupportedEncodingException thrown by ByteArrayOutputStream::toString which takes a charset name. I'm sure there are other subclasses of IOException that could be an IllegalArgumentException instead. But those few inconveniences don't invalidate the concept of checked exceptions. | | |
| ▲ | peterashford 15 hours ago | parent [-] | | I'm 100% with you - Streams is the one area where I think they dont pay well. Everywhere else, they're fine | | |
| ▲ | seunosewa 15 hours ago | parent [-] | | Which checked exceptions do you declare or enjoy having to handle in your codebase? |
|
| |
| ▲ | PhilipRoman 19 hours ago | parent | prev | next [-] | | I think checked exceptions are fine, they just haven't updated them along with other features. We now have expression based switch, why not have expression based try-catch? The other major problem is inability to pass them through the new functional interfaces, since they usually don't have anything like `<X> throws X`. But this could be solved by an Optional-like type. | |
| ▲ | HexDecOctBin 19 hours ago | parent | prev | next [-] | | (I am primarily a C developer) What is the problem with Checked Exceptions? Don't they just provide type checking? I would think that developers would want to know which function might or might not execute a non-local goto in middle of execution and handle that properly, since debugging that will be a mess. | | |
| ▲ | xmodem 17 hours ago | parent | next [-] | | Part of it is an ecosystem thing. It's a lot better now, but there were times when libraries would throw a variety of checked exceptions that usually couldn't be handled sensibly other than by being caught and logged by your top-level exception handler. This forced you to either (a) pollute many methods on many layers of your class hierarchy with `throws X`, potentially also polluting your external API (b) catch, wrap and re-throw the checked exception at every call site that could throw it (c) Use Lombok's `@SneakyThrows` to convert a checked exception into an unchecked one. Which they advise against using on production code, and which I have definitely never used on production code. There are specific situations where checked exceptions work well - where you want to say to specific code "I can fail in this specific way, and there is something sensible you can do about it". But those are fairly rare in my experience. | |
| ▲ | lock1 17 hours ago | parent | prev | next [-] | | The only way to handle a checked exception is either by declaring `throws` in the function signature to propagate it, or by using annoying try-catch statement. Then, due to the verbosity of try-catch, some decided to misuse it with an empty catch block. Personally, I think the problem isn't the checked exception itself, but rather the exception handling mechanism & popularity of unchecked exceptions. This led to some people misusing empty catch blocks or rethrowing with unchecked exception. Java 8+ functional interfaces / lambdas also don't play nicely with checked exceptions. There's no new keyword/feature/interaction between lambdas & checked exception, only old try-catch. To this day (Java 24 and soon LTS 25), AFAIK there's 0 plan to improve Java checked exception. And there are a lot of quirks if you try to use checked exception with modern Java features. It's just all around painful to work with, and I prefer to use Result<T,E>-like with `sealed` sum-type nowadays. It's quite weird the direction Java, C#, Javascript communities take on this. Lots of people just go with unchecked or using nullable reference. Which is fine for a throwaway program, but quite painful in a larger project. What do you mean a subtype / child class doesn't provide a supposedly "must be implemented" method `abstractMethod()` and instead throws an unchecked exception when you call it? You can even see this in JDK standard library, take java.util.Collection.removeAll() for example (https://docs.oracle.com/javase/8/docs/api/java/util/Collecti...). A class implementing `Collection` interface might or might not throw unchecked exception, yet you can still do this and get runtime error: Collection<T> c = new ImmutableList<T>();
c.removeAll();
Meanwhile, modern PLs with a better type system (e.g. Haskell, Rust, Zig) don't shy away from using Result<>-like and provides special syntax like Rust's Try trait operator (?) or Haskell's bind (>>=). This is pretty much similar to Java's checked exception in a lot of ways (explicit function signature declaration, type system enforcement, short-circuiting property, non-local goto). It's kind of sad that Java completely neglected checked exceptions, leaving them like an abandoned child rather than improving them like other modern PLs. | |
| ▲ | ahoka 17 hours ago | parent | prev | next [-] | | In practice there are problems: Everything can throw IOException technically which you need to handle. There are non checked exception anyway, so there might be exception that are thrown anyway. It's a mess and there is a reason no other mainstream language uses them, even if Java people don't like that fact. | | |
| ▲ | zmmmmm 2 hours ago | parent | next [-] | | A lot of that comes back to the lack of power in the type system (type erasure, lack of union types, etc). If all that code throwing IOException could express better the type of fault, and if the error handling could them in a more nuanced, less awkward manner, it would be much better than it is. | |
| ▲ | peterashford 15 hours ago | parent | prev [-] | | "Everything can throw IOException technically which you need to handle" wut? |
| |
| ▲ | watwut 16 hours ago | parent | prev [-] | | Imo, some standard libraries were massively overusing them. So, you needed to handle checked exceptions for stuff that you cant do much about or are highly improbable and genuinely should be runtime exceptions. But other, even more common source of hate is that many people simply do not want to handle them. They prefer if they can kind of pretend that stuff does not exists and look like "10x fast developers". You are technically faster if you ignore all that stuff while someone else fixes your code later on in different ticket. | | |
| ▲ | peterashford 15 hours ago | parent [-] | | See, I really don't get this. If you really don't care, just put "throws exception" on your methods and be done with. You can start lazy and tighten up if you want - your choice | | |
| ▲ | blandflakes 14 hours ago | parent [-] | | This really becomes tedious when you're working with Java's primary means of codesharing/abstraction, inheritance. You can't subtract an IOException from an interface, and you can't introduce one if you're extending an interface. So you're forced to handle an exception that you frequently can't recover from and that paradoxically you probably don't expect to ever be thrown, for a majority of methods. |
|
|
| |
| ▲ | zmmmmm 18 hours ago | parent | prev | next [-] | | it's is kind of interesting that we are in a phase where Rust is the "cool" language even though it has a similar kind of feature. I wonder which way it will age. | |
| ▲ | peterashford 18 hours ago | parent | prev | next [-] | | Obviously YMMV, but I like checked exceptions | |
| ▲ | forinti 16 hours ago | parent | prev | next [-] | | I would like some sort of pragma that would allow me to ignore all checked exceptions in a file. Something like "use nocheck;" and then all methods would implicitly throw Exception. Sometimes I want to write a small program for a one-off task and handling Exceptions is absolutely unnecessary. | |
| ▲ | DarkNova6 16 hours ago | parent | prev | next [-] | | This is a typical opinion to have. This is also an uninformed opinion. All Java needs is better syntax to handle exceptions. Nobody wants to open a whole block to handle an expected exception. ```
switch (f.get()) { case Box(String s) when isGoodString(s) -> score(100);
case Box(String s) -> score(50);
case null -> score(0);
case throws CancellationException ce -> ...ce...
case throws ExecutionException ee -> ...ee...
case throws InterruptedException ie -> ...ie...
}
``` | |
| ▲ | smrtinsert 16 hours ago | parent | prev [-] | | There should be a middle ground where the IDE could generate your exceptions for you based on unchecked exceptions. Dunno what to call that but dealing with checked exceptions in the IDE is so much easier than manually reading docs for runtimes. Yes you could vibe + c7 it these days, but still the whole thing feels nicer with checked exceptions. |
|
|
| ▲ | augustl 19 hours ago | parent | prev [-] |
| Kotlin is a much better Java so that's what we use :) I have a friend who maintains a gazillion JVM based apps for the Norwegian tax authorities and he's a Kotlin skeptic. He's pretty tired of maintaining and porting various small apps and microservices from arcane old and discarded Scala web frameworks etc. Given how locked-in Kotlin is to a single company, I kind of get his skepticism. |
| |
| ▲ | gorset 19 hours ago | parent | next [-] | | I think the «best practices» found in Java enterprise has meant that a lot of people think all Java has to look like that. High performance Java is awesome and can be competitive with C++ and Rust for non trivial systems, thanks to much better development cycle, debugging and high quality libraries. Most the benefits is the JVM, so Kotlin has those too, but I don’t feel Kotlin is enough of an improvement to warrant the downsides (at least for me). But both Kotlin, Scala and Clojure are great for the Java ecosystem. | | | |
| ▲ | jillesvangurp 18 hours ago | parent | prev | next [-] | | Java is controlled by Oracle. It's not that different from Kotlin in that respect. Go is controlled by Google. Swift is controlled by Apple. Typescript, C#, F#, VB, etc. are Microsoft controlled things. It's not like the grass is that much greener next door. I don't think these things are show stoppers. A lot of this stuff is open source after all. Jetbrains considered using Scala before they created Kotlin. I think they were right. With Kotlin they went for a bit more conservative approach. Mainly undoing things that aren't so great in Java language and unlikely to change for language compatibility reasons, and avoiding some of the pitfalls with Scala. I think Scala saw a bit of wild growth of features and frameworks that Kotlin largely avoided. For better or worse, there has been a bit of a Scala diaspora with people flocking to things like Rust, Elixir, and indeed some to Kotlin. Weather people like it or not, Kotlin plays very nice with existing Java code bases. By design. It was designed as a drop in replacement. It's why it caught on with Android developers before it even was released. It's a bit different from Scala in that respect, which while it worked alright with Java code bases really nudged you away from that to the point where you'd be swapping out your build tools, frameworks, etc. At this point Kotlin is arguably a better language to use with any of the popular Java frameworks. I'm not really aware of any exceptions to this. Spring is a good example (arguably the most popular server framework for Java and the JVM). IMHO you are missing out if you are not using that with Kotlin. The Spring people certainly seem to agree. They've invested lots of time and effort to make Kotlin a first class citizen in the ecosystem. Documentation is dual Kotlin/Java, the framework ships with lots of extension functions for Kotlin and Kotlin specific features, and expanded Kotlin support is one of the headline features for the upcoming major version. And it's not like the previous version was particularly lacking on that front. They've been supporting the Kotlin ecosystem for many years now. | | |
| ▲ | vbezhenar 15 hours ago | parent | next [-] | | I've used Kotlin quite a bit as a Java replacement in the past. However its roadmap was weird for me. I wanted Kotlin to be a thin layer upon Java, however Jetbrains ported it to JavaScript, to native. It felt like lack of focus. Another issue with Kotlin was, that its development did not 100% align with Java. Kotlin co-routines were invented, but Java went into green threads direction instead, so this feature feels like unnecessary complication of already complicated language. Nowadays I prefer Java. It's not ideal, but it aligns 100% with JVM. Kotlin was good in Java 7 times, when Java development felt frozen. | | |
| ▲ | aarroyoc 15 hours ago | parent [-] | | One important focus for Kotlin is mobile app development. However if you're just a thin layer over Java you can't create iOS apps, that's the whole story behind Kotlin Native/Kotlin Multiplatform. Being able to have apps that share code between Android and iOS. On the other hand I think a good Kotlin Native backend could be a great language in the Go space. Scala Native and Jank (Clojure) show that some people want a JVM less version of them. But currently Native is less performant than the JVM version. And now there's GraalVM, which is the Java solution for AOT and Kotlin could use it too. But it was invented after Kotlin Native. The same thing with coroutines and virtual threads. Or with Kotlin data classes and Java records. Kotlin was first, Java then implements something to solve the same issue but it's not the same way as Kotlin. | | |
| ▲ | jillesvangurp 11 hours ago | parent [-] | | > I think a good Kotlin Native backend could be a great language in the Go space With Ktor there is the beginnings of that. It can actually compile to native; but with some limitations. There's also the web assembly compiler which would make sense for things like server less and edge computing type use cases. Both are a bit neglected from a server side perspective by Jetbrains. But the potential is there. And the whole Kotlin native path could be a lot easier and more lightweight than dealing with Graal. The weak spot for Kotlin native outside the IOS ecosystem is compiler maturity, the library ecosystem, and lack of support for system libraries (e.g. posix and WASI for wasm). Those are fixable problems. But it's only partially there currently and I would not recommend it for that reason. However, I think the whole effort with IOS native has moved things forward quite a bit in the last two years. Getting Kotlin to the level of Go in terms of compilers, tools, performance, and libraries on Linux and wasm would be similar in scope. But a few years of focus on that could make a lot of difference. IMHO, Kotlin could be perfect as a system programming language with some effort. |
|
| |
| ▲ | p2detar 17 hours ago | parent | prev | next [-] | | After several years of using Kotlin, I've learned that while it's easy and often a pleasure to write, it can be a nightmare to read and I spend far more time reading code than writing it. I like the language and still use it, but for our flagship product I decided to stick with Java, and I'm glad I did now that it has accelerated the rollout of new language features. edit: grammar | |
| ▲ | elric 18 hours ago | parent | prev [-] | | > Java is controlled by Oracle. That's factually incorrect. Oracle owns the trademarks, but the language proper is governed by the community, most development is done in the open as part of OpenJDK, which is the reference implementation. | | |
| ▲ | jillesvangurp 16 hours ago | parent [-] | | Oracle employs most of the contributors and the OpenJDK leadership is Oracle as well. But it's true that companies like IBM/Red Hat (mainly) and a few others contribute as well and that decision making is community based. In practice, Oracle still wields a lot of influence over the roadmap and technical direction. But you are right that decision making is community based and meritocratic. Which in practice means Oracle has a large vote. |
|
| |
| ▲ | peterashford 18 hours ago | parent | prev [-] | | I've coded in both. I prefer Java but Kotlin is pretty cool also. And Clojure. |
|