Java 17 / JDK 17: General Availability
mail.openjdk.java.net
mail.openjdk.java.net
Among other things, this means that we can begin to use records, pattern matching for instanceof, the shenendoah GC, and more.
Links to JEPs for the other releases.
http://openjdk.java.net/projects/jdk/16/ http://openjdk.java.net/projects/jdk/15/ http://openjdk.java.net/projects/jdk/14/ http://openjdk.java.net/projects/jdk/13/ http://openjdk.java.net/projects/jdk/12/
> Pattern Matching for instanceof (16)
> Records (16)
> Restore Always-Strict Floating-Point Semantics (17)
> Sealed Classes (17)
> Switch Expressions (14)
> Text Blocks (15)
This is what excites me. Records, switch expressions and sealed classes are all excellent and even better together. Along with pattern matching switch statements, Java is finally losing a lot of cruft people complain about.
TBH, it was a lot of trouble so that someone could avoid generating a couple of getters and setters, and could use a annotation to setup the logger. I realize that there are more features available than that, but the ones that I've seen often used it in such mundane and boring ways that the setup wasn't worth the hassle for me.
But I guess we all get annoyed with minor hassles in different ways. I got annoyed with the hassle of setting up an IDE, they got annoyed with getters and setters more. :)
A lot of the time, the software I'm working on has data objects that are really amalgamations of other fields. Example: "Address" is the street address, the city, the postal code, etc, etc. These sorts of objects should be immutable. Records are perfect for that.
If I need to add additional logic, methods, then you can add those to a record. But it continues to enforce that the state is immutable.
* tuples (complex numbers, points, dimensions, colors, IP addresses),
* database query results,
* stateless beans for DI frameworks where it cuts down on the verbosity of using constructor injection (actually a slight misuse)
* composite natural keys in database modeling
The immutability can help to enforce API contracts and proper service layering. A common problem in legacy code is modules communicating with each other by modifying objects that were passed as arguments.
Eventually, Project Valhalla will introduce the possibility to declare records as primitive, which will also reduce the overhead of Wither methods.
Edit: Building web APIs should also benefit from records because the argument and result types are only supposed to be created and read, not modified.
They reduce a lot of boilerplate, e.g. when passing multiple return values.
I know the answer is always use IDE and all but it causes more context switches than scrolling a bit to see types I created.
record Point(int x, int y) {}
Point p = new Point(1, 2); Point pp = p with { x = 3; }
[1] https://github.com/openjdk/amber-docs/blob/master/eg-drafts/...
My gut feel is that records break encapsulation and will make refactoring slightly more difficult than the equivalent lombok value class. But if this gets more people making objects immutable, I'm all for it.
Colour changed = colour.withRed(5);https://advancedweb.hu/a-categorized-list-of-all-java-and-jv...
That's not _strictly_ true.
Java 17 is a release of the reference implementation, but there are a number of distributions from a variety of vendors.
Oracle are going to provide long term support for their distribution, and it sounds like many will follow their lead. (If you are going to provide LTS it would be a little perverse to be out of sync with other providers of the same software)
So, for all practical purposes, it is an LTS. But check with your vendor.
Yes, these are "distributions" (binaries) of OpenJDK that do not provide any sort of support, and clearly no LTS flag to them.
The jdk11u branch [1] (the source code) is currently steward by Red Hat, SAP employees and other contributors, and both Red Hat and SAP have a support roadmap, which currently goes until at least 2023 (SAP) [1] and 2024 (Red Hat) [2].
So, Debian is not providing an LTS binary. Debian is producing binaries out of the source code maintained by others. Once jdk11u stops receiving updates, Debian also stops shipping updates, because Debian has no LTS commitment.
[1] https://wiki.openjdk.java.net/display/JDKUpdates/JDK11u
[2] https://blogs.sap.com/2021/07/21/support-extension-of-sapmac...
This seems like exactly the intended effect to me.
Desktop applications are usually not delivered as bare JARs, but with wrapper binaries or scripts, where such flags are supposed to go.
Extended support still behind Java 8 =)
I suspect Java 8 will be with us for a long long time.
- (Proposal) Moving JDK LTS versions to a two year cadence [1]. Java 21 will be next LTS instead of Java 23.
- Oracle JDK is now free for commercial and production use [2].
- A new Java developer site [3].
[1] https://mreinhold.org/blog/forward-even-faster
edit: fixed
Still, it is pretty lame, since they've been advocating bundling of the JDK since they deprecated the WebStart.
OTOH, since Oracle JDK and OpenJDK are identical save for branding and licensing, not sure why you wouldn't just bundle an OpenJDK build in that case.
This new license seems to be targeted to two main groups: those who depend upon a "system" install of Oracle Java for running third party apps, and those who are for some reason unwilling to use OpenJDK.
Seems like the new Oracle JDK license is a lot more flexible than before. In reality it's kind of cosmetic because lots of people were using the (100% compatible) Amazon or Azul spins, or just regular OpenJDKs.
OpenJDK (which is built from functionally the same source code) has been free under GPL v2.1 + Classpath Exception for a while now.
Hopefully, developers have learned to avoid Oracle like a plague after the last absolute licensing failure with JDK that caused all the FUD.
The community terribly overreacted and misunderstood the nature of that change, and indeed caused a lot of FUD.
Language Features
394: Pattern Matching for instanceof
395: Records
306: Restore Always-Strict Floating-Point Semantics
409: Sealed Classes
361: Switch Expressions
378: Text Blocks
Language Features in Preview (behind a flag)
406: Pattern Matching for switch
412: Foreign Function & Memory API
414: Vector API
Tooling
392: Packaging Tool (jpackage)
JVM
386: Alpine Linux Port
391: macOS/AArch64 Port
340: One AArch64 Port, Not Two
388: Windows/AArch64 Port
(Source: https://openjdk.java.net/projects/jdk/17/jeps-since-jdk-11)Naturally this will take several releases.
* https://www.oracle.com/java/technologies/java-se-support-roa...
I always assumed this was because .net (arguably it's main competitor) was churning fast through version numbers and they "wanted to keep up".
I swear I googled this like 2 months ago and the first 2 or 3 links weren't helpful so I gave up. Thanks!
See https://openjdk.java.net/jeps/223#Dropping-the-initial-1-ele...
PS: had to edit, was really just a note about the numbers not the content of the versions!!!
In the end the case was settled out of court and MS agreed to pay more then 1 billion dollar to Sun. MS also agreed to license a whole slew of patents for use with .net.
[1] https://www.pinsentmasons.com/out-law/news/sun-sues-microsof...
.net didn't add support for macOS on ARM64 years ago. .net also didn't implement 2D rendering on macOS via Metal. etc. As a matter of fact .net didn't even support any other platform then Windows until recently.
Meaning .net has nowhere near the "write once, run anywhere" support Java has.
> J2SE 5.0
> […]
> The release on September 30, 2004 was originally numbered 1.5, which is still used as the internal version number. The number was changed to "better reflect the level of maturity, stability, scalability and security of the J2SE".
and
> This version introduced a new versioning system for the Java language, although the old versioning system continued to be used for developer libraries:
>> Both version numbers "1.5.0" and "5.0" are used to identify this release of the Java 2 Platform Standard Edition. Version "5.0" is the product version, while "1.5.0" is the developer version. The number "5.0" is used to better reflect the level of maturity, stability, scalability and security of the J2SE.
>> — Version 1.5.0 or 5.0?[32]
[32]: http://docs.oracle.com/javase/1.5.0/docs/relnotes/version-5....
Only missing stuff from 17, but that's a short list.
"The Eclipse Temurin™ project provides code and processes that support the building of runtime binaries and associated technologies that are high performance, enterprise-caliber, cross-platform, open-source licensed, and Java SE TCK-tested for general use across the Java ecosystem."
https://www.azul.com/downloads/?version=java-8-lts&os=macos&...
I'm on an M1 Mac and have spent more time using the x86 JVM because the ARM JVM is less likely to have applications Just Work.
Records, multiline strings, pattern matching for instanceof, handling nulls in pattern matching/switch, sealed classes/interfaces, probably other things I'm forgetting.
I had never written Java before until recently, and thank god for JDK16 features. Only thing that made it slightly tolerable.
The danger of thinking in LTS cycles is a feeling that a feature needs to be rushed to make it in, which might jeopardize the production-ready quality on Day 1 of GA. It's very important to us that the ecosystem can trust every release, in production, right out of the gate.
Unless i rewrite the native parts in Rust, of course :).
[1] https://github.com/openjdk/amber-docs/blob/master/site/desig...
At first glance, it looks like this (sure, more powerful) pattern matching system is not going to satisfy my desire for a compact syntax that lets me do the equivalent of this typescript:
const [foo, bar] = getMeTwoThings();With the pattern matching the best you are going to get is nasty boiler plate like
var returnedTuple = getMeTwoThings();
if (returnedTuple instanceof MyTupleType(Foo foo, Bar bar)) {
// Do something with foo and bar
} else {
// Not reachable unless refactoring, etc. So panic here.
}
That else clause is so terrible you'd probably just rather use the getters from the type. var MyTupleType(Foo foo, Bar bar) = getMeTwoThings();
which IIRC may be even simplified to var MyTupleType(foo, bar) = getMeTwoThings();
EDIT: found it https://mail.openjdk.java.net/pipermail/amber-spec-experts/2... let Point(var x, var y) = aPointWhat are the benefits of having a multiple return type function?
I just assume that one can use an object if this is needed throughout the whole code..
Or maybe create an arraylist if possible and return that?
In go you can do this:
function (x, y int) (sum, prod int) { return x+y, x*y }
It makes a big difference when one is using the same input to generate multiple related outputs.
Some times one needs to create new objects return multiple related items from a function. Or use a collection or array. I think it is unnecessary. Other languages (e.g. go or python) have had this for a while now. I taking a wild guess here LISP probably had it since the 1970s.
I am not a Java developer. I am one of those users who has a bad memory of using Java desktop apps in ~2001 where they ate a ton of ram, seemed horrendously slow, and had example "Hello Worlds" that are reminiscent of Enterprise FizzBuzz [1]. At some point in the last 20 years, Java has gone the other way -- it has a reputation (I think) of being "boring", "performant" and used by businesses for doing server-side logic. Still, the only way I interact with it is with the occasional dependency install.
I've noticed:
-- There are a bunch of different JREs/JDKs, most famously Sun's/Oracle's own Java, OpenJDK, OpenJDK built by Other People™, and Random Other JDKs (Azul; Amazon Corretto).
-- People rail against Sun/Oracle and what happened to Java.
-- For a bloody long time I had to download the JDK separately and/or type in "agree" into a very un-friendly sounding license at the command line.
Can I therefore ask the HN meta-brain to either explain, or point me to a reference that explains:
-- What the ideological and practical differences are between the JDKs
-- Why there are different JDKs -- I get that that it's good to have different language implementations, but there are really quite a lot!
-- What Oracle did
-- And what was the beef with the whole open-source license was. Isn't opener-better?
Thank you!
[1] https://github.com/EnterpriseQualityCoding/FizzBuzzEnterpris...
They occasionally have a few small changes, maybe with a few extra bugfixes new or a backported.
The one small difference between compiling it yourself is that Oracle does control the TCK, a test suite for the binaries that Azul and others might use but not open to you.
Note that the horrible end user experience of running java programs (or java plug-ins in the browser) back in the day, never was indicative at all of how it's for running on servers and those kind of workloads. The stuff I've written in java for backends have been blazingly fast (compared to python for instance) and with much better tooling. So devs choose java/jvm because it works well, despite some shortcomings in some areas.
Btw, I think you'd find today's java desktop apps to be snappier than you'd think (especially compared to electron for instance). Bundling the jvm removes the hassle of having to install something separate and version issues. And AOT compilation and the new modularity of the stdlib makes the files smaller and quicker to load.
The builds may ship with different optional features enabled, such as various garbage collectors or I think support for the GraalVM stuff. Support terms differ.
> Why there are different JDKs -- I get that that it's good to have different language implementations, but there are really quite a lot!
Most of what you will get these days are just different builds of the OpenJDK class library + tools + Hotspot (JVM). Well, except for the android runtime, but we don't talk about that one. Historically there have been been more JVMs and class libraries but that has been consolidated a lot since oracle opensourced it. There still is OpenJ9 and some smaller, more specialized ones.
Oracle owns "Java", that is the name, the trademark, etc. In that sense, OpenJDK is "not" "Java". But operationally, this is moot. But it has impact in other areas. What was originally "Java Enterprise Edition" was transferred over to the Eclipse Foundation, but they couldn't take the "java" name with them. All of the JEE packages were "javax.enterprise.". Oracle wouldn't give up the "Java" part in order to not dilute its trademark, so now its the "Jakarta Enterprise Edition", and all of the packages are being renamed to "jakarta.enterprise.". I mention this just as an example of the hoops the community going through, even today, over what's happening with java.
So, Oracle and the community have to dance a fine line over what is the language, compilers, tools, and libraries, and what is "java", what is trademarked, what is owned by Oracle.
Oracle was kind enough to be an invested member in the Java community by not forking, closing, and going off its own way, and leaving the OpenJDK to fend for itself. This is essentially what happened to Solaris and OpenSolaris.
The other JDKs (Zuul, AWS, etc.) were certainly a hedge against this. The industry has a lot invested in "java", and can't really afford to let it get out of hand. Having "official" builds, that were supported, and patched, and eyes on vs the latest release from OpenJDK gives companies a secure feeling. That's why other companies stepped up to support their own JDKs. To help assure clients that the technology is stable and still worth building on.
So, the differences are not so much different languages, or even different implementations (though there is certainly some of that). Rather much of it is simply stability in the community.
Also, the whole licensing issue with Oracle vs the others was a big deal also. We'll see what impact the new free license from Oracle has.
That is quite a change, and probably not very backwards compatible?
But, yea, it was a big clod to drop in the churn.
I was also curious about large ecosystems like Hadoop and their moves from 8 to 11.
I've been interviewing lots of candidates recently, and i usually chat a bit about what versions they've used. Only one is using 11, the rest are on 8. One only finished migrating to 8 this year!
elapsed secs
binarytrees,java16,7 2.478
binarytrees,java17,7 2.475
binarytrees,java16,3 4.644
binarytrees,java17,3 4.574
binarytrees,java16,2 4.765
binarytrees,java17,2 4.772
binarytrees,java16,6 4.608
binarytrees,java17,6 4.594
binarytrees,java16,4 4.733
binarytrees,java17,4 4.808
fannkuchredux,java16,2 45.438
fannkuchredux,java17,2 43.921
fannkuchredux,java16,1 10.644
fannkuchredux,java17,1 10.382
fannkuchredux,java16,3 41.432
fannkuchredux,java17,3 41.110
fasta,java16,5 1.302
fasta,java17,5 1.255
fasta,java16,2 4.473
fasta,java17,2 4.325
fasta,java16,6 1.209
fasta,java17,6 1.191
fasta,java16,4 3.164
fasta,java17,4 3.202
knucleotide,java16,5 18.224
knucleotide,java17,5 20.063
knucleotide,java16,3 7.383
knucleotide,java17,3 7.332
knucleotide,java16,6 7.447
knucleotide,java17,6 7.373
knucleotide,java16,4 36.777
knucleotide,java17,4 36.712
knucleotide,java16,1 4.979
knucleotide,java17,1 4.851
mandelbrot,java16,2 4.148
mandelbrot,java17,2 4.119
mandelbrot,java16,3 7.382
mandelbrot,java17,3 7.348
mandelbrot,java16,1 27.733
mandelbrot,java17,1 27.793
mandelbrot,java16,4 5.221
mandelbrot,java17,4 4.415
mandelbrot,java16,6 4.247
mandelbrot,java17,6 4.300
nbody,java16,3 7.410
nbody,java17,3 7.454
nbody,java16,2 7.459
nbody,java17,2 7.472
nbody,java16,5 7.006
nbody,java17,5 7.027
nbody,java16,1 7.823
nbody,java17,1 7.818
nbody,java16,4 6.739
nbody,java17,4 6.768
pidigits,java16,1 7.375
pidigits,java17,1 7.891
pidigits,java16,2 1.336
pidigits,java17,2 1.342
pidigits,java16,3 0.928
pidigits,java17,3 0.926
regexredux,java16,6 5.593
regexredux,java17,6 5.362
regexredux,java16,3 5.582
regexredux,java17,3 5.313
regexredux,java16,1 9.021
regexredux,java17,1 8.441
revcomp,java16,5 4.364
revcomp,java17,5 4.392
revcomp,java16,6 3.080
revcomp,java17,6 3.011
revcomp,java16,3 2.310
revcomp,java17,3 2.369
revcomp,java16,4 5.005
revcomp,java17,4 5.029
revcomp,java16,7 21.809
revcomp,java17,7 23.196
revcomp,java16,8 1.537
revcomp,java17,8 1.527
spectralnorm,java16,1 6.173
spectralnorm,java17,1 8.016
spectralnorm,java16,3 1.631
spectralnorm,java17,3 1.577
spectralnorm,java16,2 1.655
spectralnorm,java17,2 2.334Both sets of times could be normalized to the C program times and then compared —
https://salsa.debian.org/benchmarksgame-team/benchmarksgame/...
https://salsa.debian.org/benchmarksgame-team/benchmarksgame/...
— by someone who was interested in that comparison.
Kinda like Rust guarantees that Option<T> has the same size as T (aka free like in free beer).
Making this optimization for something like Option<u8> is, naturally, impossible.
(I assume you are aware of this and were implicitly referring to this optimization.)
That is not correct. Trivial counterexample:
https://play.rust-lang.org/?version=stable&mode=debug&editio...
prints
4
8
i.e. Option<T> is 4 bytes larger than plain TRust guarantees to optimize the following types T such that Option<T> has the same size as T:
Box<U>
&U
&mut U
fn, extern "C" fn
num::NonZero*
ptr::NonNull<U>
#[repr(transparent)] struct around one of the types in this list.
UPDATE: Or, better per your example:
struct T {i: i32} takes the same size as i32: https://play.rust-lang.org/?version=stable&mode=debug&editio...Structs are nice, as they allow for control over locality, to a degree that is simply not possible in Java currently. But there is a second effect, which is possibly more important: If I can move gigabytes of my data into arrays of structs, then 1) I greatly reduce memory requirements (far fewer pointers), and 2) I greatly reduce the amount of work that GC has to do.
This is such an important thing to add to Java, and it seems to be perpetually off the stove, not even on the back burner.
Another way of looking at it: This is fundamentally just a performance optimization. Java performance is already exceptional for most of Java's popular use cases (business processing). While valuable, I don't think this one feature is quite as important as you consider it.
As an aside, and not to say that Valhalla is not needed (I am looking forward to it very much, along with Loom), I’ve recently learned that for many use cases (not all) when you want gigabytes of struct arrays, a bunch of equal-sized primitive arrays, one per struct field, might work even better from memory requirement and cache locality perspective.
Valhalla is being actively worked on, I'm not sure what you are implying here.
I'd wager that it will ship by the next LTS, in 2024.
Optional at least states the variable may not be referencing anything and provides helpful methods to chain mapping and conditionals to more easily deal with null values.
So then you get the best of both world, the safety of Optional without the boxing overhead.
if( arg.isPresent() ) ...
vs if( arg != null ) ...
How is this better? Long getSomeValue();
int max = Math.max(0, obj.getSomeValue());
The Optional value forces you to type some text basically acknowledging that the value can be null. Optional<Long> getSomeValue();
... obj.getSomeValue().get());
I'm not saying Optional is a great solution. It's essentially a notification that a value is nullable.The type system would need to be extended with a T? (nullable), T! (non-nullable), smart-casting on null-checks, and with some annotations or a flag to determine if T should be treated as T? or T! and whether you can call methods on it.
> How is this better?
It's not if you use Optional.get, but if you use .map, .orElse and the like the compiler can prevent you from getting NPEs instead of them being runtime.
Usually I know better what I need. There were cases when I needed to access the internals, e.g. fixing a prod issue.
A quote from Thinking Forth comes to mind:
> The newest traditional languages (such as Modula 2) bend over backwards to ensure that modules hide internal routines and data structures from other modules. The goal is to achieve module independence (a minimum coupling). The fear seems to be that modules strive to attack each other like alien antibodies. Or else, that evil bands of marauding modules are out to clobber the precious family data structures.
> This is not what we’re concerned about. The purpose of hiding information, as we mean it, is simply to minimize the effects of a possible design-change by localizing things that might change within each component.
Developer change internals, because they want to improve something.
Library breaks.
Users don't want to update to new Java because their code does not work.
They want to break that chain, I guess.
Also I think that you still can allow access to any internal class using --add-opens
This allows us to fix bugs in 3rd party software or the JDK itself until fixes can be released upstream and we don't wish to release an internal version of an artifact. Not something we use exclusively for obvious reasons, but it's a handy tool to have in the toolbox when we're forced up against a wall.
Yes, the strong encapsulation of JDK impl classes can create some inconveniences to an attacker. But I don't feel it's valuable enough to justify luck of access to the internals.
And there's the beauty of TypeScript....you can still use JavaScript as if TypeScript never existed.
Of course, many teams will fall in love with TS.
But you the library user don't have to give two farts.
Pardon sarcastic tone, but why would typescript be considered a pollutant. I sometimes develop in javasript and enjoy the hints I get now much more.
I have this misfortune of dealing daily with a nasty Java framework which converts compile time errors into runtime errors, single error trace with multiple stack traces , most of them being from framework itself.
One thing that might improve situation is server side libraries instead of framework. However AFAIK there is nothing like that in Java world. Everything is bound to Servlet API at lowest level and app server/frameworks on top of it.
https://github.com/google/dagger
After that you can throw in whatever libraries you want, dagger doesn't care.
This is the JDK version that ships with the wayland gui toolkits.
I’m psyched!
There's already support for Optional.
I mean I guess a lot of code would stop compiling, or could it be deprecated somehow.
I don't think it's a technical impossibility, but it's more likely to be solved by a JVM-based language like Kotlin than it is to get it adopted into the Java mothership.
IIRC that proposition for value types makes them more akin to structs, without inheritance and dynamic methods. And I don't remember whether the fields are final, but given the current trend towards making everything as immutable as possible, they probably are.
Kotlin (or any other JVM variant that does non-nullability in a seamless way) and coding guidelines should get you 90% of the way to a null-free world.
Java 1.0 to 5 was 8 years
5 to 8 was 10 years
8 to 11 was 4 years
11 to 17 was 3 years