Hacker News new | past | comments | ask | show | jobs | submit login
What's new in Java 12, 13 and 14 (java.christmas)
202 points by sindrebn on Dec 17, 2019 | hide | past | favorite | 130 comments



One thing I find a bit disappointing is the focus on language features. Most of the effort in Java goes into the VM and libraries, while keeping the language conservative. This is because VM/library features have a much bigger impact on application quality, and more directly impact the application's users; moreover, it's a strategy that's proven quite successful -- HN notwithstanding, most developers don't like too much change in the language. Still, many developers focus on language changes that affect them, rather than major changes than can affect their customers and their business. Recent versions have seen major improvements to the GCs, startup time, and there's an exciting new Java Flight Recorder (low-overhead, deep in-production profiling) feature in 14 that allows streaming flight recorder events.

Also, the bit about LTS is problematic. While the multiple LTS update paths have their place (although the widely in their offerings and intended audiences), they are not less risky than the default path. The default path is designed to be the cheapest and easiest, but requires a little bit more agility. The effort required to update to a new feature release is not much bigger than the effort required to update to a patch release, especially as some of the LTS programs have major new features in their "patches." An LTS program should be chosen only once it's been established that the default, recommended update path is not right for your organization, and even then you'll need to compare the different LTS programs, as they differ from one another in about as much as LTS differs from the regular update path. LTS should not be the default choice.


I agree. I find the VM stuff the most facinating too, but I think you're underestimating the incredible impact language changes have had and continue to.

Language changes don't aren't just bells and whistles. Lambdas changed how nearly every API works and record types have the opportunity to make a huge difference. Sure var was smaller, but it's been refreshing.

I also think you're underselling how conservative the old minor patches used to be. With major versions this frequent LTS atleast sets a reasonable cadence for planning and movement. 6 months is hectic.


6 months is not hectic, because the new feature releases are not major releases. In fact, major releases are gone, the last one ever being 9.

Up until JDK 9, there used to be patch releases every couple of months, and big feature releases (which used to be called "limited updates") every six months. In addition to bug and security fixes, those included large, potentially disruptive features — like JavaFX and support for Linux on Arm in 7u6, Java Flight Recorder and Mission Control in 7u40, AppCDS in 8u40, and even support for Mac OS and a new GC algorithm in 7u4. Those releases also stopped getting patches after six months, when the new one was released, i.e. there were no more patches for 8u20 once 8u40 came out. Now, despite having major, disruptive features, those "limited update" releases were not allowed to change the Java SE spec, so they couldn't change the language or the library API. There were serious problems with the old model, so Oracle decided to do away with major releases altogether. To do that, they relaxed the limitation on spec changes in the six-monthly feature releases, and also changed their name. Instead of 8u40, 8u60 etc., they now get a new integer number. If you don't want to use new API and language features (you can even turn them off with the --release flag), those releases are almost the same as they used to be. If their six-month cadence between 8u40 and 8u60 was good enough for you back then, there's no reason it shouldn't be now.

(I work on OpenJDK at Oracle, but speak only for myself)


Man, I disagree. For large enterprises, six months is a ridiculous pace to package/distribute a new major version. The fact that it is just enhancements does not matter. It may seem simple, but most implementations have that integer as part of the deployment path. The aggressive deprecation/removal in the 'major' six month cycle has been rough. If this is my local workstation, no worries. It creates chaos on work systems, however.

(Did a decade+ at Oracle, and now at a shop three times its size. You should understand inflexibility and moving at the speed of business. :P )

There still are quarterly patches to the LTS releases (7u241, 8u231, 11.0.5), with the next batch due the second week of January for all the LTS versions - 7/8/11 on the Oracle side, 8/11 on the Adopt OpenJDK, and other OpenJDK implementations possibly supporting all three. Almost every other organization I've talked with is sticking to the LTS, with plans to jump from JDK 11 to JDK 17 when it comes around. (and hearing the woes of all the folks still trying to get past JDK 8)


> six months is a ridiculous pace to package/distribute a new major version

I agree, which is why we've done away with major releases altogether. There have been feature releases every six months with major new features for over ten years now. All that's changed is that we've changed how they're named and removed the major releases. And if you've found it acceptable that the 8u20 feature releases stopped getting patches after six months, and upgraded to 8u40, it shouldn't matter much that we now give those versions an integer number. Not only do you not need to package a new major release every six months, but you don't need to package a new major release ever again!

Your assumption that it's significantly harder to switch from 11.0.2 to 12 than it is to switch from 11.0.2 to 11.0.3 does not seem to be based on any data we've seen. Most organizations that can do the latter can do the former. Not only the result will be cheaper and easier overall, but you'd get to enjoy all the performance and serviceability features even if you don't want to use new language/library features.

> Almost every other organization I've talked with is sticking to the LTS, with plans to jump from JDK 11 to JDK 17 when it comes around.

That will change soon (it already is changing), as more people understand the new model and the change to the version names. However, even if you are certain that your choice of LTS is justified (and I must say that it doesn't seem like you fully understand the new model yet -- which is OK, many don't, and it will take time), you must test your code on the current JDK. Updating from 11 to 17 without doing that is taking a huge risk. You will see features disappear without deprecation warnings.


> However, even if you are certain that your choice of LTS is justified (and I must say that it doesn't seem like you fully understand the new model yet -- which is OK, many don't, and it will take time), you must test your code on the current JDK.

I think this the italicized portion is the disconnect between what Oracle wants Java users to do, and what they'd rather not do. I know the pain of wanting your users to always be on the latest and greatest version, but in my experience, medium-to-large corporates are extremely risk averse and would rather invest time upfront to do testing/qualifying software releases before deploying, then keep that deployment running for as long as possible with the assurance that the configuration is stable (or at least has known & documented failure modes). They understand the new model just fine - they just don't want it. Mostly because it introduces a lot of risk and/or requires continuous qualification, which is not only expensive but completely changes the way they operate.


I understand that, I'm just saying that if your risk calculation concludes that LTS is less risky by default, then it's based on false assumptions, based on misunderstanding. The new feature releases are not major releases. If companies were fine upgrading to feature ("limited update") releases while there were still major releases around, I don't see why they would be more risky now that major releases are gone. I think that people can perceive them to be more risky because they confuse the change to the way those releases are named with the old major releases. For some companies, getting an LTS service is less risky, but not because of some intrinsic quality of LTS but because of their particular internal processes. For a great many companies, sticking to the default, gradual update process is the cheapest, least risky option.

Moreover, there are also special risks to LTS programs, particularly the free ones. A much smaller number of people work on them (about 1/50 of the total number of people working on OpenJDK), and they completely rely on backports from the mainline. So, for example, once the CMS collector is removed from the mainline, it becomes unsupported in some LTS programs (certainly the free ones) because there are no longer fixes to backport, and they don't have the resources to fix bugs without backports.

Finally, you can't talk about risk and treat LTS as a single thing, as the different LTS programs vary greatly in their risk vs. conservativeness. The Oracle LTS service contains almost only true patches: bug and security fixes, like the first two patches for each feature release. Red Hat's LTS/OpenJDK Updates and Azul's Zulu backport huge new features in their "patches." Amazon considers (or considered) taking the current VM and backporting it as a whole to an old JDK version in a "patch."


> I understand that, I'm just saying that if your risk calculation concludes that LTS is less risky by default, then it's based on false assumptions, based on misunderstanding.

I agree with you - and I don't think LTS have less inherent risk. The distinguishing feature of LTS releases is the length of support - you can still release minor versions weekly, but still bless every 25th minor release as the LTS versions and it would work out the same because the users will know that version will get support for X years without full requalification.

You could very well be right about the 3rd-party patches/back-porting (I'll take your word for it, I'm now at the periphery of the JDK world), but their existence could be a sign of how Java users are desperately unprepared to support evergreen releases.


They're not evergreen. The last major Java release was 9, two years ago. Since then, Java has had a perpetual stream of free support.

The very notion of a "support period" becomes less relevant because what is the version that is being supported? It used to be a major release but that is now gone. The old six-monthly feature releases were also "supported" by patches for only six months. There were no more patches for 8u20 once 8u40 came out, and people were fine with that and not desperate at all. So now that we name a version 12 instead of 9u60 it's not fine? If you like, you can think about it as if we're on Java 9 forever, with an eternal support period. It's just that how the versions are named has changed.

People still don't understand the meaning of the new versions and the change to the version naming scheme. With time, they will. In the meantime, some of them still apply old terminology to new concepts and reach wrong conclusions.


> Updating from 11 to 17 without doing that is taking a huge risk. You will see features disappear without deprecation warnings.

If upgrading from one stable release to the next stable release removes features without a deprecation period, something's wrong with the release model.


No, stable releases do get deprecation warnings, but that's not what LTS is. LTS is a service that's added by vendors to arbitrarily chosen versions. In fact, there is no such thing as "an LTS release." You can start offering LTS for JDK 12 tomorrow, making it -- retroactively -- LTS. The OpenJDK development process doesn't take those services into account; in fact the development process has no notion of LTS at all (e.g. can you see LTS mentioned here https://openjdk.java.net/projects/jdk/11/ ?). All feature versions are equal in their stability. LTS is something a release can have, not something it is. All versions between 11 and 17 are stable, and none of them -- including 11 and 17 -- are major releases. Those are gone.

LTS is a service designed for organizations with special constraints, and should be no means be your default choice. Moreover, there are multiple LTS services and they differ quite widely in what they offer and who they're aimed at. Put simply, LTS does not mean what it means in other projects. Do not choose it until you've learned exactly what the new model means and what LTS means.


Versions 12 to 16 are/will be stable releases.


Language changes are super important when they enable you to program in a new way, or in that way with significantly less boilerplate. For instance, Java 8 enabled new ways of programming via Lambdas and structural typing. You could code in that way before, but anonymous class boilerplate was so high that few bothered, and those that did were hard-pressed to convince their colleagues of its value.

The problem with language changes is that to make use of them, your developer community has to educate themselves on the new features and how to use them. Certain VM changes like new GC algorithms often don't require this, as the basic interface of the GC is the same (clean up garbage for me, thanks!).

I think the next big programming style Java may enable is what I call data-oriented programming, which is enabled via sealed types and pattern matching. This enables you to code the dual of OO, where you have a fixed number of sub-types but an unbounded number of operations. I believe this style of programming is useful far more often than it is used, simply because Java doesn't make it easy to code in this style.

Other future changes I am excited for, but don't expect to get implemented any time soon, if ever, frankly, are:

* Improved native code interop. I consider this to be both a language and VM change. * Improved memory layout control, including stack-allocated types and inlined objects inside of other objects. * project loom for golang-style I/O programming. * full tail recursion. Why was this feature rejected from the VM?


> Other future changes I am excited for, but don't expect to get implemented any time soon, if ever, frankly, are:

Most if not all of them will land in the next few years. In fact, working on those precise features is what most of the OpenJDK team does.

> Improved native code interop. I consider this to be both a language and VM change.

That would be Project Panama, making its initial, partial delivery in JDK 14 (GA next March, EA available now).

> Improved memory layout control, including stack-allocated types and inlined objects inside of other objects.

Project Valhalla. The most complicated of the bunch. Just had a recent major breakthrough, and you can work with the EA release already.

> project loom for golang-style I/O programming.

Working on it :)

> full tail recursion. Why was this feature rejected from the VM?

Not at all rejected. It's still a goal for Loom. We'll just do lightweight concurrency first. Cost/benefit prioritization etc.


Utterly dumb question but why is tail recursion necessary in the JVM given that the compiler is better placed simply to turn recursion into a loop. TR removal should be done best at the highest level I'd think.


The compiler can only make this transformation in special cases, in particular, when it doesn't break any of the JVM's semantics (also, not all recursion is self-recursion, i.e. a tail call to the subroutine you're in). You can't just discard a frame of a call in a tail position, because some security mechanisms require knowing the full call-stack (plus, developers might hate you when their stack traces start missing crucial frames). So we're talking about explicit tail calls, in places that can be checked for the safety of the optimization.


> the compiler is better placed simply to turn recursion into a loop

How do you think it should do this? While keeping the semantics of Java.


> For instance, Java 8 enabled new ways of programming via Lambdas and structural typing

What does structural typing refer to in this context?


> One thing I find a bit disappointing is the focus on language features. Most of the effort in Java goes into the VM and libraries, while keeping the language conservative. This is because VM/library features have a much bigger impact on application quality, and more directly impact the application's users; moreover, it's a strategy that's proven quite successful.

I think people have taken note of the success of Kotlin, and decided that judiciously chosen language features will help user retention/adoption.


The thing I find disappointing is the lack of bytecode changes.

The language changes are all just trivial tweaks to javac. Appreciated niceties, sure, but nothing meaty. The VM changes are then likewise focused mostly on the GC. Again, appreciated, but it's entirely disconnected from the language.

Where's the long-overdue improvements to the bytecode? Where's value types? Where's runtime generics?


It's not true that the VM changes focus mostly on the GCs. There have been significant changes to startup time and low-overhead profiling. And there are constant improvements in the JIT compilers. Project Loom's lightweight concurrency also involves big VM changes, but without any bytecode changes.

Reified runtime generics for reference types is a bad idea; it destroys language interop for very little gain. Value types and specialized generics for value types, on the other hand, are in the works. You can download and play with them here: http://jdk.java.net/valhalla/


> One thing I find a bit disappointing is the focus on language features

Overall, I wouldn't underestimate the importance of syntax features. After all, if a developer likes writing your language, they'll more likely choose it over a different language.


I agree because I use the JVM but I do not use Java. So I care about changes to the JVM and ecosystem but changes to the Java language itself don’t mean anything to me.


Pattern matching in switch statements (calling them match statements would then be more fitting), a nice way to deal with nulls, and proper sum types (aka tagged unions, like enums in Rust) and Java would be pretty up-to-date.


I'm still not sure why imperative/OOP language have been so resistant to adding pattern-matching of the sort seen in Haskell and OCaml.

There are plenty of almost entirely pointless features that get implemented in major languages, like 'events' in C#. They add almost no value to the programmer. Pattern-matching would be really useful for avoiding rats' nests of control-flow, but until recently no major imperative language even seemed to consider adding them.

The extremely obscure Felix programming language has had pattern matching for years. [0] As nestorD says, Rust has them now, as does Kotlin. About time.

[0] http://felix-lang.github.io/felix/


I hugely disagree with you thinking that event is useless in C#, rather I think it should have had been implemented as built-ins in every major programming language in the style of what C# did.

Not only that it makes every possible event explicit and stand-out on its own, which is good for inline optimization and documentation (think about the catastrophic event handling in JS world), it also provides a standard, much more intuitive syntax using formal function delegate declaration (think type-safe function pointers), vastly different than what we do in JVM.

Before having lambdas in Java, we need to add an EventListener as a variable and adding an extra interface, so event handlers are insidious to write, that you have to write a new class, implement the specific interface, write some shim properties to store externally-living variables explicitly, and finally "new" that class as an instance, and add it to a specific event listener, which is not only verbose, and also costly, in terms of memory use (it has to be backed by vtables rather than simple functions) and time taken to implement it.

Well after the long-awaited introduction, Java finally have limited lambda support that just generates a class and it have some odd issues with, for example, enforced effectively final variable reference [0], but in C#, you have delegates and events almost from day 1 -- and it handles all that event mess nice and clean where nobody can still beat that simplicity and elegancy even till today.

[0]: https://stackoverflow.com/questions/34865383/variable-used-i...


> it makes every possible event explicit and stand-out

I agree that's nice to have - essentially announcing events as special in the type system.

> good for inline optimization

Any optimisation here should be possible with an ordinary implementation of the observer pattern, no?

> it also provides a standard, much more intuitive syntax using formal function delegate declaration

I'm not convinced that it does. Without events, we can still write:

    var h = () => { doStuff(); doOtherStuff(); };
    subject.registerObserver(h);
> Before having lambdas in Java, we need to add an EventListener as a variable and adding an extra interface

I suspect we're both right, then: events were introduced for a good reason, but now that C# has lambdas and such, they don't seem to add much.


I'd much rather use events than that snippet.



There's also some draft for the proper sum types (aka tagged unions). But we need 'm confirmed! Cannot get my code to use it and then they do not get in and I have to un-cleanup the code base.


Erlang is where I first encountered pattern matching, and it's so integral to the language it simply would cease to exist without it.

I was pleasantly surprised when I discovered Python 2 would pattern match tuples in function parameters...and then very disappointed when I discovered a few weeks later that Python 3 had removed even that minimal amount of syntactic sugar.


The reluctance might be because polymorphism and pattern matching are kind-of solving the same problem from different angles.


That's an interesting point. I've been wondering for a long time why a lot of people who are exposed to pattern matching in Scala never start using it themselves, even if they understand it well enough to read pattern matching code without difficulty. It often offers a simple, transparent way to express logic that looks very tricky using if/else, but despite seeing examples they keep reaching for if/else even in awkward cases. And I've observed that they end up adding methods to classes solely to be used in a single piece of if/else business logic, which often (in my opinion) are the concern of the business logic that uses them, not the concern of the class.

And I find that we disagree. When I frame a question as, "How does this algorithm handle this value?" they frame it as, "How does this class behave in this algorithm?" Is the difference in how the types are treated in the algorithm best expressed as the concern of the class (via polymorphism) or as the concern of the algorithm (via pattern-matching)?

I write a lot of OO code with polymorphic methods and am not opposed to modeling things that way, but I think it's often not the best way. I feel like business logic that could be expressed coherently in a single place gets scattered across many classes, and to understand the algorithm you have to gather the logic from a bunch of different places and reconstruct it. Not only that, classes accumulate little fragments of logic that belong to disparate concerns that are supposed to be handled elsewhere. If you have polymorphism and not pattern matching, this is inevitable. If you have both, it can be avoided.


That's not really true. OOP discourages inspecting the class of an instance, but still has conventional imperative control-flow. Deeply nested 'if' statements can rapidly become less readable than pattern-matching.


I'm curious if there is an elegant way to deal with backward compatibility when adding another case to a widely used sum type? Is it just a matter of fixing all the compile errors immediately?


I think the limitation you are describing is one of the two aspects of the expression problem[0]:

- with objects you can easily add new types, but it's difficult to add functions (methods) dealing with these types

- with sum types you can easily add new functions, but it's hard to add new variants in the sum type

Is it possible to overcome these limitations? I first read about the expression problem in the excellent post "The Expression Problem and its solutions"[1] on Eli Bendersky's blog (discussed here[2] on HN); as the title suggests it does present interesting ways to "solve" the expression problem.

However he also points out that the chosen solution in a a typical programming language (visitor pattern) quickly becomes unwieldy. The second solution (multimethods) is much nicer to deal with, but requires support from the language.

[0]: https://en.wikipedia.org/wiki/Expression_problem

[1]: https://eli.thegreenplace.net/2016/the-expression-problem-an...

[2]: https://news.ycombinator.com/item?id=11683379


Thanks, this is interesting discussion.

It seems like these treatments tend not to get to the heart of the expression problem as seen in actual language tools, which is migration between language versions. Let's say you're on version 5 of a language and you want to migrate all your tools to support version 6 where there is a new expression type. Can your codebase clearly represent a situation where some tools have been migrated to support version 6 and others aren't done yet? Can you easily figure out what remains to be done? And once the migration is done, can we remove any traces of the previous version that we don't want anymore?

And how do we approach this if the AST is published as a library and each tool is a package written by a different team?

There might be other usages of sum types that are simpler, though.


Scala is a JVM language with excellent pattern matching. (Including completeness checking, to a limited degree.)


Oooh that's a good idea. Does that already exist in other languages? I've not seen it before.


Ocaml, F#, Rust, Kotlin (I believe), Haskell, etc

It is a common feature in languages derives from the ML family[0].

[0]: https://en.wikipedia.org/wiki/ML_(programming_language)


Kotlin doesn't have real pattern matching.


It doesn't, but at least 'when' statements will be exhaustive when working with sealed classes - which is a breath of fresh air if you enjoy working with sum types and pattern matching.


when expressions will be exhaustive, when statements will not.

Needless distinctions like that make the fresh air a little less fresh...


Scala has had this for a long long time: https://docs.scala-lang.org/tour/pattern-matching.html


Swift also have them.


You still get the ancient and quirky generic programming, barely a support.


Java is actually getting quite a few nice features these days. I am especially excited about these improvements to the `switch` statement – I have always felt that the `switch` statement is more or less useless in its current form. Now, if it only had exhaustiveness..


I'm more looking forward to things like Project Panama.

A big gap between Java and C# is value types and better interop with native code ("pointers"). ByteBuffers in Java are painful for many usages and very poor compared to things like [StructLayout(LayoutKind.Sequential)] in C#.


As someone that used to write a lot of C#, I find that the language is changing so often that it's hard to know what's new and what's been around for years.

In contrast, Java hasn't changed all that much over the years, and I wonder if an approach of taking the more useful features from C# and ignoring some of the others would be a good approach.

I often wonder how Java developers feel when they look over at C#, and see a language that has exploded in functionality over the last decade, all while Java has mainly optimised the JVM and slowly added features.


It's not taking some features and ignoring others. It's taking features than have shown good cost/benefit, and not taking those that haven't. The choice here is about which features not to adopt, just as much as it is about which features to adopt. Java's philosophy is still innovation in the VM while keeping the language conservative. It's just that conservative is a relative term, here. If some language feature seems to have a good cost/benefit ratio and it's become mainstream enough, Java will adopt it.

BTW, Java has also "exploded in functionality over the last decade", it just hasn't translated to language changes. Even the project I work on, adding lightweight concurrency, will not change the language at all, while in C# it took the form of a huge language change (async/await). Nevertheless, in Java the added functionality will be at least the same as it's been in .NET.


> It's taking features than have shown good cost/benefit, and not taking those that haven't.

I actually wonder if it's more taking features that have proven sexy, and ignoring the rest. I still think that the single biggest source of verbosity - and design damage in some of the newer APIs such as streams - is that Java hasn't implemented extension methods. That costs me time and money on a regular basis. By comparison, the cost of fall through by default in switch statements is that I have to use a linter. Which I already have to do for a fistful of other reasons, anyway, so, while this -> operator certainly scratches an itch I've had, it doesn't move the needle much in terms of productivity or code quality.

edit: Should add, in C#'s defense - .NET's lightweight concurrency was initially implemented as a library. C#'s async/await came later, and is just syntactic sugar as far as I've ever been able to tell.


First, no language feature has been shown to move the needle much in terms of productivity or code quality. We are unable to detect differences between (reasonable) language choices, let alone individual features, so it's mostly about ergonomics. I'd be extremely surprised if you could show that any feature or lack thereof actually costs you money, but if you could, that would be quite a discovery. As to extension methods, they're not ignored. The language team is just unconvinced it's a good feature, which doesn't mean there aren't people who like it. As to switch statements, the language team had actually analyzed many hundreds of millions of lines of code before committing to the feature.


> First, no language feature has been shown to move the needle much in terms of productivity or code quality.

Absolutely true. When I've looked at that research, I was really quite impressed by how little has gone into looking into it, considering how interesting the subject is to so many people. My guess would be that it's because it's prohibitively expensive to study. That said, there was one result that I believe was shown to be fairly robust, and independent of language: that bug rate and cost are both generally proportional to lines of code written.

To that extent that that may be true, while I certainly don't have a $500,000 study by a team of professors at Stanford to back me, there's at least a plausible basis for my own perception of doing better work in object-oriented languages that do or do not have some sort of mixin mechanism: I find that using them often lets me get the same job done in less code. (Without that, I admit I have to retreat to pointing out that absence of evidence is not evidence of absence.)

There's also the design damage thing. Some developers on my team are quite resistant to using streams instead of loops in Java, and it's precisely because of the poor ergonomics. If you need to do an operation that isn't built into the Java API, you have some sub-par options: You can implement a collector, which is justifiably criticized as being a hassle (6 methods to implement) that yields code that scans poorly (every other verb is "collect"). Or you can implement a function, but using that function requires breaking the flow of the stream code by creating a bunch of intermediate variables, or, worse, constructing a pyramid of doom. By contrast, when we're working in Kotlin, you can just write a function and deploy it the same way you'd deploy any other method in its equivalent APIs. It's less effort, it's less code (read: stuff to get wrong), and, perhaps critically, it's a lot less annoying.


What operation that isn't in the stream API would you say you need most often?


> I'd be extremely surprised if you could show that any feature or lack thereof actually costs you money,

Bad language design and semantics definitely costs money in the long term. For example, Tony Hoare refers to Null References as his "billion dollar" mistake. The verbosity of Java before sophisticated IDEs would also have cost significant time and money. Java is improving significantly (and arguably was never as bad as say JavaScript or PHP), but there are some legacy decisions that will be very hard to change; and so improvement can only ever be incremental.


> and so improvement can only ever be small and incremental.

You seem to hint that some hypothetical non-small improvement can be made differently (in some other language). Perhaps it could, but it doesn't seem anyone has done it yet. We do not observe large differences between and in companies based on language choice. I think some of the reason is that developers overestimate the cost of coding in the entire software development process.


> We do not observe large differences between and in companies based on language choice.

Hmm, I think it's pretty clear that most folks are far more productive in Python than say C++. But yes, I agree that there's no silver bullet, programming is hard.


Well, not at all in the domains where C++ is normally used nowadays; that's why I talked about comparing reasonable choices. On the other hand, you can see how quickly people transitioned away from C++ to more appropriate alternatives in those domains where C++ is no longer used. It happened virtually overnight (same as the transition from Assembly to Fortran and from Fortran to C). When you don't see such a rapid transition it's usually a good sign that none of the alternatives offers a big advantage.


> I often wonder how Java developers feel when they look over at C#, and see a language that has exploded in functionality over the last decade, all while Java has mainly optimised the JVM and slowly added features.

I am a long time Java programmer that has mostly programmed C# lately.

I'm getting more conservative by the years but I still found myself liking modern C#.

The thing I miss from Java is the ecosystem:

- three top notch IDEs

- more mature ecosystem

- maven


Use Rider and Nuget and you shouldn't miss much.


I like C# more than Java because it is improved more often. Conservatively of course, but each version adds some new good stuff to play around with. Java felt like it stayed the same for so long.


I find it to be the opposite. In recent years C# has had modest language changes while Java has introduced streams, optionals, lambdas, function pointers...a whole lot of catch up and IMO arguably in an uglier but ultimately quite similar way to C#. Now I get to relive another couple years of devs learning, unlearned, and then properly learning when to use Linq/streams.

Optionals and the new IO libraries are causing far more churn in my Java code and the libs I use than any recent C# changes.

The Java language doesn't feel conservative to me. It just feels slow. What was worth the wait? What does Java do better than C#? The only thing I miss while in C# is Java's take on enums.

All that said, I don't begrudge Java as a whole. The JVM and other priorities add a lot of value and I'm glad their adherence to bytecode compatibility remains strong. The language is the trade off but that doesn't mean I need to pretend its better.


Java has changed a lot too. Its a real problem in an old code base as there are different generations of developers writing in different styles making the whole thing inconsistent and confusing.


The new style of switch statements is very nice. I've found myself using if else blocks to replace switch statements because they're simply more legible, and they take up less vertical space. Now the new style switch statements will be an improvement over that.


Its copied from Scala pattern matching, and still isn't as good as it.


Almost all features in the Java language are guaranteed to be copied from other languages because it is in Java's "charter" not to introduce features that haven't been tried in other languages first, and then copy only those that have shown a good cost/benefit. The question you should ask is not which features are copied, but which ones aren't.


It's not copied from Scala, there were many languages before Scala which had this feature before.


what's up with all these .christmas domains appearing high on HN listings?

there appear to be accounts dedicated to posting from javascript.christmas, java.christmas, and functional.christmas , all of the same style/format/etc.

the only posts they submit are from those domains. is this a coordinated boosting effort?

functional.christmas => https://news.ycombinator.com/submitted?id=bendiksolheim

javascript.christmas => https://news.ycombinator.com/submitted?id=ewendel


https://blogg.bekk.no/introducing-bekk-christmas-ad01660ccad...

Is there a rule against authors posting their own content? It's not some grand conspiracy, it's just an christmas campaign by a company that has asked their employees to write about topics that interest them, and those articles are shared during advent. On the 25th it'll presumably go quiet again until December 1st 2020.


Looks like spam. I've flagged the most recent posts, hopefully the mods see this.


how is it spam if it's just shared various blog posts from a single website?


Scroll down to the bottom of the page, it’s essentially a single website.


"Bekk is all about craftmanship and the people crafting it. This year, we're creating 12 calendars, each with daily content, articles and podcasts."

Seems like they are trying to attract developers, shame their main site is Norwegian.


If I'm not mistaking, there is no JEP for making throw statements expressions. Is there an obvious thing that I'm missing here? It would make sense for concise method bodies [1] and throwing in switch expression branches more consistent (over making exceptions for throw statements). Also, C# did the same thing.

[1]: https://openjdk.java.net/jeps/8209434


Why are they spewing Java versions so quickly? I have barely moved to 8 yet.


Java moved to a six-months release cycle in 2017: https://en.wikipedia.org/wiki/Java_version_history

Java 8 had its end-of-life for commercial usage in january 2019. The new long term release is Java 11.

Time to move on for you.


>Java 8 had its end-of-life for commercial usage in january 2019

_Oracle's_ Java 8 end-of-lifed, but many other vendors provide TLS for their respective Java implementations.


Just a correction: they are not separate implementations. Almost all vendors use Oracle's Java implementation -- OpenJDK. It's just that only Oracle and companies that license the source from Oracle (like Azul) can release non-GPL builds based on OpenJDK, so other vendors maintain old OpenJDK versions by doing their own backporting from the mainline, where most of the work is done by Oracle.


Amazon Corretto and Azul are making decent efforts for this. You can also find openjdk 7 versions with some support still.

For actively developed projects, I would recommend moving to java 11 without too much delay unless you have pressing technical or business reasons not to. If it's dead code and it is not causing issues, don't mess with it too much.

The Java 8 to Java 11 upgrade is unfortunately somewhat disruptive due to the module stuff. That affects some projects that depend on JVM internals, which tends to include e.g. older versions of application servers. Upgrading those is a bigger deal usually.


Some companies spend longer than six months to discuss/agree to a 'major version upgrade' of software.

Naturally the gap between (say) Java 10 and 11 is fairly small, meaning it shouldn't take many months to merely discuss an upgrade - but not all companies have got round to the regular-release way of thinking.


Java 8 was released March 18, 2014, so they had 5 years to upgrade.

But I see your point about the new release schedule, where the LTS version is not supported after 6 months.

I think the companies need to change their mindsets. New Java version are backwards compatible, as they introduce changes gradually.

It is actually more dangerous to wait, because they risk that some features (like GC) are deprecated after 4-5 versions. By updating regularly and keeping an eye on deprecated features, they should have time to adjust


I still need to pass weird flags for Tomcat to make it work under Java 9+, almost 6 years later. Modules were a mistake. If not for modules, a lot of people would have migrated to 9+.


Modules were certainly the biggest upgrade barrier ever in the history of java. But the have enabled a way for the JDK to get smaller without them we would face the JDK getting bigger with each release, which is not sustainable.

So on reflection I think it was a good move. Most frameworks and libraries work on modules now.


Modules where not a mistake but we will likely benefit from it in say at least 5 years. Every artifact/library you use has to be a (real) module to be able to use it's full potential.


I've yet to see a real world use that is meaningful. Mostly it just adds deployment bureaucracy for opting in to stuff that used to be there by default. I'm not seeing a huge adoption of modules outside of Java's core libraries.

A good thing that came out of it was that it forced them to untangle the 2 decades old standard library. This was disruptive but it seems to have also unblocked a bit of progress and also allows the to have experimental modules in non lts releases (9,10,12,13).


The LTS versions are supported past 6 months. Java 11 has 2 years of public updates through AdoptOpenJDK. The next LTS (17) will no doubt have similar.


It doesn't matter so much, as Java is backwards-compatible to stone age. If the company has finally settled on a backlog, they can start with whatever LTS version is the most recent one.

It's only a drawback for hired hands that may have become used to the features in v13 and then land a gig where they have to scale back to v1.6, that has to hurt.


I thought the whole point of backward compatible versions, is that you don't discuss, you just move.


It's not really an "update every 6 months" thing - I imagine most companies will stick to the LTS releases which are less frequent.


Not really. The real world seems to move much slower. I'm not sure if Android even fully supports 8 yet.


They recently moved to the same version model as Firefox, Chrome, and others have: Major version bump at a regular cadence. They used point releases before: there are a few Java 8 versions.

They still used to gate bigger language changes on major version releases, so upgrading point releases to major versions at a 6 month cadence let's changes roll out more as they're done.

Iiuc they're treating every third version as a candidate for LTS versions depending on your vendor. So people who for features are excited for every release, but those care for a little extra stability care about 8, 11, 14 etc.


I really wish they would use a numbering scheme that used points for the non-LTS releases: 8.0, 8.1, 8.2, 9.0...


I’m wondering when Java 2 comes. Java 12 is actually 1.12...


They dropped the pretend Java 7 => Java 1.7 thing already. They don't even do 7u80 style versions anymore.


Really? When?

EDIT: It went Java 1.4 -> 5.0[0]

[0]: https://en.wikipedia.org/wiki/Java_version_history


> Java 12 is actually 1.12...

No it is not.


That “instanceof” change looks strictly worse than Kotlin’s “smart casts” (after checking x is an instance of Y, x implicitly casts to Y as long as its value doesn’t change).

The new Java shorthand, by introducing a new variable name, also introduces some sneaky variable shadowing risks (as this blog post itself explains!)

Edit to add: maybe the difficulty is in formally specifying “smart casts”, or at least clearly documenting them? I don’t think Jetbrains has documented all the rules used by Kotlin. It doesn’t seem undoable, though.


Cached: https://web.archive.org/web/20191217093210/https://java.chri...

(Google hasn't cached it yet as of this writing)


Curios, why post this?


Because I tried to access the page a few times over a two-hour period, and it always timed out.


Will we ever get to see golang-style multiple return values/results?


Method chaining becomes complicated if you have multiple return values. In Go, you can't return error values if you want to do method chaining. Error handling then becomes even more complicated.


I would like to have the result type for this, like in Rust:

enum Result<T, E> { Ok(T), Err(E), }


I've implemented this in Kotlin with sealed classes, and it's slowly taking over within our org. You don't get a few things (like the ? sugar) but it's still really nice.

I have no idea why the Kotlin std lib has a Result type but limits it to exceptions - such a missed opportunity.


I find using Optional a better alternative in typical "result|error" scenarios.


When is Java going to fix its ugliest wart - regex backslashitis? Seriously, which other language in 2019 requires you to escape every sodding backslash in a regex?


Second that. It's the most annoying thing in Java.


Every language is becoming Rust. I love it.


off-topic: What a cool TLD!


You have got to be joking, now Christmas is a domain?


Why not? There was a lot of pressure on .com, now with all these GTLDs it's easy and cheap to find a cute name.


"Welcome to Kotlin"?


Soon Java will become the new PERL with 20 ways to do the same thing & developers will have to spend hours on Google trying to figure out what that wierd bit of syntax actually does.


It seems that most languages these days are on a path to adding as much syntax as possible. Is there no limit? The mainstream languages are already too complex for me to understand fully, let alone use effectively.

We used to joke about APL (the "beautiful diamond") and Lisp (the "ball of mud"). Lisp was big, at the time, but most of it is what we'd call the standard library today. The actual core was quite small, and everything was remarkably coherent for a system of its size. Today, many core languages are as big as all of Common Lisp.

When I see a language add new syntax for a trivial transformation, in the compiler because the language isn't extensible, using ASCII art because they've run out of symbols on the keyboard, it just looks like the worst of APL combined with the worst of Lisp.


I'm not sure what you're objecting to here. The switch enhancements, in particular, seem to me to reduce boilerplate and improve readability. If I ever go back to spending time in Java I'll certainly be using them.


Sigh, I know new language features are cool, but I highly doubt the growing dominance of Python and JS is a question primarily of language features. Python has a REPL and the outstanding tooling built on that along with an ecosystem of libraries where a default use case is the design choice. That all leads to "fast" development which what a lot of people care about. JS has the default use app deployment area: browser.

Meanwhile Java's REPL is a pretty sad imitation, and I see no movement toward trying to get back in the user app space.

I love the JVM and the language itself is good enough, but the management of Java features through the years leaves me disappointed.

* I know Android is Java and Kotlin focused but Android development is entirely different than writing a JavaSE app. Also know Kotlin compiles to JS, and I think that supports my grumpy young man persona. A hugely successful language IDE company saw it useful to build a cross compiling language on your platform.


Java's development is still mostly not in the language (although some developers focus on language changes). Most of the improvements in recent versions were to GCs, low-overhead deep profiling, and general performance -- neither Python nor JS compete well in these areas. In addition, the upcoming JDK 14 has the jpackage tool which would make it easier to deploy desktop applications, and there's a lot of investment reducing warmup time (CDS), AOT compilation that appeals to some microservices and maybe mobile/WASM apps, easy FFI and native memory access that can help with machine learning (Panama) and, yeah, the REPL. What features would you like to see?


It's a different kind of programming. Two different industries basically.

Python and JS were designed for small experiments. I would wager 90% of Python code per capita are single file scripts.

Java is for building whole systems.

The reason Java is losing traction compared to the Python/JS type languages is that the type of programs people write are different. In the 90s, the majority of programming was on big infrastructural things like word processors, control software, web browsers, etc. Now that programming has gotten so much more popular, more people (by plurality) are working on comparatively smaller, more toyish things. It happens that Python/JS is the better tool for this kind of work.

If software is to keep growing at the same pace, the new programmers will be absorbed by the Python/JS camp. Python/JS will keep rising. There is a maximum number of kernel developers or compiler developers in the world, but the amount of small toy apps that can be created is infinite.


What do you really get out of a Java or Python REPL?

If it’s the simple kind like python in bash, it’s really primitive compared to an IDE where you can inspect things. Why doesn’t a simple project suffice?


> What do you really get out of a Java or Python REPL?

For my part, a REPL helps me think about what I'm doing. There's a design process prior to writing code--sketch things out on paper, do a mind map, assemble pieces, get a general architecture. In the thick of coding, though, it's nice to be able to try out an idea or two in real time, test as you go, and feel out how the code is taking shape.

REPLs are really an invaluable tool for thinking about code in real time. For some people that may not be helpful or necessary, but it's expedient for me.


REPL-driven development is quite common in the LISP communities, and one of the main reasons I love Clojure. Stuart Halloway did a talk on this topic: https://vimeo.com/223309989


Right, but will We Assembly be a JS killer?

If I can stay in Python and target the browser without the fuss and bother of JavaScript, why would I?


WASM won't kill JavaScript because there is a whole generation of programmers that actually prefers it to Python etc. and goes out of their way to use it (nodejs).

There are also more technical reasons like WASM not being able to access DOM.


There's already a transpiler to compile python to Javascript. The question is: why would you want the hassle to add that tool to your pipeline and the added complexity of debugging your frontend code?


Nothing prevents you from compiling your Python code to JavaScript blob and run it without really bothering with JavaScript. You don't need wasm for that.


JavaScript and Python can't match performance, scalability, security, rich libraries for developing enterprise applications that comes with Java Ecosystem.


You might not, but JS is popular enough for many developers to continue using it.


Is it me or does the below sound condescending?

Trying new features is a good way to broaden your skill set, and if there is something you strongly dislike about the usability of a feature you can even provide feedback to the JDK developers.

To me it reads like: Try our experimental features because that will make you a better (rounded | paid) developer, and if you really really want you may even provide feedback.


No offense, but that's probably you. Even if I try to read that as condescending, I have a hard time doing it.

I read that as: trying new stuff in code generally makes you a better programmer. And when you test stuff that's still in an experimental phase, the language designers are probably still open to feedback from the broader public.


None taken! I'm getting allergic to corpo talk lately and it looks like I'm overreacting!




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: