News for hackers. Stuff that matters.
Re:Rating 26 years of Java changes by vbezhenar on Saturday October 11, 2025 @04:57PM (#45552647)
I don't really feel that Java uses proven features.

For example they used checked exceptions. Those definitely do not seem like proven feature. C++ has unchecked exceptions. Almost every other popular language has unchecked exceptions. Java went with checked exceptions and nowadays they are almost universally ignored by developers. I'd say that's a total failure.

Streams another good example. Making functional API for collections is pretty trivial. But they decided to design streams for some kind of very easy parallelisation. This led to extremely complicated implementation, absurdly complicated. And I've yet to encounter a single use-case for this feature. So for very rare feature they complicated the design immensely.

Modules... LoL.

We will see how green threads will work. Most languages adopt much simpler async/await approach. Very few languages implement green threads.

Re:Rating 26 years of Java changes by rzwitserloot on Saturday October 11, 2025 @05:25PM (#45552847)
> For example they used checked exceptions.

Those are from java 1.0 and thus don't appear to be relevant to the part of the discussion I think this part of the thread is about (namely: "Why doesn't java crib well designed features from other languages?").

> Java went with checked exceptions and nowadays they are almost universally ignored by developers.

They aren't.

Note that other languages invented for example 'Either' which is a different take on the same principle, namely: Explicit mention of all somewhat expectable alternative exit conditions + enforcing callers to deal with them, though also offering a relatively easy way to just throw that responsibility up the call chain.

The general tenet (lets lift plausible alternate exit conditions into the type system) is being done left and right.

Re:Rating 26 years of Java changes by jayd16 on Saturday October 11, 2025 @07:06PM (#45553497)
I suppose you could actually solve it by having a promise that catches the exception like your suggesting with an either result. The C# Task API can do this. It has it's own headaches where now the developer has to pay attention to observing every exception.

Java could do something similar but they have enough promise types already.

Re:Rating 26 years of Java changes by vips7L on Sunday October 12, 2025 @09:16AM (#45558040)
All modern languages are adopting a checked error system: Rust, Swift, Kotlin, Zig, Gleam; they all have some type of error you must handle.

The problem with Java is that they haven’t added the syntax to make dealing with those errors easy. It’s boiler plate hell.

Re:Rating 26 years of Java changes by rectang on Sunday October 12, 2025 @12:46PM (#45559604)
Yeah, unwrapping a Result in Rust can often be done via a single character, the chainable `?` operator.

That’s not the only issue, though: Java also shunts both checked and unchecked exceptions through the same mechanism, conflating them. It’s no wonder that Java’s problematic implementation of checked exceptions has poisoned people against the concept.

Re:Rating 26 years of Java changes by dkarl on Saturday October 11, 2025 @07:02PM (#45553455)
You're absolutely right about checked exceptions. However, I think they're an exception (forgive me) from the pattern of Java mostly sticking to the strategy of, we can build a practical, industrial, reasonably performant language that has all these nice bits from other languages: garbage collection, portable bytecode, no pointer arithmetic, collections in the standard library, etc.

I think streams are a great example of what I was saying about Java failing to take advantage of coming last. Scala (probably among others, but Scala was right there on the JVM) had already demonstrated that it was possible to enable simple, readable code for simple use cases, while also enabling complex and powerful usage. And the experience of Scala had shown that there's little demand for parallel collections outside of extremely niche use cases where people tend to use specialized solutions anyway. Somehow Java, with this example staring them in the face, managed to get the worst of both worlds.

Re:Rating 26 years of Java changes by lenkite on Sunday October 12, 2025 @03:35AM (#45556108)
Totally Hard disagree on streams - I used parallel streams in my last Job nearly all the time. They are critical for cpu-intensive tasks involving large datasets. And they do involve just a single code change in the consuming code. Sequential to parallel processing can be done via one `.parallel`.

I always believed it was a major plus point for Java compared to other languages. I am even surprised to hear otherwise. How should parallel processing of streams work in your opinion, then ? Just saying it be unsupported would be laughable considering hardware today.

I would rate this feature 9/10. The fact that the author has rated it 1/10, shows he hasn't really worked on large, parallel processing of data - in Java anyways.

Re:Rating 26 years of Java changes by dkarl on Sunday October 12, 2025 @09:56AM (#45558250)
In the companies I've worked at, those kinds of workloads have been done in Spark or in Beam (GCP Dataflow, etc.)
Re:Rating 26 years of Java changes by JavierFlores09 on Saturday October 11, 2025 @06:02PM (#45553063)
Stuart Marks and Nicolai Parlog recently had a discussion about checked exceptions in the Java channel [0]. In short, while they mentioned that there are certainly some things to improve about checked exceptions, like the confusing hierarchy as well as the boilerplate-y way of handling them, they're not necessarily a failed concept. I do hope they get to work on them in the near future.

0: https://www.youtube.com/watch?v=lnfnF7otEnk

Re:Rating 26 years of Java changes by vbezhenar on Saturday October 11, 2025 @06:26PM (#45553189)
They are absolutely failed concept in Java. Every first popular library uses unchecked exceptions, including famous Spring. Java streams API does not support checked exceptions. Even Java standard library nowadays includes "UncheckedIOException". Kotlin, Scala: both languages grown from JVM and do not support checked exceptions.
Re:Rating 26 years of Java changes by samus on Sunday October 12, 2025 @02:21AM (#45555754)
Spring has a special error handling strategy where the whole request is allowed to fail, punting error handling off to the caller.

A lot of code that throws checked exceptions is simply dangerous to use with Java streams because the execution order of stream operation is not obvious and possibly non-deterministic. For this reason, streams were never intended to also handle errors. Reactive frameworks are much better at that.

The UncheckedIOException is for situations where you really cannot throw a checked exceptions, such as inside an iterator. Which might lead to ugly surprises for the API user;

Re:Rating 26 years of Java changes by vbezhenar on Sunday October 12, 2025 @05:48AM (#45556856)
> A lot of code that throws checked exceptions is simply dangerous to use with Java streams because the execution order of stream operation is not obvious and possibly non-deterministic.

From the type system PoV, they could have just written something like `interface Runnable<X> { void run() throws X; }` and now `forEach` would have been written like `<X> void forEach(Runnable<X> r) throws X`. And repeat that for all stream operations, promoting `X` everywhere, so if your mapper function throws SQLException, the whole pipeline will throw it.

It even works today with some limitation (there's no way for `X` to get value of `SQLException|IOException` union type), but with some generic improvements it could work.

But they decided to not touch this issue at all. So now people will fool compiler with their tricks to throw checked exceptions like unchecked (or just wrap them with UncheckedXxxException everywhere, I prefer that approach).

Re:Rating 26 years of Java changes by samus on Monday October 13, 2025 @07:54AM (#45567342)
At the risk of repeating myself: streams were simply never designed with error handling in mind. Aborting everything at the first error is just the most simplistic error handling strategy. Reactive streams frameworks should be preferred for this.
Re:Rating 26 years of Java changes by peterashford on Sunday October 12, 2025 @08:33PM (#45563488)
I agree. The only issue for me is that they could be less verbose but given that I'm always using an IDE, this is in practice a non-issue
Re:Rating 26 years of Java changes by bigstrat2003 on Saturday October 11, 2025 @08:54PM (#45554140)
> For example they used checked exceptions. Those definitely do not seem like proven feature.

Checked exceptions are an awesome feature that more languages should have. Just like static typing is a good thing because it prevents errors, checked exceptions are a good thing because they prevent errors.

Re:Rating 26 years of Java changes by rectang on Saturday October 11, 2025 @10:21PM (#45554589)
Idealized checked exceptions are isomorphic to Rust's `Result` type, which is great.

Java's implementation of checked exceptions has some issues, though.

* "Invisible control flow", where you can't tell from the call site whether or not a call might throw (you need to check the signature, which is off in some other file, or perhaps visible in an IDE if you hover).

* Java has both checked and unchecked exceptions, but they go through the same try-catch mechanism, failing to make a clean distinction between recoverable errors and unrecoverable bugs. (In e.g. Rust and Go, recoverable errors go through return values but unrecoverable errors go through panics.)

In the end, Java's exception design simultaneously requires a lot of effort to comply with, but makes it difficult to understand when you've successfully locked things down.

Re:Rating 26 years of Java changes by samus on Sunday October 12, 2025 @02:03AM (#45555666)
> * "Invisible control flow", where you can't tell from the call site whether or not a call might throw (you need to check the signature, which is off in some other file, or perhaps visible in an IDE if you hover).

Never found this this to be a problem. It is really common to all implementations of exceptions, not just checked ones. And when you write code the compiler will yell at you. In monadic code,

Re:Rating 26 years of Java changes by rectang on Sunday October 12, 2025 @11:47AM (#45559062)
Invisible control flow is common to all implementations of unchecked exceptions (Java, C#, C++, Python, Ruby, etc). It means that any code, anywhere, at any time, can throw an exception.

People are used to that, and one common strategy is to not worry too much about exceptions and then wrap a big `try` block around everything near the outer boundary of your code. It’s good enough for many purposes and yields a high initial development velocity, but is comparatively fragile.

With Languages like Rust, Go, and Swift, only unrecoverable errors trigger the panic mechanism. Every call site where a recoverable error may occur is identifiable — in Rust via Result, `unwrap()`, the `?` operator, etc, in Go via returned Err (though unlike Rust you can discard them silently), and in Swift via the `try` operator.

You can still develop quickly by just unwrapping every Result, but unlike languages with invisible control flow, you can easily audit the codebase and go back to harden every site where a recoverable error may occur — yielding a level of robustness which is difficult to achieve in languages with unchecked exceptions.

Re:Rating 26 years of Java changes by peterashford on Sunday October 12, 2025 @08:32PM (#45563480)
As someone who uses Go professionally now and Java previously, I disagree with your take on unchecked exceptions. I think that Panics and errors is worse than just using exceptions. I think the latter is just simpler to deal with. At the end of the day, when error handling is complex, its complex with either approach - you have to think carefully about what's happening in the problem domain and come up with a robust solution. What the code level adds is complexity: the Go approach is more complex and consequently worse. I love Go coding but its error handling sucks and I would gladly have the Java approach instead.
Re:Rating 26 years of Java changes by vips7L on Sunday October 12, 2025 @09:21AM (#45558064)
Do you not have to check the signature to see what a function can return when using Results? It’s off in another file too.

> failing to make a clean distinction between recoverable errors and unrecoverable bugs

Recoverability is context specific. One persons panic may just be another error case for someone else. I think this is one thing that programmers miss when talking about this topic. It is really up to the caller of your function if something should panic. You can’t make that decision for them.

Re:Rating 26 years of Java changes by rectang on Sunday October 12, 2025 @12:06PM (#45559225)
The point of avoiding invisible control flow is not to identify the type of the error, but to identify all locations in the code where recoverable errors may occur.

> One persons panic may just be another error case for someone else.

We can make a strong distinction between recoverable errors (e.g. this I/O operation may fail) versus unrecoverable errors that may leave the process in an unsound state, such as divide-by-zero or out-of-bounds array access[1].

There are some problem domains where even unrecoverable errors are not allowable, and programmers in those domains have to grapple with the panic mechanism.

But for the rest of us, it is useful to be able to distinguish between recoverable and unrecoverable errors — and to know how we have handled all possible sites which could result in recoverable errors.

[1] Joe Duffy explains it well: https://joeduffyblog.com/2016/02/07/the-error-model/#bugs-ar...

Re:Rating 26 years of Java changes by paulddraper on Saturday October 11, 2025 @08:57PM (#45554154)
Go implements green threads.

It might only be one language, but it’s a pretty big one

Re:Rating 26 years of Java changes by jsight on Saturday October 11, 2025 @09:57PM (#45554474)
I agree with you w/r/t the streaming parallelization. I remember huge arguments about this on some of the lists back in the day, because that design decision had lots of ridiculous consequences.

Eg, mutable state capture in lambdas is largely restricted because of the thought that people would use parallel threads within the stream processing blocks. That decision lead to lots of ugly code, IMO.

I've also never seen a need to try to parallelize a simple stream processing step.

Re:Rating 26 years of Java changes by peterashford on Sunday October 12, 2025 @08:35PM (#45563507)
I've used Streams before to good effect but I can't say I'm in love with the design. Seems overly verbose.
Re:Rating 26 years of Java changes by stirfish on Sunday October 12, 2025 @12:50AM (#45555324)
You've never used parallel streams? They're my favorite way to do parallel computation in Java, and very easy if you've structured your problem around streams.
Re:Rating 26 years of Java changes by vbezhenar on Monday October 13, 2025 @05:12AM (#45566357)
Code with parallel streams wouldn't even pass my review. The server processes multiple requests simultaneously. It makes no sense to smash all cores in one request. It'll cause bad latency for other requests and will not increase throughput.

There might be use-cases, but I've yet to encounter them.

And when I need parallel computation, I can just use good old ExecutorService. Few more lines, but that's OK for a task that arises once in a 10 years.

Re:Rating 26 years of Java changes by samus on Sunday October 12, 2025 @01:56AM (#45555643)
Checked exceptions are for errors that are not possible to prevent. How else should the caller know which exceptions are really likely to happen?

Modules absolutely achieved their primary goal: stopping libraries from accessing JDK internals without the application's knowledge. The ecosystem is slow on the uptake since split packages and access to internal APIs is endemic, but it is happening ever so slowly. I wish libraries could opt into not being part of the unnamed module.

Virtual threads were designed with explicit cooperation of the community, with the explicit goal of making it easy to switch as much existing code over to it as possible. I really don't understand the scepticism there. Most other languages went with promises or reactive streams because they were inspired by how functional programming languages do it.

Re:Rating 26 years of Java changes by vbezhenar on Sunday October 12, 2025 @06:02AM (#45556925)
> Checked exceptions are for errors that are not possible to prevent. How else should the caller know which exceptions are really likely to happen?

The same way, caller can know which exceptions are really likely to happen in TypeScript, C++, Python. Or in modern Java which avoids checked exceptions anyway. By reading documentation or source code. That's perfectly fine and works for everyone.

And you highlighted one big issue with checked exceptions. You've claimed that those exceptions are "really likely to happen".

When I'm writing reading data from resource stream, the data that's located next to my class files, IO Exceptions are really unlikely to happen.

Another ridiculous example of this checked exception madness:

    var inputStream = new ByteArrayInputStream(bytes);
    var outputStream = new ByteArrayOutputStream();
    inputStream.transferTo(outputStream); // throws IOException? wtf???
This code can throw OutOfMemoryError, StackoverflowError, but never IOException. Yet you're forced to handle IOException which doesn't happen. And that's the issue with checked exceptions.

There's no correspondence between checked exceptions and likelihood of their occurence. NullPointerException probably happens more than any checked exception. The division between checked exceptions and unchecked exceptions is absolutely arbitrary and makes sense only at caller place, never in called function signature.

> Modules absolutely achieved their primary goal: stopping libraries from accessing JDK internals without the application's knowledge. The ecosystem is slow on the uptake since split packages and access to internal APIs is endemic, but it is happening ever so slowly. I wish libraries could opt into not being part of the unnamed module.

"Slow" is an understatement. I don't see this happening at all. Last time I tried to write very simple application with modules, I spent so many hours banging my head over various walls, that I probably will not do another attempt in a foreseeable future.

Re:Rating 26 years of Java changes by clanky on Sunday October 12, 2025 @09:51AM (#45558229)
There's a recent Reddit thread with some good discussion around modules where Ron Pressler took part. tl;dr: the architects acknowledge uptake outside the JDK has been slow, largely because there have always been few benefits to modules, and secondarily because build tool support is lacking (perhaps because of the first reason). At some point they may begin providing additional benefits to modularization which may help stoke demand.

https://www.reddit.com/r/java/comments/1o37hlj/reopening_the...

Re:Rating 26 years of Java changes by samus on Sunday October 12, 2025 @04:10PM (#45561441)
[delayed]
Re:Rating 26 years of Java changes by vbezhenar on Sunday October 12, 2025 @06:09PM (#45562439)
> This provides no automatic verification that indeed all likely error situation that can and should be handled were indeed handled.

And some people write code in Python which provides no automatic verification whatsoever.

Actually unchecked exceptions are very similar to dynamically typed languages. And that's fine. As Python and other languages proved by their mere existence: dynamic typing is not inherently bad. Sometimes it's good. I think that for error handling, it's good.

> Java class loaders can do anything including loading resources from the network. Which is admittedly not that common these days after the demise of applets.

Technically they can, but in my particular case I know very well, that my resources are residing inside of JAR file. And if that JAR file happened to reside on the failed HDD block, that's not going to be a recoverable error.

When we're talking about IO Exceptions, it's almost always failed operation which requires complete abort. It's either failed hardware, or, typically, disconnected client. Can't do much about it, other than clean up and proceed to the next client.

And the same could be said about SQL Exceptions. Like 99% of SQL exceptions are application bugs which are not going to be handled in any way other than wind up and return high level HTTP 500 error or something like that. There are cases when SQL exception should be handled, but those are rare. Yet JDBC developers decided that programmers must execute error handling rituals on every call site.

> The NullPointerException indicates a bug in the application. By the very reason it occurs, the current thread cannot continue execution normally.

That's not exactly true. In JVM, NullPointerException is absolutely well defined and you can continue execution after catching it. You might suspect, that logical application state is corrupted, but sometimes you know well that everything's fine (and in most cases you hope that everything's fine, if your Spring MVC handler threw NPE, Spring is not going to crash, it'll continue to serve requests). It's not C++ with its undefined stuff. JVM is pretty reliable when it comes to every error, including NPE, stack overflow or OOM. Latter is special, because even handling error might prove challenging, when memory allocations fail, but JVM will not hang up or crash.

Re:Rating 26 years of Java changes by samus on Monday October 13, 2025 @07:47AM (#45567289)
> And some people write code in Python which provides no automatic verification whatsoever.

Python is a language with almost no static validation whatsoever. It would be very odd if it cared about checked exceptions. This dynamism makes big Python code bases infuriating to work with.

> When we're talking about IO Exceptions, it's almost always failed operation which requires complete abort. It's either failed hardware, or, typically, disconnected client. Can't do much about it, other than clean up and proceed to the next client.

If this is the case then the solution is to add it to the `throws` list.

> That's not exactly true. In JVM, NullPointerException is absolutely well defined and you can continue execution after catching it.

Why would I catch a NullPointerException instead of fixing my application? The JVM is indeed completely fine, but processing still cannot continue because that code simply does not exist.

Re:Rating 26 years of Java changes by vips7L on Sunday October 12, 2025 @09:11AM (#45558005)
Checked errors aren’t universally ignored by developers. Rusts main error system is checked. Swift has really introduced checked typed throws. Kotlin is introducing checked error unions. Checked exceptions are the same thing.