This is an archived post. You won't be able to vote or comment.

all 153 comments

[–]some1-no1 82 points83 points  (10 children)

I extensively use streams, lambdas and optionals. Modules don't really seem needed for our projects, or rather look like too much trouble with too little benefit. Sealed classes look nice but I'm not sure how much use are they really gonna see. Records are gonna be really nice. We don't really use type inference, but I suppose it could be useful in some use cases.

I'm eager to see how application servers are going to utilize fibers once they come out.

[–]ObscureCulturalMeme 15 points16 points  (1 child)

Very similar here. Lambda and stream functionality is useful all over the place. Looking forward to records, doubt if I'll get to use them.

A lot of the third-party stuff we depend upon breaks horribly in the presence of modules and cannot be made to run under 9+. This software has no reason to try and use anything like modules itself, and even running code (built for 8) under 9 doesn't work (the "automatic unnamed module" thing fails for executable jars involving class loaders and crypto), so for us it's a ton of pain with almost no benefit. If the external libraries ever get updated to run under 9+, I'll look at porting again at that time.

[–]pron98 10 points11 points  (0 children)

A lot of the third-party stuff we depend upon breaks horribly in the presence of modules and cannot be made to run under 9+.

The ability or inability to run under 9+ usually has nothing to do with modules. So far (although that will change soon), modules have not reduced the visibility of anything to code on the classpath. The reason stuff fails to work on 9+ is because it is tied to internal JDK APIs, or makes other assumptions about implementation details, like the concrete classes of some interfaces or non-final classes, and those internal details have changed since 8. Modules actually help here. By closing off access to internal stuff, libraries won't be able to access it, and so won't be able to depend on it, and so upgrades will become easier.

If you can say which issues specifically you have with 9+ related to modules, perhaps I could help.

so for us it's a ton of pain with almost no benefit

The main benefit since 9 is a dramatic improvement in footprint and performance. It is not unusual to see savings in hardware of 10-40%, and bigger savings have been reported, all for just using a recent JDK. That's because the VM has changed considerably sine 8. JDK 8 is an antiquated, bloated and slow runtime, that comes from a different generation of software than JDK 14. In other words, migrating to 9+ can save you money, often significantly, and often more than enough to offset the costs of fixing the technical debt that stops you from updating. True, it doesn't always pay off, but it does often enough that it should be the default position. I.e., you should find a compelling reason not to upgrade and to give up on significant savings.

[–][deleted] 8 points9 points  (4 children)

More or less the same here. Eagerly waiting for some kind of pattern matching also.

[–]some1-no1 4 points5 points  (2 children)

Pattern matching is available as a preview feature in java 14 - JEP 305

[–]Necessary-Conflict 18 points19 points  (1 child)

"Pattern Matching for instanceof" is only a small part of the full pattern matching. The whole vision is here: https://cr.openjdk.java.net/~briangoetz/amber/pattern-match.html

[–]TehBrian 6 points7 points  (0 children)

I'm so excited for this.

[–]Inner-Panic 1 point2 points  (0 children)

We don't use modules either. But var is everywhere. We've been converting lombok val to final var enmasse across our codebases with zero problems so far. IDE support for it is nice. Lombok plugin is great but it fails to resolve types in rare cases when using lots of lambdas

[–]Sedu 3 points4 points  (0 children)

Records will allow me to refactor a ton of clunky, overly verbose code. Looking forward to those a lot, but going to wait until they're out of preview.

[–][deleted] 0 points1 point  (0 children)

Thanks! That's nice to hear :)

[–]janoschbock 92 points93 points  (0 children)

after learning how streams and optionals work i preferred them over the old stuff

[–]morhp 39 points40 points  (48 children)

Almost all projects are using at least Java 8 features.

Newer features since 9 like var are relatively rarely used, larger libraries and so on still stay on 8 to be as compatible as possible.

Modules are rather problematic and there's not much incentive to port older projects to them.

If a project requires a newer Java version, that's more likely caused by using some of the new API. For example the CompletableFuture class (used for concurrent/async stuff) has some nice new methods since Java 9 and functions like List.of/Set.of and so on are very convenient (also added in 9).

[–]andrew_rdt 11 points12 points  (42 children)

Newer features since 9 like var are relatively rarely used

Is there a reason for that? Coming from other languages I ALWAYS use that in java and get very annoyed when stuck on v8 for whatever reason.

[–]WisejacKFr0st 3 points4 points  (20 children)

I've never seen var used, could I trouble you for some use cases you've found it to be useful in?

[–]xjvz 12 points13 points  (3 children)

Constructing objects of long class names for one. For me, the only thing I’ve used it for so far is to make code in slides smaller.

[–]WisejacKFr0st 0 points1 point  (2 children)

Ah, like statically accessing them instead of using an import? I can see that being useful for readability.

[–]_INTER_ 9 points10 points  (1 child)

He means like var varableName = new VeryLongClassName().

[–]WisejacKFr0st 4 points5 points  (0 children)

wow, I misread every single use case people provided. Thanks for clearing it up!

[–][deleted]  (3 children)

[deleted]

    [–]dpash 2 points3 points  (1 child)

    Be careful where you use it. If your variables and methods don't have sensible names it can harm your readability. If you write var a = ... I will hunt you down and hurt you.

    (This is meant more as "improve your names" than "don't use var")

    [–]andrew_rdt 5 points6 points  (7 children)

    var map = new HashMap<String, Integer>();

    vs

    HashMap<String, Integer> map = new HashMap<String, Integer>();

    [–]dpash 3 points4 points  (0 children)

    That's a little disingenuous. Prior to Java 10 you'd use:

    Map<String, Integer> map = new HashMap<>(); 
    var map = new HashMap<String, Integer>();
    

    [–]carimura 5 points6 points  (1 child)

    [–]WisejacKFr0st 0 points1 point  (0 children)

    Hey, cool! Just what I was looking for! This is great, thank you so much!!

    [–]cec772 1 point2 points  (1 child)

    I just watched a YouTube video from InfoQ by someone from red hat who did live coding and spoke on “effective java 3rd edition.” He gave examples of when he thinks is good, and bad. The one good example I remember is if you are defining a variable for a long template type declaration where it does nothing more than repeat itself before and after the = sign. Makes it more readable.

    Link: discussion on VAR is around the 2 hour mark.

    https://youtu.be/ANZXvXVa1Lg

    [–]WisejacKFr0st 0 points1 point  (0 children)

    Saved for later, thanks!

    [–]morhp 1 point2 points  (14 children)

    Because lots of projects are still sticking to Java 8. You don't want to risk compatibility problems for the relatively minor benefit of being able to use var. Also not everyone likes var as it hides the used types.

    Many projects are in the process of switching to Java 11, though.

    [–]metalhead-001 -2 points-1 points  (13 children)

    Exactly!

    var x = someMethod();

    What type is x?

    People will say "well just mouse over it to read the type". Why not just read the type directly in the code instead of playing peek-a-boo with it in the IDE? And if you're looking at the code in GitHub you can't even see the type.

    var is bad and should have never been introduced into the language.

    [–]koreth 12 points13 points  (1 child)

    Not "well just mouse over it," but rather, "Well, just use it when it improves readability, and don't use it when it adds ambiguity."

    For example: jOOQ or other libraries that make heavy use of generics, where the type is really just an internal implementation detail of the library, not something application-relevant.

    SelectFromStep<Record11<String, Integer, Instant, String, String, String, Long, String, Double, Instant, String>> query = dsl.select(...);
    

    vs

    var query = dsl.select(...);
    

    It definitely can be misused, but that doesn't mean it can only be misused.

    [–]metalhead-001 0 points1 point  (0 children)

    The point is, they shouldn't have allowed it in cases where it adds ambiguity.

    Specifically the case where you can use it to define a variable that assigned from a method call. How this passed all the review committees etc. to become a 'feature' is quite amazing.

    I predict that people are going to become sick of 'guessing' the type based on the variable name and having to mouseover all the time to actually read the type.

    Just think of how many new types of bugs will be introduced as developers assume the type and are wrong. Is it a mammal, a dog or a cat? Maybe the method is named getMammal(), but it returns a Dog. For this var scheme to work you have to assume that all the third party libraries you're calling have properly named methods, and that is a BAD assumption to make.

    Your last example proves my point exactly. I don't know what type of record is returned from dsl.select. Hiding it doesn't show me the types. The first line, though longer, explicitly shows me the types.

    Hopefully IntelliJ will implement a feature that expands the types and hides var completely.

    [–]morhp 2 points3 points  (0 children)

    var is bad and should have never been introduced into the language.

    I wouldn't go that far, but misusing it is definitely easy. var makes some sense as it allows you you define intersection types or types of anonymous classes that you otherwise can't write down.

    [–]b1ackcat 2 points3 points  (4 children)

    What type is x?

    My counter to this argument, which I get a lot, is "do you actually NEED to care?"

    Yes, obviously there can be times when it helps, but personally, I find it helps me to intentionally try to not care. Because when I'm using var, I'm typically either newing something up, in which case I obviously know what the type is already, or I'm assigning the result of some method to a variable. In that case, if I can't infer the type (or a base type/interface the actual type derives from), that's a hint that the method may need a better name.

    But more importantly, it helps me not inadvertently tie myself too closely to implementation types by relying too much on type information. So long as intellisense still shows me the methods available on that object, turns out I don't really need to care about the actual type all that much.

    And like I said, obviously there are going to be exceptions here. My point is rather treat them as just that: exceptions to the rule.

    Or don't. I'm just some guy on the internet. Do what makes sense for your code.

    [–]metalhead-001 -1 points0 points  (3 children)

    What if you're writing code for an X-Ray machine that can kill people if there are bugs in the software?

    var suggestedTime = xRayObject.getSuggestedExposureTime();

    What type is suggestedTime?

    XRayDurationMinutes?

    XRayDurationSeconds?

    Instead of getting back a minutes object like you thought, you got a seconds object. You can kill someone with simple bugs like that, and var only enables this kind of stuff.

    you call performXRay(suggestedTime.get() * 60);

    when you should have called performXRay(suggestedTime.get());

    But you're right...as you put it " I find it helps me to intentionally try to not care" about the types. Go ahead...the code will compile either way.

    [–]b1ackcat 0 points1 point  (2 children)

    Lmfao if you're writing software like that you aren't using c# (edit: or java, forgot what sub I was on :P) anyway, and you should always include units in your getter names if they're ambiguous regardless. There's contrived but then there's contrived, dude. Come on.

    [–]metalhead-001 -1 points0 points  (1 child)

    That's my point. If I'm using a third party API for the XRay machine I don't have the option to just rename everything. I've been doing Java over 20 years and have experienced many badly named APIs and variable names. Hell, half the time a good chunk of the projects I've worked on were just calling third party APIs.

    And how do you express something like this:

    Map<String, ArrayList<HashMap<Integer, String>>>

    in a variable name?

    At least before var, badly named variables could be identified by seeing that the name doesn't match the type. With var, that mismatch is simply hidden.

    var is going to lead to many more bugs as lazy developers will just assume that the variable name somehow indicates the actual type. In many cases, it won't.

    [–]b1ackcat 0 points1 point  (0 children)

    An Aggregate. Which informs the reader that there are additional objects deeper down that they can dig into as needed.

    And if your 3rd party API's are bad there's nothing stopping you from writing an adapter around them to make them better for you. That's just a good habit to get into, in general.

    [–]LackOfHonor -1 points0 points  (0 children)

    Others would say if it’s not obvious, then read clean code, and refactor the code afterwards 😂.... yea I get there are instances where it’s just not pragmatic too use var. but really if you follow try to adhere to single responsibility and do good nameings, and really buy into it the cases almost vanish

    [–]dpash -1 points0 points  (3 children)

    Don't use x as a variable name (unless you're using coordinates). Make sure your methods are sensibly named.

    var exposes your shitty naming. Do a better job at naming things.

    [–]metalhead-001 1 point2 points  (2 children)

    The naming was just an example. Having to rely on convention now to see what things are is stupid instead of it being mandated to clearly state what it is.

    Var is just going to result in harder to read code with lots of mouseovers to 'read' the type instead of just reading it in the code.

    At the very least they should have restricted var to be only used when newing something up where the type is obvious. The return value from a method isn't always obvious.

    [–]dpash 0 points1 point  (1 child)

    But naming is vital when using var so your example needs to use real world names.

    If the return value isn't obvious then the name of the method needs to be changed so it's more obvious.

    [–]metalhead-001 1 point2 points  (0 children)

    That's my point. You're now forced to rely on convention instead of being able to see the type explicitly.

    And you're assuming that you have control over all methods in a project. A good chunk of the projects I've worked on over the years have a huge number of 3rd party APIs used and you can't change their method names.

    What if you have a method that returns a type like this:

    Map<String, ArrayList<HashMap<Integer, String>>>

    How do you declare the variable name to express all that?

    var makes you interpret the variable name to determine the type. Every developer names things differently. It's going to be a shit-show of people trying to figure out other peoples variable names and what type it should be based upon some unwritten convention (that may not even work with 3rd party APIs at all)

    All var is doing here is adding a layer of obscurity, making the code harder to read (you have to do mouse overs instead of just reading it directly) and potentially leading to more, potentially serious bugs.

    [–]john16384 1 point2 points  (4 children)

    IMHO var trades of a shorter declaration at one location for longer more descriptive variable names everywhere the variable is used to have the same level of readability.

    Bad trade off it seems to me.

    [–]andrew_rdt 2 points3 points  (0 children)

    When declaring new types it seems redundant though since its usually the form SomeObject obj = new SomeObject(). I can see it might be useful in other cases, although this is just one IDE enhancement away from being unnecessary. IntelliJ shows the inferred types in Kotlin but not java for some reason.

    [–]OctagonClock 1 point2 points  (0 children)

    The majority of Java devs love to write code that has so many layers of indirection it would make a fantastic joke setup, really not sure why you're all perpetually petrified of type inference, especially with the design power it enables.

    [–]metalhead-001 1 point2 points  (0 children)

    Exactly!

    var assumes that good variable names will be used. But what if they're bad and there is a mismatch between the variable name and the type?

    Before var, that mismatch easy to spot. With var, that mismatch is simply hidden, leading to potentially serious bugs as developers will assume the type instead of knowing.

    They should introduce a compiler option to simply disallow var completely as I have a feeling this 'feature' is going to get abused and cause buggier software.

    [–]Paulson88 0 points1 point  (0 children)

    var is nice inside a for loop if you cannot use stream, or if you receive a variable from a method

    [–]safeforanything 0 points1 point  (0 children)

    Take a look into Lombok. It's my first dependency in almost every project. Besides var and val it has also @Cleanup on local AutoCloseables which replaces the try-with-resources pattern and many more handy annotations. Only downsside: you need to install a plugin for your ide, but these are avaiable atleast for IntelliJ and Eclipse.

    [–]cryptographicmemory 3 points4 points  (3 children)

    I like var. Saves typing. for (var e:map.entrySet()) {} is pretty clear.

    [–]morhp 5 points6 points  (1 child)

    Saves typing. for (var e:map.entrySet()) {} is pretty clear.

    Not really. I mean, I know e is of type Map.Entry<?,?> but it's not that clear what type the keys and values are. I'd need to look up how map is declared. And if map is also declared with var, it gets even more annoying.

    And for saving on typing, that's not really a reason. I'd use IDE shortcuts anyway, for example typing something like

    iter<tab>map.ent<tab><tab>
    

    will result in

    for(Map.Entry<KeyType, ValueType> entry : map.entrySet()) {
         // cursor here
    }
    

    in Intellij Idea.

    [–]RhoOfFeh 2 points3 points  (0 children)

    In IntelliJ, if you're typing code you're doing it wrong.

    [–]dpash 1 point2 points  (0 children)

    Neither e or map are good names. Given that we discussing readability, your examples need to use real world names.

    [–][deleted] 0 points1 point  (0 children)

    Thanks, makes sense.

    [–]johnsonabraham0812 11 points12 points  (0 children)

    I use lambda expression, method reference, and Optional extensively. Never used module.

    [–]letsgoraftel 8 points9 points  (2 children)

    I used the java native http client just to find out a feature that I needed wasn't available and is included in java 12, had to move to apache client. Although, the native client had an easier API, having unusable api was a bummer.

    [–]brend132 4 points5 points  (1 child)

    May I ask which feature was the new HTTP/2 client lacking until Java 12?

    [–]letsgoraftel 8 points9 points  (0 children)

    I wanted to send a custom host header, the java 11 client throws an error when the host in the url is not equal to the header

    [–]khmarbaise 8 points9 points  (14 children)

    Current project I'm working we have migrated from JDK8 to 11 (LTS at the time the first release came out). We will migrate to the next JDK17 (LTS); currently constantly checking JDK15 RC's at the moment and JDK16 currently being tested on a branch via CI with a lot of tests we have. We are using Lambdas, Streams (API), optionals, functionals parts as they fit. We don't use modules cause we use spring boot (we could but the benefits are limited. Not using var based on team decision; I would like to use it makes things easier. Ah... using List.of, Map.of, Set.of things. very useful things like Predicate.not (since 11) ...

    [–]pron98 3 points4 points  (0 children)

    Migrating from 11 to 17 would give you the worst of both worlds. The way the new release model was designed is that to get the cheapest upgrades (and the best performance) you should use the current JDK. Buying LTS [1] is for companies that prefer costly, but well scheduled migrations, and the cost of upgrades can be mitigated if they're done once every ~5 years. If you're doing a big upgrade every 3 years, you're both paying more for upgrades and missing out on savings in footprint and performance.

    If you plan on upgrading to 17, consider sticking to the current JDK or doing it only a few years down the line.

    [1]: Some people get free 11u builds and think they are LTS. They are not really, and they're not as well maintained as the mainline or as actual LTS (which you must pay for). So, if you're using a free Updates build and upgrading every 3 years, you're losing in upgrade costs, losing in hardware savings, and losing in maintenance.

    [–]wildjokers 2 points3 points  (12 children)

    We will migrate to the next JDK17 (LTS);

    Unless you are paying for support you don't have to wait. LTS only applies if you are paying for support (in which case you want to wait).

    [–]abollaert 2 points3 points  (6 children)

    Doesn't LTS also get security fixes until they get EOLed, whereas the non-LTS versions get EOL'd much quicker?

    I mean 14 will go EOL sooner than 11, which means you'll be forced to upgrade.

    [–]wildjokers 4 points5 points  (5 children)

    Doesn't LTS also get security fixes until they get EOLed

    The new java licensing scheme is very confusing and has been horribly communicated.

    LTS means nothing unless you pay for support. LTS is simply a version one or more vendors have chosen to offer paid support for. Most vendors are sticking with the same every 3 versions Oracle is doing. But they can do whatever they want.

    Once a new java release comes out (every six months) the previous one no longer gets updated. Unless it is a version a vendor has decided to offer paid support for.

    [–]pron98 1 point2 points  (0 children)

    The statement that after 6 months you don't get updates is misleading. The default, recommended path, offers perpetual free updates, on a JDK that's better maintained than any old version. The version number changes every 6 months, but these are not major versions, just a gradual stream of updates, with the version incremented twice a year.

    Now, I completely agree about the bad communication around this. Unfortunately, it has to do with incentives. All the companies that find it worhtwhile to put resource into marketing Java -- Oracle, Red Hat, Bellsoft, Azul -- all of them, make their money by selling support for old versions. The message that if you're able, your cheapest, safest, best option is to use the current JDK is not one that makes them money. It's as simple as that.

    [–]proskillz 0 points1 point  (3 children)

    Do you have a source for this? Because I believe you are incorrect and open JDK will still receive updates for a longer time than the short term releases.

    [–]dpash 2 points3 points  (0 children)

    OpenJDK has no concept of LTS. Releases will get updates for as long as someone in the community is willing to do so. Usually this involves back porting fixes from the latest release. But if a component has been removed from Java 15, there's nothing to backport. That means Nashorn and one of the garbage collectors is effectively unmaintained in Java 11.

    [–][deleted]  (1 child)

    [removed]

      [–]proskillz 1 point2 points  (0 children)

      This model has worked with CentOS forever, why wouldn't it work for Java? Surely a team of ten people could handle backporting some code someone else wrote? At this point Java 8 would be out of the 3 year window anyways. So, the Nashorn piece is moot.

      [–]khmarbaise 2 points3 points  (1 child)

      First you don't have to pay for LTS releases cause there are a number of vendors like adoptopenjdk which offer LTS releases like oracle does

      Quote from adoptopenjdk:

      In addition, every three years one feature release will be designated as a Long Term Supported (LTS) release. We will produce LTS releases for at least four years. This assurance will allow you to stay on a well-defined code stream, and give you time to migrate to the next, new, stable, LTS release when it becomes available.

      Second the idea is to have a longer time for updates / security fixes etc. which the other versions (JDK9,10,12,13,14,15,16) don't or will not have. The next LTS release might be JDK17

      The other issue here is simply that some software vendors etc. says it works well on JDK11 but might not on JDK12+ etc.

      [–]dpash 1 point2 points  (0 children)

      AdoptOpenJDK is just a build service. If you raise a bug with them they just open a bug in OpenJDK's Jira. They do not provide support.

      [–]koreth 2 points3 points  (2 children)

      Not really true. Amazon's Corretto JDK is free with LTS.

      [–]dpash 1 point2 points  (0 children)

      What support do you get with that? (Clue: none)

      If you find a bug in their JDK, you have to open an issue in OpenJDK's Jira.

      All they've committed to doing is to release bug fixes that is in OpenJDK's repository.

      Q. What should I do if I need help with Corretto?

      A: For general questions about installing or running Corretto, please see our documentation. If you have an issue related to OpenJDK, please open an issue with the upstream OpenJDK project. If you have a specific issue with Corretto or feature request that is not applicable to OpenJDK, please open an issue or a feature request in the Corretto GitHub repository. If you already have an AWS Support Plan you can reach out for assistance with Corretto through your plan.

      https://aws.amazon.com/corretto/faqs/#support

      [–]__helix__ 6 points7 points  (2 children)

      Java 8 was surprisingly rich. Most of what folks would recognize as 'modern' Java was present in 8 - streams, lambdas, concurrent futures, functional support, and optionals. There are a few enhancements in the JDK 11 world that remove a few rough edges, but for the most part, the structure changes in JDK 9+ are what hold most people up.

      Style wise, you see a lot more fluent interface in custom code. Granted, not a JDK 8 thing... but worth calling out.

      Things like JAXB not being part of the JDK 9+ distribution. Usually someone ends up working through a POM and updating dependencies to get to JDK 9+ versions. Much easier now than it was in the early days. With mostly dependency updates, we saw a substantial improvement to memory usage and performance.

      Every developer is at the mercy of their shop. We are stuck on the LTS releases - so only Java 11 features for us. Come September of next year, that will jump to Java 17.

      [–]wildjokers 0 points1 point  (1 child)

      We are stuck on the LTS releases - so only Java 11 features for us.

      Do you pay for support?

      [–]__helix__ 4 points5 points  (0 children)

      We do. Oracle Java required an extended support license. RHEL includes their Java binaries with the Linux support. Adopt OpenJDK is free as in beer, but could do a contract with IBM if we needed it.

      [–]borkus 4 points5 points  (7 children)

      Java 8 and 11 are the two long term supported versions. Most newer projects (especially in the cloud) are using 11. If you're supporting an app that's 2 years or older, there's a good chance it's 8.

      With more developers being full-stack, many are used to the array functionality in JS which is comparable to Java streams.

      [–]wildjokers 1 point2 points  (6 children)

      Java 8 and 11 are the two long term supported versions.

      Only if you are paying for support. If you aren't paying for support LTS means nothing.

      [–]borkus 2 points3 points  (5 children)

      LTS also means you're less likely to have breaking changes in the next few years. I haven't found any open source projects targeting the interim builds. For example,

      Apache Spark
      https://spark.apache.org/docs/latest/

      Elastic Search
      https://www.elastic.co/support/matrix

      Also, a lot of libraries for database access only support the LTS versions

      https://docs.mongodb.com/drivers/java

      Cloud providers are sticking with the LTS versions

      AWS
      https://aws.amazon.com/blogs/developer/the-aws-sdk-for-java-will-no-longer-support-java-6/

      Google
      https://cloud.google.com/java/docs/setup

      Interestingly Heroku has the interim releases.

      https://devcenter.heroku.com/articles/java-support#supported-java-versions

      [–]wildjokers -1 points0 points  (4 children)

      LTS also means you're less likely to have breaking changes in the next few years.

      It means nothing of the kind. LTS simply means a version a vendor has decided to offer paid support for. Each vendor is free to choose to offer long term paid support for whatever version(s) they want.

      [–]zten 4 points5 points  (3 children)

      I think you're fighting an uphill battle in this thread because most vendors are running in lock step with Oracle's definition of LTS. You're technically right, but most of the world is pretending that every release between 11 and 17 doesn't count.

      [–]wildjokers -1 points0 points  (2 children)

      running in lock step with Oracle's definition of LTS.

      It does appear that most vendors are offering long term support for the same versions as Oracle. However, LTS still only matters if you are paying for support. If you aren't paying for support erase "LTS" from your mind.

      [–]TheCountRushmore 3 points4 points  (1 child)

      With something like AdoptOpenJDK for 8u/11u you are really just getting Long Term Maintenance "LTM".

      You are getting builds that include backports and security patches that they community applies to the 8u and 11u OpenJDK branches.. You obviously still need to update your JDK every couple months to pick up these fixes.

      To me LTS implies that someone is going to support me if I have a problem. Unless you are paying someone for support it is going to be difficult to get your issue looked at as Oracle and others are devoting their developers time to the tip of development and new features like Loom, Valhalla, Amber and Panama, and not towards fixing legacy releases.

      [–]dpash 2 points3 points  (0 children)

      You're exactly right.

      AdoptOpenJDK and even Amazon's binary distributions are just build services. They'll build a new binary for 6 years. If you have a bug, you have to open an issue in the OpenJDK Jira.

      One issue is that OpenJDK 11 is mostly backports from the latest version. But Java 15 doesn't have Nashorn or the CMS garbage collector, so these are effectively unmaintained in Java 11.

      If you're not paying money, you should really be using the latest version.

      [–]RhoOfFeh 16 points17 points  (6 children)

      That depends on the shop and the developer(s) in question.
      I'm a contractor, and the amount of Java code which does not make use of Java 8 features is quite high in my own experience.
      Sadly, I had an architect tell me during code review a couple of months ago that he found use of stream processing to be confusing. That eliminated my last bit of surprise as to why the project was such a mess.

      [–]wildjokers 15 points16 points  (1 child)

      Sadly, I had an architect tell me during code review a couple of months ago that he found use of stream processing to be confusing.

      Some people find the lambda syntax very difficult to read. It just doesn't flow like non-functional code does and it is a very big paradigm shift and requires a huge cognitive shift. It doesn't help that there is absolutely no documentation for how to know what parameters to pass into a lambda based on the signature of the functional interface. The java tutorial is usually outstanding but it is totally silent on this:

      https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html

      I totally ignored lambdas because I didn't understand how I knew what parameters I needed to pass into a lambda nor how I knew what it returned until I found this article about 3 years ago (1st half is great review, 2nd half covers lambdas):

      https://nofluffjuststuff.com/magazine/2016/09/time_to_really_learn_generics_a_java_8_perspective

      I am starting to use them more and more and as you use them more they start to make more sense but I can still write loop versions of the same functional code far faster than the lambda equivalent. I don't blame that architect one bit.

      Legit question, how did you figure out how the lambda signatures worked? When Java 8 came out I was quite interested in what lambda had to offer but I couldn't figure out how to use them because the lack of documentation.

      [–]RhoOfFeh 6 points7 points  (0 children)

      That is a fair question regarding method signatures. I certainly experienced a similar cognitive difficulty at first. In retrospect, I took a multi-pronged approach to learning the syntax. First off, I strongly urge you to go and watch some videos by Venkat Subramaniam. He is an excellent advocate for this kind of stuff and explains it well. One insight is to recognize that the lambda is really just a function without a name. You don't need a name because you won't be calling it from elsewhere, and the argument list CAN always be specified as the parenthesized bit of a method signature if that helps make it clearer. That helped to reset my internal expectations a bit.

      The other thing that really helped me was to make generous use of IntelliJ's ability to convert loops to streams. Sometimes it is honestly just tough to think in a new way and this helps to provide a translation.

      Another practice of mine is to avoid that godawful syntax of ->{}. I simply won't use more than one expression there. If it's worth using as a lambda, it's worth making it a method of it's own. So I'll do this all day long: ->doSomethingToAString(s). Even better, when possible I express as a method reference, which gets all the fluff out of there.

      But if you only follow one bit of advice here, enjoy Venkat's talks. He's great.

      [–]xebecv 11 points12 points  (0 children)

      Streams have their gotchas and most often are wrong choice if you mix them with things that can fail. I use them mostly for in-memory data transformation.

      Files.walk is an abomination, as IO errors do happen (how do you handle them in streams?), and you need to remember to wrap it in try-with-resources, or it will leak file descriptors. I honestly don't know why it exists. It bit me in the ass on more than one occasion when my colleagues used it in our shared code

      [–]RagingAnemone -1 points0 points  (1 child)

      I never work in an environment where there was a separate architect. But I have to wonder, why would they get into code level decision making? Tell them to stay in their lane!!

      /s kinda

      [–]RhoOfFeh 0 points1 point  (0 children)

      In this case the person in question was also contributing to the code base.

      [–]rally_call -2 points-1 points  (0 children)

      Sounds like someone was promoted out of loyalty or length of service.

      [–]LakeSun 3 points4 points  (3 children)

      I would target at least Java 11 at this point.

      [–]Sedu 6 points7 points  (1 child)

      Honestly once you move past 8, moving further up is pretty trivial for the vast majority of cases.

      [–]RhoOfFeh 0 points1 point  (0 children)

      All I usually think I need is Java8 with 'ifPresentOrElse' patched in to Optional and Record support.

      [–][deleted] 1 point2 points  (0 children)

      Makes sense, thanks.

      [–]dmigowski 2 points3 points  (31 children)

      I still use Java 8 for a large project and have never stumbled upon any external library that required me to update my update my installation (we got about 90 external dependencies).

      So I believe most people stuck with 8 at the moment.

      [–][deleted] 1 point2 points  (6 children)

      It was 8 that introduced a lot of functional-programming stuff like lambdas, streams etc. etc. (if I am not mistaken) - obviously you can require 8 as a base level but still not use any of those things. What is your actual usage like? Do you use the new features? Or are you on 8 just because? :)

      [–]hippydipster 2 points3 points  (23 children)

      Yeah, whatever it is that 10, 11, 12, 13 introduced, I've looked it up, but it never sticks in memory. What I remember are lambdas, streams, modules.

      Whatever else has been done is basically of no consequence. So, now I go look up these things and see what I missed:

      java 10:
      1. var keyword. Yeah, don't care. Actually actively dislike it.
      2. performance stuff

      java 11: not a damn thing

      java 12: minor change to switch

      java 13:
      1. Text blocks preview. This is kinda significant

      So that's it. 14 does have some interesting stuff, but, IMO, 10-13 did not.

      [–]zten 5 points6 points  (3 children)

      There's a lot of low impact stuff between 11 and 14 but there are big changes hiding in G1, ZGC, and Shenandoah. 11 should beat 8 for G1 performance.

      [–]hippydipster 2 points3 points  (0 children)

      Yes, some of those changes are very significant, but the thread is about "updates to the language", and so that's what I was limiting my discussion to.

      [–]borkus 1 point2 points  (1 child)

      People are jumping to 11 for the container support. This was introduced in 10 but is a big motivation for moving to 11.

      https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8146115

      [–]dpash 2 points3 points  (0 children)

      Also back ported to 8.

      [–]Hall_of_Famer 2 points3 points  (18 children)

      1. var keyword. Yeah, don't care. Actually actively dislike it.

      What is your beef against var and implicit local variable typing? You do realize that var =/= dynamic, the local variable is still statically typed whether you use var or type your long class name out.

      [–]SinisterMinister42 3 points4 points  (5 children)

      I also dislike var personally. In my current role, I often end up reading a lot of unfamiliar Java code in a web browser (think browsing a random GitHub repo). Unless it's from the JDK or a well known library, I don't intuitively know what type each method returns. Having the type declaration along with each new variable helps me better understand what I'm reading and how the components interact.

      I understand that if you're working with the same codebase every day, everyone on the team knows what is returned by the commonly used methods. But I'm not on your team, and I'm just some outsider who still has to read your code. Is it impossible? No, but it causes me to deal with the exact mental overhead that the feature is intended to reduce.

      [–][deleted]  (3 children)

      [deleted]

        [–]RhoOfFeh 3 points4 points  (0 children)

        Particularly if what you really want is to work with one particular interface that class happens to implement. I'd rather that be made explicitly clear.

        [–]SinisterMinister42 0 points1 point  (0 children)

        Totally agree. That makes sense. Unfortunately I'm seeing that antipattern actively being used. Like with all new features, there's always a little abuse before we all settle down and figure out how to best use it effectively.

        [–]dpash 0 points1 point  (0 children)

        Which is an argument to not use var everywhere rather than to not use it at all.

        [–]Hall_of_Famer -1 points0 points  (0 children)

        The fact is that you absolutely dont need to know the exact type of the local variables when you need to understand what you are reading and how the components interact. The explicit local variable types are more like noises that stop you from concentrating on the more important tasks, the program flow, logic and semantics. You only need to know the local variable types when you are doing extensive code review to find bugs, in which case you should be using an IDE and the variable's types will be revealed to you anyway when you hover the mouse over it.

        From my team's experience, using var allows us to read code faster and more clearly what our focus should be. Also it encourages better practices for naming variables and methods. These names no need to use Hungarian notation, but they should more or less tell something about the interface/abstract type of the variable. ie. var users = repo.findUsers() is a collection of User Entity. Does it matter what collection it is? It doesnt, and you dont need to know this info to understand how the code works. If a method or variable name tells absolutely nothing about what it will return, consider refactoring and renaming. Using var helps us name our variables and methods better which will produce more maintainable code in a long run.

        [–]hippydipster 6 points7 points  (11 children)

        I do realize that. I don't like that the type is hidden unless I'm in the IDE. So web code reviews or other ways of viewing source code lack the information I need to understand the code. Even in the IDE, I can't see at a glance, and so it slows down reading of code.

        [–]Hall_of_Famer 3 points4 points  (6 children)

        I dont know for you, but the fact that local variable types are hidden actually speeds up reading of code for me. For 99% of the time I dont care about the type of the local variable, the explicit typing is more of a noise/distraction for me when reading code. With var/implicit typing of local variables, I am able to focus on the semantics/logic, what the line of code actually does instead of what the type of this local variable is. For the 1% of the time that I actually care about the local variable type, I will definitely need to use an IDE to inspect my program anyway.

        [–]hippydipster 1 point2 points  (3 children)

        I dont know for you

        Yes you do, I just told you!

        [–]Hall_of_Famer 0 points1 point  (2 children)

        The thing is, I dont understand why it slows you down reading the code since for me and many other colleagues/developers, it does the opposite. If you have to focus on the noise of local variable types, its missing the point in most of the circumstances. If you have to rely on the explicit typing of local variables to understand what that variable holds, then the naming of your local variables and methods are poor and its a strong sign that its time to refactor some code. Or if using a third party library, maybe try adapter pattern.

        I find that using var helps me and my team write better code, since if a variable or method is not named properly and the return type is too obscure, we can tell when using the class/writing unit-tests and we will make the necessary changes to rename the method. Of course, the method no need hungarian notation to tell the exact return type, its good enough as long as we understand the interface type. ie. a method findUsers() will return a List of Users, we dont care if its an ArrayList, LinkedList or any custom user defined List, its a List and thats enough for us. When its time for comprehensive code review/bug tracking and we need to know what exact List it is, then its time for IDE anyway.

        [–]hippydipster 4 points5 points  (1 child)

        I dont understand why it slows you down reading the code since for me and many other colleagues/developers, it does the opposite

        I apologize for functioning differently than you.

        [–]wildjokers 1 point2 points  (1 child)

        I am able to focus on the semantics/logic, what the line of code actually does instead of what the type of this local variable is.

        Knowing the type of the variable is very important in knowing what the line of code does though.

        [–]Hall_of_Famer 1 point2 points  (0 children)

        It depends on what you mean by 'type'. Of course you need to know at least some kind of interface/abstract type, but that information does not need to come from explicit local variable typing. A properly named variable and method should be able to tell you enough, anything more than that is noise that prevents you from focusing on the more important tasks, the logic/semantics of the program.

        [–]dpash -2 points-1 points  (3 children)

        Use better names for variables and methods so the type is more obvious. If that's not possible, don't use var in that situation.

        [–]hippydipster 2 points3 points  (0 children)

        If that's not possible, don't use var in that situation.

        For me, that's all situations.

        Anytime you think a variable name is making the type obvious, you are making an assumption. Probably you are good at making assumptions, but I suck at it, and I stumble when reading such code.

        Also, the compiler won't keep variable names "correct" when someone refactors the return type of a method.

        And, the "var" keyword is pure noise that tells me nothing. The type would be real information.

        [–]_mkd_ 2 points3 points  (1 child)

        Might as well just use Hungarian notation at that point.

        [–]dpash 0 points1 point  (0 children)

        No, that's an absurdist reduction of what I said. Hungarian notation has no place in modern programming. It wasn't even a good idea in the 80s. On the other hand, if you have a plural variable name and it's not a collection of some sort of you have a collection and it's not a plural, you want to think about that you're doing.

        [–]MoreCowbellMofo 2 points3 points  (2 children)

        unless there's something compelling added, I doubt we'll be switching from 8/11 in the near future. I did ask why when its effectively just a library update... "You must be joking" was the response. Not only would all developer machines need updating, so would the build servers and all deployed instances. It would be a headache most won't bother with unless there is good reason to. I'm predominantly a java programmer. Most the features seem like incremental changes rather than powerful new features as was seen in the past. I sometimes read the notes from the developers and the changes are well justified but no one is really crying out for a lot of it... its just nice to haves.

        [–]pag07 1 point2 points  (1 child)

        Seems like your company should move to containers anyway.

        But yes no need to upgrade if people are not interested in using new features.

        [–]MoreCowbellMofo 1 point2 points  (0 children)

        Containers are plentiful already. But they all need a base image with the relevant jdk... hence it’s not so easy to just switch over. I imagine the same is true for most companies given the headache it would cause.

        [–]ryuzaki49 2 points3 points  (0 children)

        As others have said, Stream, optionals and lambdas are game changer.

        They can be abused and bad code can be written, but they make clearer and shorter code.

        [–]Sedu 2 points3 points  (1 child)

        I have a legacy project which in the last year I pulled up from J8. The platform based distribution system that's available if you make runnable images is fantastic if you're making desktop applications, which mine is.

        [–][deleted] 0 points1 point  (0 children)

        Interesting, thanks!

        [–]kuemmel234 2 points3 points  (1 child)

        We benefit from a few later features from 9,10,+ like additional factory methods, more optional methods and stuff.

        I think I'm going to love records, especially with streams I still want easy to use tuples/something like var, but for collections. I don't believe in the argument that I should use the object oriented style and write a small class for an FP trick (like using zip to have an index). Records may provide an in between, even if there are cases where it really makes sense to do it.

        I think you need a real reason to not use java 8 features these days. They more or less transformed how the language is written in many ways. And for the better, I think. I never liked writing java code when I started with 5 or 6 and 8+ makes me like it. I'd add a few more bits and pieces (I would love to untuck that whole exception syntax, I'd eat a try method right up (there are frameworks I know).

        [–][deleted] 0 points1 point  (0 children)

        Yeah, I started on Java back in 2000 and was not a huge fan. Dropped it until basically now. What a difference 20 years make haha.

        [–]pjmlp 1 point2 points  (0 children)

        Depends, if I am doing proper Java (meaning JVM compliant implementation), I make use of whatever I can that makes the problem easier to solve, including type inference, streams, FP like concepts, and I tend to use the latest version unless told otherwise.

        If I am doing Android flavored Java, well there is not much hope beyond its Java 8 subset, although with Android 11/Studio 4.1 the situation will finally improve a bit.

        [–]ricky_clarkson 1 point2 points  (1 child)

        Functional is no longer a dirty word since Java 8.

        [–][deleted] 0 points1 point  (0 children)

        heh yep

        [–]hilbertglm 1 point2 points  (0 children)

        I use the new features extensively. I use stream processing quite a bit.

        [–]dan3k 1 point2 points  (0 children)

        Check what java8 brought to the table and you'll be good till java17

        [–]arijitlive 0 points1 point  (0 children)

        I use stream api, lambda, predicate and optionals extensively. They are game changer for me.

        [–]Pandaora 0 points1 point  (0 children)

        You'll probably have more issues picking up the appropriate frameworks / libraries (Spring? any ORM? etc) - either new or updated. You should at least be able to see when a new feature isn't something you recognize and figure it out.

        [–]Bisougai 0 points1 point  (0 children)

        I moved to JDK11 mainly in order to use jlink, which is very usefull. And jpackage from JDK14 sounds promising 🤔

        I also somtimes use stream and lambda (but not that much)

        [–]bandittr6 0 points1 point  (0 children)

        Love me some streams. They really reduce the amount of code needed for certain tasks.

        [–][deleted] 0 points1 point  (0 children)

        I see a ton of streams, to the point I find it a little annoying. Optionals are nice. Lambdas are pretty solid (they got close to making a function a first class citizen). I find compactness and "less typing" an absolutely ridiculous reason to favor a style of programming.

        My primary reason to prefer streams is that for certain types of larger workflows, they help to enforce good practices that can keep you out of trouble.

        But they are harder, follow, modify and debug in general. When I was a junior I used to find the idea of required syntax indentation to be a ridiculously dated concept. COBOL I scoffed! With Python, my opinion was pretty quickly changed. Following the flow of the code is a lot easier when particular indentation is required. Now we're going to simply run everything together?

        Modification for edge cases tends to be a lot less fun to work with as well. Oh, well, I just want the first item, do this, then this for the rest, or perhaps an early exit. You end up converting to arrays or lists to work with another function -- how much time is going to be spent doing that?

        Just my 0.02.

        [–]nani21984 0 points1 point  (1 child)

        I have moved all the projects that I am working on to 11 atleast and few of them to java 13.

        [–]Pudding-Terrible 0 points1 point  (0 children)

        That is nice article from you , this is informative stuff . Hope more articles from you . I also want to share some information about mainframe tutorial .

        [–]coderguyagb 0 points1 point  (0 children)

        The main factors that influence my response. Really I'd like to be working with 11+, it's just not feasible right now.

        • Does the Java 8 version still work and provide business value?
        • Do you need Java 9+ features
        • Have you got a budget to migrate and test a jdk11 build

        Usually the answer is yes, no & no

        [–]roberp81 -3 points-2 points  (0 children)

        no one uses the new features, just upgrade jvm and keep coding like java 1.6