评估26年来Java的变化
Rating 26 years of Java changes

原始链接: https://neilmadden.blog/2025/09/12/rating-26-years-of-java-changes/

## Java 26 年:个人回顾 本文回顾了 26 年的 Java 开发历程,从 1999 年的 Java 1.1.8 开始。作者挑选了重要的语言和核心库变化(不包括 UI/图形和 VM 改进),并对每个变化进行了主观评分。 早期里程碑,如集合框架 (4/10) 和正则表达式 (9/10),奠定了基础。Java 5 (2004) 标志着一个转折点,带来了泛型 (8/10)、注解 (5/10) 和自动装箱 (7/10)。 后续版本则成效不一。Try-with-resources (Java 7, 10/10) 是异常安全性的重大胜利,而 Java 8 的 Streams (1/10) 被认为是对函数式编程的一次失败尝试。 更近期的补充,如 Records (Java 14, 10/10) 和模式匹配 (Java 17/23, 7-9/10) 受到积极评价,使 Java 更接近代数数据类型。Java 9 的模块 ( -10/10) 因破坏性强且收益甚微而受到严厉批评。最新的版本专注于质量改进和现代密码学,包括字符串模板 (Java 21, 10/10 潜力) 和后量子密码学 (Java 24)。 总而言之,作者强调了 Java 从一种基础语言演变为一个复杂、功能丰富的平台,并邀请读者分享他们自己的观点。

相关文章

原文

I first started programming Java at IBM back in 1999 as a Pre-University Employee. If I remember correctly, we had Java 1.1.8 installed at that time, but were moving to Java 1.2 (“Java 2”), which was a massive release—I remember engineers at the time grumbling that the ever-present “Java in a Nutshell” book had grown to over 600 pages. I thought I’d take a look back at 26 years of Java releases and rate some of the language and core library changes (Java SE only) that have occurred over this time. It’s a very different language to what I started out with!

I can’t possibly cover every feature of those releases, as there are just way too many. So I’m just going to cherry-pick some that seemed significant at the time, or have been in retrospect. I’m not going to cover UI- or graphics-related stuff (Swing, Java2D etc), or VM/GC improvements. Just language changes and core libraries. And obviously this is highly subjective. Feel free to put your own opinions in the comments! The descriptions are brief and not intended as an introduction to the features in question: see the links from the Wikipedia page for more background.

NB: later features are listed from when they were first introduced as a preview.

Java 2 – 1998

The Collections Framework: before the collections framework, there was just raw arrays, Vector, and Hashtable. It gets the job done, but I don’t think anyone thinks the Java collections framework is particularly well designed. One of the biggest issues was a failure to distinguish between mutable and immutable collections, strange inconsistencies like why Iterator as a remove() method (but not, say, update or insert), and so on. Various improvements have been made over the years, and I do still use it in preference to pulling in a better alternative library, so it has shown the test of time in that respect. 4/10

Java 1.4 – 2002

The assert keyword: I remember being somewhat outraged at the time that they could introduce a new keyword! I’m personally quite fond of asserts as an easy way to check invariants without having to do complex refactoring to make things unit-testable, but that is not a popular approach. I can’t remember the last time I saw an assert in any production Java code. 3/10

Regular expressions: Did I really have to wait 3 years to use regex in Java? I don’t remember ever having any issues with the implementation they finally went for. The Matcher class is perhaps a little clunky, but gets the job done. Good, solid, essential functionality. 9/10

“New” I/O (NIO): Provided non-blocking I/O for the first time, but really just a horrible API (still inexplicably using 32-bit signed integers for file sizes, limiting files to 2GB, confusing interface). I still basically never use these interfaces except when I really need to. I learnt Tcl/Tk at the same time that I learnt Java, and Java’s I/O always just seemed extraordinarily baroque for no good reason. Has barely improved in 2 and a half decades. 0/10

Also notable in this release was the new crypto APIs: the Java Cryptography Extensions (JCE) added encryption and MAC support to the existing signatures and hashes, and we got JSSE for SSL. Useful functionality, dreadful error-prone APIs. 1/10

Java 5 – 2004

Absolutely loads of changes in this release. This feels like the start of modern Java to me.

Generics: as Go discovered on its attempt to speed-run Java’s mistakes all over again, if you don’t add generics from the start then you’ll have to retrofit them later, badly. I wouldn’t want to live without them, and the rapid and universal adoption of them shows what a success they’ve been. They certainly have complicated the language, and there are plenty of rough edges (type erasure, reflection, etc), but God I wouldn’t want to live without them. 8/10.

Annotations: sometimes useful, sometimes overused. I know I’ve been guilty of abusing them in the past. At the time it felt like they were ushering a new age of custom static analysis, but that doesn’t really seem to be used much. Mostly just used to mark things as deprecated or when overriding a method. Meh. 5/10

Autoboxing: there was a time when, if you wanted to store an integer in a collection, you had to manually convert to and from the primitive int type and the Integer “boxed” class. Such conversion code was everywhere. Java 5 got rid of that, by getting the compiler to insert those conversions for you. Brevity, but no less inefficient. 7/10

Enums: I’d learned Haskell by this point, so I couldn’t see the point of introducing enums without going the whole hog and doing algebraic datatypes and pattern-matching. (Especially as Scala launched about this time). Decent feature, and a good implementation, but underwhelming. 6/10

Vararg methods: these have done quite a lot to reduce verbosity across the standard library. A nice small improvement that’s had a good quality of life enhancement. I still never really know when to put @SafeVarargs annotations on things though. 8/10

The for-each loop: cracking, use it all the time. Still not a patch on Tcl’s foreach (which can loop over multiple collections at once), but still very good. Could be improved and has been somewhat replaced by Streams. 8/10

Static imports: Again, a good simple change. I probably would have avoided adding * imports for statics, but it’s quite nice for DSLs. 8/10

Doug Lea’s java.util.concurrent etc: these felt really well designed. So well designed that everyone started using them in preference to the core collection classes, and they ended up back-porting a lot of the methods. 10/10

Java 7 – 2011

After the big bang of Java 5, Java 6 was mostly performance and VM improvements, I believe, so we had to wait until 2011 for more new language features.

Strings in switch: seems like a code smell to me. Never use this, and never see it used. 1/10

Try-with-resources: made a huge difference in exception safety. Combined with the improvements in exception chaining (so root cause exceptions are not lost), this was a massive win. Still use it everywhere. 10/10

Diamond operator for type parameter inference: a good minor syntactic improvement to cut down the visual noise. 6/10

Binary literals and underscores in literals: again, minor syntactic sugar. Nice to have, rarely something I care about much. 4/10

Path and Filesystem APIs: I tend to use these over the older File APIs, but just because it feels like I should. I couldn’t really tell you if they are better or not. Still overly verbose. Still insanely hard to set file permissions in a cross-platform way. 3/10

Java 8 – 2014

Lambdas: somewhat controversial at the time. I was very in favour of them, but only use them sparingly these days, due to ugly stack traces and other drawbacks. Named method references provide most of the benefit without being anonymous. Deciding to exclude checked exceptions from the various standard functional interfaces was understandable, but also regularly a royal PITA. 4/10

Streams: Ah, streams. So much potential, but so frustrating in practice. I was hoping that Java would just do the obvious thing and put filter/map/reduce methods onto Collection and Map, but they went with this instead. The benefits of functional programming weren’t enough to carry the feature, I think, so they had to justify it by promising easy parallel computing. This scope creep enormously over-complicated the feature, makes it hard to debug issues, and yet I almost never see parallel streams being used. What I do still see quite regularly is resource leaks from people not realising that the stream returned from Files.lines() has to be close()d when you’re done—but doing so makes the code a lot uglier. Combine that with ugly hacks around callbacks that throw checked exceptions, the non-discoverable API (where are the static helper functions I need for this method again?), and the large impact on lots of very common code, and I have to say I think this was one of the largest blunders in modern Java. I blogged what I thought was a better approach 2 years earlier, and I still think it would have been better. There was plenty of good research that different approaches were better, since at least Oleg Kiselyov’s work in the early noughties. 1/10

Java Time: Much better than what came before, but I have barely had to use much of this API at all, so I’m not in a position to really judge how good this is. Despite knowing how complex time and dates are, I do have a nagging suspicion that surely it doesn’t all need to be this complex? 8/10

Java 9 – 2017

Modules: I still don’t really know what the point of all this was. Enormous upheaval for minimal concrete benefit that I can discern. The general advice seems to be that modules are (should be) an internal detail of the JRE and best ignored in application code (apart from when they spuriously break things). Awful. -10/10 (that’s minus 10!)

jshell: cute! A REPL! Use it sometimes. Took them long enough. 6/10

Java 10 – 2018

The start of time-based releases, and a distinct ramp-up of features from here on, trying to keep up with the kids.

Local type inference (“var”): Some love this, some hate it. I’m definitely in the former camp. 9/10

Java 11 – 2018

New HTTP Client: replaced the old URL.openStream() approach by creating something more like Apache HttpClient. It works for most purposes, but I do find the interface overly verbose. 6/10

This release also added TLS 1.3 support, along with djb-suite crypto algorithms. Yay. 9/10

Java 12 – 2019

Switch expressions: another nice mild quality-of-life improvement. Not world changing, but occasionally nice to have. 6/10

Java 13 – 2019

Text blocks: on the face of it, what’s not to like about multi-line strings? Well, apparently there’s a good reason that injection attacks remain high on the OWASP Top 10, as the JEP introducing this feature seemed intent on getting everyone writing SQL, HTML and JavaScript using string concatenation again. Nearly gave me a heart attack at the time, and still seems like a pointless feature. Text templates (later) are trying to fix this, but seem to be currently in limbo. 3/10

Java 14 – 2020

Pattern matching in instanceof: a little bit of syntactic sugar to avoid an explicit cast. But didn’t we all agree that using instanceof was a bad idea decades ago? I’m really not sure who was doing the cost/benefit analysis on these kinds of features. 4/10

Records: about bloody time! Love ‘em. 10/10

Better error messages for NullPointerExceptions: lovely. 8/10

Java 15 – 2020

Sealed classes: in principal I like these a lot. We’re slowly getting towards a weird implementation of algebraic datatypes. I haven’t used them very much yet so far. 8/10

EdDSA signatures: again, a nice little improvement in the built-in cryptography. Came with a rather serious bug though… 8/10

Java 16 – 2021

Vector (SIMD) API: this will be great when it is finally done, but still baking several years later. ?/10

Java 17 – 2021

Pattern matching switch: another piece of the algebraic datatype puzzle. Seems somehow more acceptable than instanceof, despite being largely the same idea in a better form. 7/10

Java 18 – 2022

UTF-8 by default: Fixed a thousand encoding errors in one fell swoop. 10/10

Java 19 – 2022

Record patterns: an obvious extension, and I think we’re now pretty much there with ADTs? 9/10

Virtual threads: being someone who never really got on with async/callback/promise/reactive stream-based programming in Java, I was really happy to see this feature. I haven’t really had much reason to use them in anger yet, so I don’t know how well they’ve been done. But I’m hopeful! ?/10

Java 21 – 2023

String templates: these are exactly what I asked for in A few programming language features I’d like to see, based on E’s quasi-literal syntax, and they fix the issues I had with text blocks. Unfortunately, the first design had some issues, and so they’ve gone back to the drawing board. Hopefully not for too long. I really wish they’d not released text blocks without this feature. 10/10 (if they ever arrive).

Sequenced collections: a simple addition that adds a common super-type to all collections that have a defined “encounter order”: lists, deques, sorted sets, etc. It defines convenient getFirst() and getLast() methods and a way to iterate items in the defined order or in reverse order. This is a nice unification, and plugs what seems like an obvious gap in the collections types, if perhaps not the most pressing issue? 6/10

Wildcards in patterns: adds the familiar syntax from Haskell and Prolog etc of using _ as a non-capturing wildcard variable in patterns when you don’t care about the value of that part. 6/10

Simplified console applications: Java finally makes simple programs simple for beginners, about a decade after universities stopped teaching Java to beginners… Snark aside, this is a welcome simplification. 8/10

This release also adds support for KEMs, although in the simplest possible form only. Meh. 4/10

Java 22 – 2024

The only significant change in this release is the ability to have statements before a call to super() in a constructor. Fine. 5/10

Java 23 – 2024

Primitive types in patterns: plugs a gap in pattern matching. 7/10

Markdown javadoc comments: Does anyone really care about this? 1/10

Java 24 – 2024

The main feature here from my point of view as a crypto geek is the addition of post-quantum cryptography in the form of the newly standardised ML-KEM and ML-DSA algorithms, and support in TLS.

Java 25 – 2025

Stable values: this is essentially support for lazily-initialised final variables. Lazy initialisation is often trickier than it should be in Java, so this is a welcome addition. Remembering Alice ML, I wonder if there is some overlap between the proposed StableValue and a Future? 7/10?

PEM encoding of cryptographic objects is welcome from my point of view, but someone will need to tell me why this is not just key/cert.getEncoded(“PEM”)? Decoding support is useful though, as that’s a frequent reason I have to grab Bouncy Castle still. 7/10

Well, that brings us pretty much up to date. What do you think? Agree, disagree? Are you a passionate defender of streams or Java modules? Have at it in the comments.

联系我们 contact @ memedata.com