JDK 15
jdk.java.net
jdk.java.net
String query = """
SELECT "EMP_ID", "LAST_NAME" FROM "EMPLOYEE_TB"
WHERE "CITY" = 'INDIANAPOLIS'
ORDER BY "EMP_ID", "LAST_NAME";
""";
It's one more step closer to scala/kotlin/etc.(Sorry, being somewhat lazy, I could pull up the spec).
> Incidental white space surrounding the content, introduced to match the indentation of Java source code, is removed.
I like how Scala does this via the indent marker and strip.
https://openjdk.java.net/jeps/378
I'm not entirely sure "most sophisticated" is entirely a good thing - but the jep looks pretty thorough at least.
Ed: how does Scala do it? Java uses the indents for the closing triple-quote to determine stripping/indent + cutting trailing spaces. Ie, if my reading is correct:
a = """
OK.
"""
Is "OK.\n" (even if there are any spaces after the dot).> Incidental white space is removed, as if by execution of String.stripIndent on the characters resulting from step 1.
The new stripIndent() method is provided as a convenience to developers.
def pushConstant(num: Int): String =
s"""
|@$num
|D=A
|$accessTopOfStack
|M=D
|$incrementStackPointer
|""".stripMargin
accessTopOfStack and incrementStackPointer are other functions that return text. It made composing Assembly a breeze.So given that, I don't think it really ends up being that sophisticated. I think this could be a decent easy programming question for a technical interview though!
At the same time I'm slightly scared of that magic. It helps that it's well-defined in the JEP.
Directly from http://openjdk.java.net/jeps/378:
Another alternative involves the introduction of a new instance method, String::formatted, which could be used as follows:
String source = """
public void print(%s object) {
System.out.println(Objects.toString(object));
}
""".formatted(type);yamlp performs string interpolation from YAML files:
https://bitbucket.org/djarvis/yamlp/
I reuse my library in my text editor:
https://github.com/DaveJarvis/scrivenvar/
The text editor can interpolate strings in a variety of contexts (such as Markdown, R Markdown, XML, and R XML documents):
https://www.youtube.com/watch?v=u_dFd6UhdV8
As far as I can tell, there is no performance degradation from the recursive interpolation; the editor reads, interpolates key/value pairs, and substitutes the resulting values into R Markdown documents riddled with up to a thousand simple formulas in about 600 milliseconds (on my desktop computer).
Also, the editor provides a way to maintain the interpolated variables in a tree-like view:
https://github.com/DaveJarvis/scrivenvar/blob/master/README....
The substituted values appear in the preview pane in their final form. This is all real-time and pure Java.
A. "${label1} ${label2} ${label3} .... ${label 400}"
B. "%s %s %s ... %s".formatted(label1, label2, label23, ... label400) // Ooops, typo!
Here, have another one:
I want to have a string with this content:
"Fluffy Nero Polly<random text> ... <random text> Trexxie"
Which one is easier to figure out and debug?
A. "${cat} ${dog} ${bird} <random text> ... <random text> ${dinosaur}"
B "%s %s %s <random text> ... <random text> %s".formatted(dog, giraffe, dinosaur, ..., cat).
To me, the difference shows up more with this scenario:
A: "${v1} ${v2} ${v3} ${v4}"
B1: "%s %s %s %s".formatted(v1, v2, v3)
B2: "%s %s %s %s".formatted(v1, v2, v3, v4, v5)
B3: "%s %s %s".formatted(v1, v2, v3, v4)
A does what you tell it, whether it's wrong or right. B has a chance of warning you that the argument list and the format specifier don't match. On the other hand, B gives you two things that have to be kept in sync with each other, and A can't get out of sync, since there's only one thing.
So: Less of a chance to make the error, or more of a chance to catch it. Which is better? I lean toward A, but I will admit that it seems subjective.
B only catches mistakes in the case that the number of parameters doesn't match the number of placeholders, which isn't even possible with A. If the string you built isn't correct, that's on you in either case, and should be immediately obvious by looking at the output. So in that sense, interpolation is strictly better than `formatted` at dealing with potential mistakes.
I mean it's not ideal, but sprintf and co are only intended for relatively short text (like logging), if you have any more, use a templating language instead. Plenty of those in Java as well (JSP, Velocity, etc).
String interpolation would be safer, as it would make the intent clearer, and you wouldn't risk bumping in corner cases. It would be even safer if the protocol could be overrided such that you wouldn't have to use Object#toString, but for Java that's too much already.
Java has been a very conservative language. And I understand why.
But it's funny how, for many features that were added later, people were rationalizing their absence with such lines too. E.g. we don't need anonymous functions / lambdas, as anonymous classes are enough. Well, turned out that Microsoft was right all along when they released those in J#.
Also adding a template engine is overkill for doing string concatenation.
There's nothing wrong with that. If string interpolation is really useful, then Java will add it some years down the line.
It's cheap to add features but literally impossible to remove them. There's no way to undo a mistake in language design. That's an asymmetry. I'd rather err on the side of caution than kitchen-sinking it.
I like how Java binaries still work on the latest Java, however, if distribution happens via binaries, why should the language keep source compatibility anyway?
Or, you know, the latest compiler could allow you to select the source code version you want. And automated code migration tools can work too.
---
Err'ing on the side of not getting features is why Java has lost a lot of mindshare.
Java is still super popular, but that's basically in spite of the language itself, because the language is awful.
Now is the year. String interpolation is really harmless feature.
echo "$(ls)"
in my zsh, so I'm not sure what to say, to be honest.
echo "Username is ${USER}"
As I recall (and Wikipedia seems to confirm), parameter substitutions were in the original bourne shell in 1979, so... Yeah, I'm not sure what's going on there.
Are you saying that they haven't been around for long or that they failed? If latter, then I respectfully disagree. Any recent JS and Python code I have seen uses them extensively. They are also a joy to use, and imho improve readability immensely. Ergonomics matter. This is one aspect of Python3 I would miss the most if I had to go back to 2.
[1] https://github.com/manifold-systems/manifold/tree/master/man...
A good video on this process: https://www.youtube.com/watch?v=2y5Pv4yN0b0
Functional style is cool and some people will go to great lengths to use it.
Like shaving a few characters of a perfectly fine piece of code by using currying and instead make one single long line of code describing it.
Can be very simple and elegant, like a better Python, on the JVM.
But also very rigorous, as a Java superset, with powerful features like mixing dynamic and static compilation in the same class.
Or even deep, with run-time metaprogramming and compile-time AST manipulation capabilities (giving tools like Gradle, Spock...).
And you have of course multiline interpolated Strings. And so much.
My absolute favorite thing is being able to do something like:
someIntegerCollection = someStringCollection*.toInteger()
I also find the use of closures for things like collection filtering to be quite nice: canadianUsers = someUserCollection.findAll { user ->
user.countryCode = "CA"
}
The equivalent in Python is a little more cumbersome and overly verbose: canadianUsers = [user for user in someUserCollection if user.countrycode = "CA"]
I'll still be writing things in Python whenever I can, but when I do write in Groovy there's a lot of nice stuff I get to have.Ultimately the issue isn't the presence or absence of those classes (because they aren't hard to write minimal versions of as a one-off if you need them and can't allow the dependency), it's the pervasiveness of use (or lack thereof) by libraries and especially the standard library.
If Try and Either were added to the Java stdlib tomorrow, the rest of the stdlib would still be stuck throwing exceptions for error propagation, because they can't change the return types of existing methods. The only benefit would be that third-party libraries could feel comfortable enough to use them in their type signatures. But, in practice, most libraries still target Java 8, so I wouldn't hold my breath for that, either.
[0] https://vavr.io
Why is that useful? Because now you can do a switch statement that matches on type:
int getCenter(Shape shape) {
return switch (shape) {
case Circle c -> ... c.center() ...
case Rectangle r -> ... r.length() ...
case Square s -> ... s.side() ...
};
}
As long as Shape is sealed, the compiler can be confident that these are all the possible subclasses of Shape.The benefits of enums (as these are referred to in some languages) is that after the safe downcast you have access to the fields and methods of the specific type just by invoking them.
Pattern matching also makes this construct even nicer to use (and I would argue that having one without the other is worse than not having either), but that doesn't seem to be included in the language yet, very probably for good reasons (I just don't follow Java development closely so I don't know about them).
public int countNodes(JsonElement el) {
return switch(el) {
case JsonObject obj ->
obj.entrySet().stream()
.mapToInt(e -> countNodes(e.getValue())).sum()
case JsonArray arr ->
arr.stream().mapToInt(::countNodes).sum()
default -> 1
}
}
[0] https://www.javadoc.io/doc/com.google.code.gson/gson/latest/...Where are these used? Well, they are used in a sense all over the Java language already in the form of methods with checked exceptions, which say in their contract that they return either a successful result or any of the declared errors but nothing else.
> The ability to reason clearly and conclusively about permitted subclasses will be realized in a future release that supports pattern matching.
If the final version ends up working as explained in the draft, it is going to be a fantastic addition to the language.
But http://openjdk.java.net/jeps/360 says:
> Release 15
Have they lied to me? Those monsters.
Too bad it doesn't appear to be coming in 15 :(
Java still makes the GC work harder than other languages. In some of my testing, idiomatic "microservice" Java code makes ~10x as much garbage per request as equivalent idiomatic Go code. Some of that is the language, and some is just that libraries and frameworks are super allocation-heavy. If the ecosystem can tighten that up, then these great GCs will have even more impact.
A lot of my recent projects have actually been fairly modest in terms of memory requirements compared to a few years ago where I'd have thought nothing of using 4GB heap on a simple spring app.
I'd love to see a jvm or graal implementation of ASAP memory management. The idea generally being having extremely aggressive analysis on your code, reducing heap allocations where possible, statically managing objects where they can provably infer object lifetimes, reference counting everything left over that provably can't result in cycles, and then garbage collecting everything else.
Do you mean this?
ASAP: As Static As Possible memory management
http://codrutstancu.com/p81-stancu.pdf
SVM has support for snapshots/isolates, where you can ~instantly instantiate a new JVM with a fresh heap. If you set your GC params such that it never really collects, you get something close to that but without the complexity.
Much to the chagrin of Martin Thompson, even the standard library is affected. Avoiding allocations is something most Java programmers don't even think about, because they are not aware it might be an issue and because there is no alternative - in Go and Rust you can stack-allocate instead, in Java you can't (not really).
This is interesting. I skimmed some introductory parts of https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-908.pdf as well as the definition of the SCAN function and searched the PDF for "reference count" to see how it does what you propose. At the moment I don't have the impression that ASAP dynamically reference counts anything. Let alone selectively reference count certain objects but use a tracing GC for others. Could you tell me where exactly to look for details? Wouldn't references from RC objects to GC objects, and vice versa, be an absolute pain to deal with?
That being said, it does read like it uses similar approaches to automated reference counting: code is inserted by the compiler to manage reference counts and eventually dispose of objects when no longer referenced. It also appears that there are approaches toward using regions and linear types where possible. I think the takeaway though is that ASAP makes as many decisions as it possibly can to statically enforce memory safety and reclamation, but building a finely grained program-specific approach toward garbage collection for anything else. Literally every distinct program would result in a distinct garbage collector tailored to that program that is inlined into the code.
While the JVM also has escape analysis, because everything is a pointer the chances of an object escaping is considerably higher.
I'm hoping that when Project Valhalla eventually lands, it'll help greatly with allocations and reduce memory pressure even further.
You want an List<T> of objects? It's now a list of pointers to individual allocations. You want a Path class instead of just passing strings around, for type safety? One extra allocation per object.
Especially Project Loom. Virtual threads will be a game changer. A return to original Java's rallying cry of programmer productivity.
There's always been steady progress, sure. But it seems like Oracle is much less risk adverse. Or maybe the governance changed. Or maybe Sun, IBM, other had been holding back a lot of progress. I'd love to know the backstories. To better inform future efforts.
Regardless, Java today is amazing and rapidly getting better.
Furthermore, it's a little bit of gatekeeping for those who may be entirely new to understand the difference between something like OpenJ9 vs AdoptOpenJdk vs Amazon Corretto.... you get the point.
It was quite clear since the beginning, plenty of Code ONE, Devoxx, NDC, JavaZone, Jax, InfoQ talks
Conferences that I expect any veteran to spend some of their learning budget, or at very least read some of the related articles on Java magazines.
but pron of Oracle says, a few comments over:
> No one offers free LTS ... those "free LTS" distributions you should know that you're using a JDK that's not fully maintained ... Maintaining a JDK is a lot of work ... For real support for an old version you must pay.
So it doesn't sound like it's really free. If the free version doesn't get security updates you can't really use it in practice.
My impression is that languages such as JavaScript and Go gain more and more track for enterprise software stacks. They are much more multi-paradigm at heart then the Java language could be. I wonder why Java doesn't learn from C++, which reinvents itself every few years. The lambda notation in C++ is really a thing Java could easily have.
Java has had lambda expressions, with what I would describe as cleaner syntax than C++'s, since JDK 8. Is there something I'm missing that C++'s have over Java's?
This has also lead to a lot of Java becoming much more functional, see especially the Stream API[0] (also added in JDK 8). I would say it's much, much easier to write functional-style code in Java than it is in Go.
[0]: https://docs.oracle.com/javase/8/docs/api/java/util/stream/S...
Java lambdas are just syntax sugar for anonymous class from language point of view. They're implemented differently under the hood, but they don't bring anything new to developer, they just save few lines of code which is nice, but could be much better.
On the rare occasion that I need to do this, I usually find that I'm thinking about the problem the wrong way and there's a much clearer way to write it than messing with mutable variables outside my closures.
Check out Brian's talk on Stewardship: https://www.youtube.com/watch?v=2y5Pv4yN0b0
I kid!
My bro is a C++ partisan. We've been arguing about this for 25+ years. Every time I'm about to use my crushing grip of reason to submit him, he wiggles free.
He's made a pretty good career from fighting misc compilers over the years. So who am I to judge?
I never really understand this. Tasks and threadpools work great. Are you excited that you can reduce memory usage? I have never been restricted before.
https://youtu.be/23HjZBOIshY?t=152
This is good too.
https://archive.fosdem.org/2020/schedule/event/loom/
I'll butcher it, but my TLDR is: Program sequentially, get threading for free. Any blocking calls are now async under the hood.
[1] aka @pron or https://news.ycombinator.com/user?id=pron
Your answer might be to use async, event-driven IO instead, but the central thesis behind virtual threads is that this is a terrible programming model, and there's no reason the programming language can't help you write your code top to bottom, but still get the desired performance.
There are lots of reasons for the continual stream of innovation but the biggest change has been the 6-month release cadence.
No. All automagically handled for you. Just write what looks a lot like regular code.
Now, can you change the default behavior? Yes, but now you're on your own.
The first versions of Java only had green threads. That was a cooperative threading model where only a single OS thread was used and the VM did a context switch while blocking for IO (in essence, every method declared as throwing InterruptedException could potentially context switch).
The mixed model you were talking about is most likely the threading model of Solaris where threads were split into a userspace part and a kernel part. It was possible to configure pthreads so as to use a multiple userspace threads on top of a single kernel thread (in a similar way as green threads worked in Java). It was also possible to run it in a one-to-one configuration or a version where you had a large number of userspace threads mapped to a smaller number of kernel threads. The last model was default in Solaris for a long time.
Eventually it was discovered that kernel threads were so fast in Solaris that there was practically never any benefit to the thread-pool model, and by Solaris 2.6 (I think, it's been a while so I could be wrong about the version) they changed it so that the default thread model was one-to-one.
I've just recently been able to upgrade some things to JDK 11.
The only free of charge LTS is the latest java version, all versions n-1, n-2 are out of free support, you can only buy one.
I got the impression (but please correct me if I'm wrong) that only this year most major libraries got all the kinks worked out for Java 11. In particular, when using them together.
Guice is one that only recently got the nasty (but relatively harmless) warning you get when using it with Java 11 under control.
Java 17 is the next long term support release, so most of us working on longer lived code bases will probably skip all the releases in between. It doesn't seem worth the effort, because if the Java 9 and 10 experience is anything to go by, you will be hunting down issues with Maven plugins, transitive dependencies, and libraries holding back for now all day.
Personally I've dropped guice and just stick to Weld anymore since it's the reference implementation of the standard. I haven't had any problems running it on JDK 14.
You had issues with 10? The only issues I got were with Java 9, because introduction of modules broke some stuff. Later it was just making sure that ASM or aspectj/lombok is in the most recent version that has new JDK version added, which might have been a problem in 10 (I know I was trying to upgrade on day 1).
But nowadays, all the most popular libraries are on par with the next Java version that is in the works at least a month before the release.
Since JDK 12, I just do an upgrade every 6 months and had no issues so far.
And if you don't ship software to clients then there is almost no downsides to upgrading and a lot of upsides.
If you do ship software to clients you should be using jlink, this way you ship smaller binaries and clients don't need to worry about JDK, because you will provide it to them .
And you also need to lookup what LTS means in case of Java - it is not the same as in e.g. Ubuntu.
In Ubuntu you get free of charge fixes in LTS, in Java you need to buy an LTS version from someone (they will make fixes there) OR use the latest JDK version (which gets all the fixes free of charge).
Plus, keep in mind that LTS is a paid service. What appears to be "free LTS" isn't really LTS, but builds of the OpenJDK Updates projects. Those builds serve as the basis for various paid LTS offerings, but in themselves they don't actually maintain the full JDK. OpenJDK Updates just backports stuff from the mainline version. If you're using a component that's been removed from the mainline -- and you probably do or else you'd upgrade -- then that component is not maintained in OpenJDK Updates (so-called "free LTS") because there's nothing to backport from.
The only version that's 100% maintained for free is the current JDK (15 as of today).
If you're using one of those "free LTS" distributions you should know that you're using a JDK that's not fully maintained. The only JDK version that's fully maintained completely free is the current version. To be fully safe and run maintained software you can either use the current version for free or use an old version and pay someone for LTS.
Maintaining a JDK is a lot of work. There are a couple of hundred full-time developers working on OpenJDK tip and maintaining the current release; there are ~10 full-time engineers (probably less) from all companies combined maintaining both OpenJDK 8u and 11u. For real support for an old version you must pay.
(I work on OpenJDK at Oracle)
The thing is that the money saved in hardware/hosting by running the current version would more than pay for any update costs. By using the current version, companies will be using better maintained software and paying less money for it. Those "free LTS" builds, which aren't really LTS, is a mind game that keeps companies on old versions that cost more money to run in the hopes that people will ultimately pay for real maintenance, perhaps once they fall behind too far.
1) OpenJDK Updates binary builds: they take the source code of the project, build it, and provide binaries. Examples I know are AdoptOpenJDK and the free Azul OpenJDK distribution.
2) Open source LTS: they take the OpenJDK Updates project, then add bugfixes they did for their PAYING customers. They publish the source code of the result. Here I see RedHat OpenJDK (such as the OpenJDK 8/11 builds distributed with RHEL 7/8). Those are then made available for free in binary form as well, such as part of CentOS. If you want a big fixed in those versions you have to pay, but you can benefit from bug fixes made for others. "LTS" here means as long as the RHEL version lives.
3) Paid LTS with custom support. Those do the same as 2, but don't release the source or binaries to the public, only to paid customers. Maybe there are even custom builds for specific customers. That would be Oracle mainly, and Azul and IBM as well.
What's unclear to me is if fixes from 2 flow into 1. Also, I don't know which kind Coretto is (Probably 1).
Is that a correct assessment of the situation?
There are other differences, too. Adopt, made by a particularly amateurish team at IBM that is barely involved with the OpenJDK project and quite unfamiliar with its workings, isn't a member of the vulnerabilities team and so gets access to security fixes later than all other vendors (and that's not the only thing that makes their build more problematic than all others). Among those that do participate in OpenJDK to varying degrees, including Amazon, there are differences in how much of the changes to their branded forks they upstream to OpenJDK Updates (RH upstreams more; Azul less).
Anyway, the important thing to know is that there is only one version that is fully supported for free -- the current one, and so the safe choices are either some paid LTS or the current version.
> Anyway, the important thing to know is that there is only one version that is fully supported for free -- the current one, and so the safe choices are either some paid LTS or the current version.
It looks like overstatement for me but reasonable perspective for Oracle employee.
Size isn't the only issue. Version number of fetishism is very much a thing in large companies. Megacorps and banks are very slow to update. I can't tell my customers to switch to Java 15 tomorrow (or even next year). Especially after the complexity of upgrades to 9 and 11, both of which broke things in many subtle ways. This may not be an issue for many applications, but it was certainly an issue for us and our customers.
I admit that doing away with major releases, giving the feature releases new version names, and the last ever major release was too much all at the same time and is confusing. But the payoff in learning what actually happened is big, as is the loss in not. Your customers might be losing both time-to-market and serious money for a lack of a day's worth of education. They can start here: https://blogs.oracle.com/java-platform-group/update-and-faq-...
[1]: The only version for which you get free support from anyone is the current version. No one offers free LTS for old versions. https://news.ycombinator.com/item?id=24487298
That might not sound too important but it has an effect on GC chosen amd obviously how you might have tuned your thread pools.
By now, I'd say if you depend on a library that still doesn't work on JDK9+ you should replace it, but depending on your requirements that may not be so easy and so some people are still stuck on JDK8.
I have tests that use JSON serialization and deserialization (and then some), and they pass perfectly fine on Java 8 runtime, but fail in exactly same place on Java 11, without recompilation. I have spent some non-zero time trying to get to the bottom, but so far without much luck.
In theory yes.
In practice the plugin and scanning systems the software I use has had a multitude of failures between JDK8 and 11.
The Hadoop ecosystem has definitely been dragging its feet on JDK bumps.
[0] https://github.com/apache/spark/blob/master/resource-manager...
And in the particular case of Java 9, they decided to deprecate several things, and quickly removed them in Java 11 (that is: with less than a year warning, and no warning if you follow only the long-term versions). That includes a lot of J2EE classes which previously came with the JRE, and now became external dependencies (with the most recent version of these external dependencies sometimes having slightly different behavior).
For example, in addition to the module system, Java 9 changed the implementation of some of its XML rendering libraries and caused meaningful behavior changes.
https://github.com/CodeFX-org/java-9-wtf has a list of some of the stuff that broke.
That said, 8 -> 9 was the only really painful transition in my experience. Since then the upgrades have been smoother.
anybody know why a javascript engine was ever included in core java in the first place? seems... niche. and yet core java never included a simple web server (officially).
GraalVM offers interop between JavaScript, Python, Ruby, R, C/C++ and of course Java and other JVM languages.
I think GraalVM has the potential to make the JVM something of a universal platform. I guess that was the goal with Nashorn as well, but now it seems much closer to fruition.
In my limited experience writing web code, the client side concerns itself with rendering and user interaction, the server side concerns itself with efficiently supplying dynamic data to the client, and other than request payload definitions the two have no logic in common.
Of course I could rewrite it in another language, but with Nashorn I don't need to. I can execute many hundreds of lines of Javascript with around four lines of utterly boilerplate Java. And it works perfectly. I don't need to worry about edge cases or dealing with subtle variations in regular expressions (don't at me) and other string parsing nuances.
I'm just a sole developer; I don't have minions. If I had to rewrite it today I'd probably look at a transpiling approach, but even then, defensive text manipulation tends to be edge-casey at the best of times.
(Also note that my priority here is browser performance, where it's running continuously on hundreds of clients simultaneously—often budget smartphones with limited CPU power. On the server it only has to run once per submit and the CPU cost on the server is beyond trivial.)
Release GA Date Premier Support Until
11 (LTS) September 2018 September 2023
12 (non‑LTS) March 2019 September 2019
13 (non‑LTS) September 2019 March 2020
14 (non‑LTS) March 2020 September 2020
15 (non‑LTS) September 2020 March 2021
Ref https://www.oracle.com/java/technologies/java-se-support-roa...I've been writing Java for longer than I've been driving, and way longer than drinking actual java. Geez. There's a certain fluency I have with this language that I don't have with any other language, not even Python/PHP/JavaScript/C#, all languages that I have 1k+ hours experience in.
https://openjdk.java.net/jeps/381
Wow this is the end of an era.
In practical terms, unless you want to test out Java features (which can be removed with the next release), you only need to track the LTS-releases every 3 years and actively upgrade every 6 years to stay on a supported version.