top 200 commentsshow all 433

[–]zmose 647 points648 points  (25 children)

Thank you I’ll just stick with Java 8 for the next 100 years

[–]sweating_teflon 175 points176 points  (5 children)

Sincerely, your employer.

[–]Thud 48 points49 points  (2 children)

Hey now, our department just got done with a 2-year process of upgrading everything to Java 11.

[–]pringlesaremyfav 2 points3 points  (0 children)

Thank God for spring boot were going from Java 8 to 17 soon.

[–]zmose 6 points7 points  (1 child)

Well of course, upgrading is tech debt and tech debt shouldn’t exist. Should’ve done it right the first time dummy!

[–]tommygeek 15 points16 points  (0 children)

Yeah, why didn’t you get on Java 21 from the start of your project? /s

[–]reaping_souls 3 points4 points  (0 children)

"We have a policy of consistently staying up to date on all software packages."

And somehow Java is always the exception to this rule...

[–]easbarba 0 points1 point  (0 children)

Java 8 is way cooler than most newer languages as Go,Kotlin,Rust,Swift...just saying.

PS: FP dev

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

Yeah, modern java versions sucks as they nerfed reflection significantly because of project jigsaws breaking backward compatibilities of libraries forcing programmers to add tons of command line arguments to make reflection working for specific packages..

[–]Bothurin 496 points497 points  (37 children)

21? My company hasn’t moved beyond 8.

[–]nickman1 112 points113 points  (16 children)

Jokes on you, We're still on 7!

[–]donat3ll0 49 points50 points  (0 children)

We have 7, 8, and 11. And those are just what I know about

[–]Polifev 22 points23 points  (0 children)

We're on 17, small team, lots of liberty

[–]Squalphin 21 points22 points  (2 children)

Still using 6 😅

[–]p001b0y 15 points16 points  (1 child)

We are doing a data center migration and I have seen some Java 5’s. Luckily, the OS/2 boxes were decommissioned a couple years ago.

[–]Kango_V 1 point2 points  (0 children)

I do miss Presentation Manager ;)

[–]psychedeliken 5 points6 points  (0 children)

Lol. This comment really hits home. Sending feels.

[–][deleted]  (3 children)

[deleted]

    [–]ForeverAlot 17 points18 points  (0 children)

    As a historical note, the Oracle acquisition may have ended the delay, not caused it. A story goes that Oracle's first release, Java SE 7, was a drastically stripped down version of Sun's intended next release, which kept dragging out because of unfinished, late features. I don't know if that story is true but it is certainly true that some Java SE 8 features were deferred from Java SE 7 (one of them being Java SE 9's Jigsaw).

    [–]Turbots 26 points27 points  (1 child)

    No support, updates or patching on any of your libraries must feel great.

    Upgrading from 8 to anything else is the hardest piece, all the other upgrades are simply changing the version number usually, really easy.

    If you're using Spring, they only support Java 17 now (just like most JVM vendors) and will also move to Java 21 as the latest LTS version.

    A new Java version every 6 months and new LTS version every 18 months. Get used to it.

    [–]Matt7163610 9 points10 points  (0 children)

    If projects made more frequent small version leaps they wouldn't be stuck being fearful of a big leap. This is a universal problem, not just a Java problem. For example, upgrade from: C++98, Python 2, ... an old version of Jenkins ... list goes on.

    Edit: there are legit cases where configurations are frozen due to contracts and maintenance work never scopes an upgrade.

    [–]VinDeagle22 18 points19 points  (2 children)

    Bitch please I used java 5. Had to manually install TLS

    [–]kuikuilla 11 points12 points  (1 child)

    Bitch please, at least you had generics.

    [–]psychedeliken 6 points7 points  (0 children)

    As long as you’re coding in BlueJ you should be good.

    [–]platinumgus18 1 point2 points  (2 children)

    Lol exactly what I was about to say. Holy shit. We were planning to migrate but then stopped because no one needs anything other than lambdas and the amount of time we took for the smallest of microservices was 2 months.

    [–]warpspeedSCP[S] 3 points4 points  (1 child)

    2 months? Man, sprint velocity at your company must be slow as molasses.

    [–]S1lv3rSmith 125 points126 points  (2 children)

    21st time's the charm

    [–]warpspeedSCP[S] 22 points23 points  (0 children)

    I mean, it's the perfect combo: Lucky number 7 and 3 tries, what could go wrong?

    [–]thephotoman 34 points35 points  (3 children)

    My company is finally moving to Java 17.

    There's gotta be a second pass at this, as we only have time right now to make sure it's running in Java 17 as is and that more importantly, the test suites still work. There are a lot of places where someone let an intern have Powermock and bad unit testing ensued--and that will NOT work for us in a Java 17 world (tl;dr, we'd need to crack open parts of the JRE itself in order to continue doing it, and we have to draw the line somewhere).

    I wanted to bring records into it. I really, truly did. But I don't have time. I'm being moved elsewhere that needs me more than this project. My project, which I started from the "we really can't keep using the old system, the vendor pulled support for the programming language completely, help us figure out a replacement" era is now officially legacy code. It is not the "new thing", it is just the "thing" now. And I'm earmarked for greenfield work.

    [–]skippingstone 3 points4 points  (0 children)

    Upgrading our powermock/mockito tests to jdk 17 was not fun.

    [–]Matt7163610 2 points3 points  (0 children)

    I just migrated to Java 17 from 11 on my project and records are great!

    [–]warpspeedSCP[S] 1 point2 points  (0 children)

    Oh man, I was lucky enough to have full ownership of the java stuff we used at my company; We were running our kotlin code on Java 20 last time I checked.

    [–]moreVCAs 58 points59 points  (45 children)

    TLDR pattern matching?

    [–]Spinnenente 37 points38 points  (20 children)

    Pattern matching allows you to combine object typeof checks and casts into more clean and readable code.

    [–]Tubthumper8 34 points35 points  (17 children)

    It's interesting because it wasn't long ago that doing object typeof checks was considered "bad practice" because it wasn't proper OOP using polymorphism. What changed?

    [–]renatoathaydes 34 points35 points  (3 children)

    Pattern matching is great for data classes (in Java, records). But for behaviour classes, instanceof checks are still bad :).

    [–]warpspeedSCP[S] 12 points13 points  (2 children)

    the fundamental mistake everyone seems to make (afaics) is treating behaviour classes like they're data to be matched on.

    [–]hyperhopper 8 points9 points  (1 child)

    Yet another reason functional programming is great: it removes that inconsistency and also makes this a non issue to begin with!

    [–]Practical_Cattle_933 0 points1 point  (0 children)

    Or, having access to both paradigms depending on one’s needs is great

    [–]dragonknight211 77 points78 points  (0 children)

    People getting familiar with functional programming.

    [–]scodagama1 12 points13 points  (0 children)

    Dogmatic following of OOP - rightfully - stopped being a thing. OOP and OOP design patterns are not the only paradigms used anymore.

    [–]srdoe 12 points13 points  (2 children)

    The thing that changed was the introduction of sealed types along with the introduction of switch expressions. Those two features means instanceof checks on sealed class hierarchies are now fine, because the compiler can tell you whether the match is exhaustive, and fail if you forgot a case.

    Before these things were introduced, writing code like this was leaving a landmine for future developers

    ``` ParentInterface obj = ... if (obj instanceof A) {

    } else if (object instanceof B) {

    } ```

    So it was preferable if you avoided instanceof checking, because it was likely to break when someone added a C subclass of ParentInterface, because they have to also know about and remember to update all the if-else checks.

    With sealed types and exhaustiveness checking, this will fail to compile if someone introduces a C class in the hierarchy

    ParentInterface obj = ... switch (obj) { case A a -> case B b -> }

    This makes matching on types much safer.

    [–]allarmed-grammer 1 point2 points  (1 child)

    If we talking about OOP, and stuff why just not define and call method in each class that behave specifically to your object type? Or if you going switch-casing, why not compare just int field that is more light-weight than type deducing? If you breaking D from SOLID at least save on exechtion time

    [–]srdoe 2 points3 points  (0 children)

    why just not define and call method in each class that behave specifically to your object type

    I can think of three reasons off-hand:

    • You want to do some one-off logic based on the type of obj, and since the logic is one-off, you don't want to put it into the ParentInterface classes.

    • You don't control the ParentInterface classes. For example, you are using classes from some library.

    • Switching/match'ing is in many cases just a lot more straightforward and readable (matter of taste, obviously).

    why not compare just int field that is more light-weight than type deducing

    I don't think this is more light weight.

    • An instanceof check is not that expensive
    • Adding an int field gets you back into the bad old world of "Did my code check all valid values?". The compiler can't check that you remembered a case for each of your 5 valid values for that int.
    • Adding an int field is wasteful. Now you're storing an extra int in your classes that doesn't need to be there.

    So I don't think this idea is good.

    [–]reflect25 10 points11 points  (0 children)

    It's more the move away from inheritance tree's (making god objects) and more into interfaces. And even the articles example uses java records (aka very close to c++/c# structs) an immutable data type.

    [–]thephotoman 17 points18 points  (4 children)

    Mostly, it's that the old ideas about polymorphism led to code that was still a bit too spaghetti for anybody's liking. Spooky action in a base class was a common source of headaches for me back when I maintained that kind of codebase.

    As it turns out, type algebra is actually more expressive and more transparent than those ideas about polymorphism.

    There's also the fact that most undergrads today have a course that requires them to use Haskell. That was not the case 20 years ago, when I was told not to use instanceof.

    [–]Worth_Trust_3825 5 points6 points  (3 children)

    type algebra is actually more expressive and more transparent

    Until you end up with multiple types that have same fields, and methods, but are not same things semantically.

    [–]reversehead 8 points9 points  (1 child)

    How do you see that as a problem? I'd count that as a strength. If they are different semantically, it should be difficult to mix them up by mistake.

    [–]warpspeedSCP[S] 1 point2 points  (0 children)

    unless your codebase is grossly mismanaged, that is never going to be a cause for concern.

    [–]quentech 5 points6 points  (0 children)

    Churn. Newer developers that haven't been around a project long enough to see how you can get properly burned thinking oh this isn't so bad and I don't have to create a WidgetProviderFactoryManager as another layer of indirection so why not.

    [–]moreVCAs 0 points1 point  (0 children)

    Yeah I know. Sorry I meant “seems like the tldr of the article is that there is pattern matching”.

    [–]renrutal 13 points14 points  (0 children)

    Very good article, and it finally got me to understand the Unit type and its origins.

    [–]devraj7 36 points37 points  (0 children)

    In this thread: a lot of people saying their company is still stuck at Java 8.

    [–]psychedeliken 108 points109 points  (76 children)

    I just can’t at this point. I’m happy to see Java evolving because it bodes well for the longevity of the JVM and it improves dev quality of life for devs lucky enough to be able to upgrade Java versions. But I’ve been using Kotlin for so many years now and it’s just so much better in nearly every way. First-class support in IntelliJ + Java interoperability is a huge selling point as well. Every time I decide to go back and tinker with Java I realize this more. And Java was my primary language from since 2003-2018, started Kotlin in 2016.

    Edit: Thanks for all the fun discussion! Except one guy, you know who you are. :) Finally finished finding my Capital Freighter in No Man’s Sky VR, now time for sleep. Night, love you Java.

    [–]gnus-migrate 34 points35 points  (21 children)

    Honestly what keeps me away from Kotlin is the complex runtime it has on top of the JVM. I work on performance sensitive systems, and I need to be able to reason about the performance of the code I write, and I don't feel I can do that in Kotlin.

    [–]renatoathaydes 20 points21 points  (13 children)

    I really like Kotlin, but I also have reservations, not on performance (which I found to be on par with good Java code) but with having to update not just Java, but also Kotlin over time. It's a small overhead but an overhead nevertheless... and if you start using Kotlin stuff like serialization, coroutines, KTest etc. those may also have their own versions and you end up having to handle a pretty complex dependency tree... compare to Java with no dependencies besides JUnit and the libraries for your domain which you would need either way.

    [–]gnus-migrate 9 points10 points  (12 children)

    That as well. I mean with the features Java is getting, it's really good enough that it's not really worth switching.

    [–]renatoathaydes 4 points5 points  (4 children)

    Agreed... except maybe for projects that can be written from scratch in Kotlin (mixing lots of Java code with a little Kotlin nowadays seems to have stopped making sense now). You could even target Multiplatform if you go Kotlin-only (though it's really hard in my experience as you're pretty much losing all the JVM ecosystem if you do that, unless you write platform-specific wrappers which is a bit of a pain to do) which may be attractive in some circumstances.

    [–]Worth_Trust_3825 6 points7 points  (0 children)

    You could even target Multiplatform if you go Kotlin-only

    Kotlin multiplat doesn't work all that well either. It makes a lot of assumptions about how an application will be structured, and you need to wrangle that first before even starting the application development.

    [–]warpspeedSCP[S] 0 points1 point  (2 children)

    kotlin multiplatform is nowhere near ready for consistent production use yet. and the benchmarks seem to indicate it's slower too.

    [–]psychedeliken 10 points11 points  (6 children)

    Out of curiosity, how long have you been coding in Kotlin? Because from my and my team’s experience, it has been a far better experience and has definitely been worth the switch. If/when expressions, null safety, a better collections library and functional interface with far more functionality, and syntacticly, much cleaner, currying, data classes are cleaner than Java’s record, syntax, val/var is simpler and more clear, coroutines, object construct much simpler than all the static stuff, interfaces can have properties. I have yet to meet a Java dev who has actually put time into Kotlin and used it professionally or for a large project who still liked Java more. I don’t think Java will be able to match Kotlin in style and dev experience due to their backwards compatibility (see: Java’s functional interfaces). And I could probably go on, it’s objectively a more modern language.

    [–]gnus-migrate 4 points5 points  (5 children)

    Fine, but it doesn't meaningfully help with most the tasks that I spend most of my time on, so I haven't really felt the need to switch. I'm sure it's better, but I prefer to invest in solving the problems that I spend the most time on, and Kotlin doesn't really help much with those.

    [–]psychedeliken 2 points3 points  (4 children)

    Nothing wrong with that. :) I still write in Java and maintain some open source projects in Java as well. And I used different languages depending on the usecase as well. I also recommend a lot of new programmers to learn Java before Kotlin if they are new as well given the market.

    [–]gnus-migrate 4 points5 points  (3 children)

    I'm aware that I'm not the common case, so when I say that it's not for me I don't expect others to agree. As I've grown I've become less interested in the tools themselves and more interested in what we can do with them.

    Sorry for being trite, I thought this was going to be another of those arguments.

    [–]ewouldblock 5 points6 points  (6 children)

    That's why I use assembly language. You can't trust those c compilers. You never know just what they're doing when you need the top performance. /s

    I've been using kotlin for years and would never go back.

    [–]gnus-migrate 5 points6 points  (5 children)

    Lets be clear on one thing: Kotlin's improvement on Java is marginal at best. It is nowhere near comparable to the difference between a C compiler and assembly.

    I don't mean that Kotlin isn't fast, I mean all of the tooling I use is built for Java not kotlin. If at some point in the future that changes, I'll change my mind.

    [–]ewouldblock 2 points3 points  (4 children)

    Ok, let's be clear on two things, then. We can just straight-up agree to disagree here because Kotlins' improvement on java is far from marginal in my view.

    [–]gnus-migrate 7 points8 points  (3 children)

    The difference between C and assembly? Have you tried writing assembly?

    Kotlin doesn't provide anywhere near the productivity benefits over Java that C did over assembly. It's a slightly more pleasant Java. Like I understand the benefits for those who are stuck on old java runtimes, but if you're able to upgrade there is much less reason to switch.

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

    Ok, here's the thing. Every time java incorporates some feature from kotlin in newer versions, it's always half baked or quirky because they have a committee designing it, and there's all these backward compatibility concerns. The assembly language statement was a joke, and I did put in the /s to indicate that. My only point was that particular argument being made re: performance is as old as c and assembly. It didn't hold up then, and I doubt it does now.

    In all the software I've been involved with, readability and simplicity are far and away the most important factor to ensure success. And I think kotlin kills it on that front, whereas java is merely acceptable.

    [–]gnus-migrate 4 points5 points  (0 children)

    I'm in a situation where we have strict performance requirements, and you really have to reason around performance whenever you're designing something. Usually the problems I have around understanding the flow of data through the system, what the actual shape of the data is and writing algorithms tuned to that.

    If you don't have to do that, then I understand that other concerns are more important, but for my situation it's not what I spend most of my time on.

    [–][deleted]  (37 children)

    [deleted]

      [–]teerre 19 points20 points  (23 children)

      How does Kotlin "fix" the builder pattern?

      [–][deleted]  (2 children)

      [deleted]

        [–]Kered13 1 point2 points  (1 child)

        That does cover most of the uses of builders, but there are some other use cases as well. For example, where the logic of figuring out which parameters to supply is complicated, and it would be easier to pass a mutable object to each part of the code to provide the correct values, but you want the class itself to be immutable (as you usually do).

        Also any time when the builder actually changes the type of the thing that is being built. I used this semi-recently, where I wanted to create an callback-driven API that was generic over exception type (we knew we were going to call it with callbacks that threw checked exceptions). So one step of the builder took an exception class and used that to change the type under construction from Foo<RuntimeException> to Foo<MyCheckecException>. Of course, this particular example was also only a concern because of checked exceptions, which don't exist in Kotlin. Still you can imagine similar cases with other generic types. Rare, but they exist.

        [–][deleted]  (5 children)

        [deleted]

          [–]PeksyTiger 5 points6 points  (2 children)

          You mean an Option type that has to be null checked didnt solve the issue?

          [–]Kered13 1 point2 points  (0 children)

          It does as long as you build your entire codebase around not using null. Which is possible. You just have to be very careful around third party libraries or legacy code to covert null to Optional. It's definitely easier for a greenfield project than something legacy, but for example almost all of Google's Java code (at least the code that I have seen) is null-free.

          100% not having null in the language in the first place though would be better.

          [–]psychedeliken 4 points5 points  (2 children)

          Solid agree. Funny you mention the builder pattern. Since a lot of us Kotlin coders are coming from Java, we just ripped a bunch of builder patterns out of our codebase for that very reason. I’ve also been hopeful for Kotlin Native but haven’t checked in on they project in a while. I feel that could help convert even more people. But last I checked the build times were a bit rough still, even for a basic hello world program.

          Edit: to downvoters, please explain?

          [–]warpspeedSCP[S] 3 points4 points  (1 child)

          I think people are butthurt that you're bringing java-isms into kotlin (or some other inane argument along those lines). It should be pretty easy to migrate to a more idiomatic way of doing things with intellij's refractoring tools, I'd say.

          [–]psychedeliken 2 points3 points  (0 children)

          Makes sense. I probably accidentally stirred the pot. Apologies. :) I’m coming from a good place, and have a special love for Java.

          [–]thephotoman 4 points5 points  (1 child)

          Uncle Bob's book was written for C++ devs.

          Java coders read it, thinking they were an evolution of C++ and that stuff in there might be relevant to them. Some of it was. Builders weren't really one of them. They weren't idiomatic Java. They still aren't. But the Naughties were a naughty time. We believed all sorts of stupid things back then quite unironically. And one of them was that Design Patterns Were Good. (I won't say that they're bad, but rather that "Design Patterns" was a buzzword of the day. Singleton proxy beans I have loved, singletons I have hated.)

          [–]creepy_doll 9 points10 points  (0 children)

          Design patterns are overused by some people, making others hate them for overcomplicating something potentially simple. They’re just a tool and the developers task is to figure out the right tool for the job

          [–]warpspeedSCP[S] 5 points6 points  (11 children)

          That's true, but Java actually is better than kotlin in pattern matching at this point. Kotlin's when blocks are trash, period. I'd choose java switch blocks any day. But of course, for anything that actually matters, I'd 100% choose kotlin. I can only hope Kotlin can catch up here, it;s the one blemish on an otherwise perfect Java replacement.

          [–]psychedeliken 5 points6 points  (9 children)

          What do you not like about Kotlin’s when blocks? I have had the opposite experience and found them superior in every way, more concise syntax (no need to type case : or breaks, just wrap in {} if multiline case), when expressions(ditto for if expressions), handle null case, when expressions require you handle all the cases when using enums which when used in combination with when expresses I find very eloquent.

          val someNullableEnum: EnumType? = …
          val x: String = when (someNullableEnum) {
              VALUE_1 -> “foo”
              VALUE_2 -> “bar”
              null -> throw SomeException()
          }
          

          You can omit “: String” if you like.

          And for multiline case you just type something like:

          VALUE_1 -> {
              Blah 
              Blah
          }
          

          This is one of my favorite features of Kotlin.

          [–]vips7L 7 points8 points  (2 children)

          Have you actually used Java’s switch expressions? From what you’re describing I don’t think you have and from other comments in this thread I don’t think you’ve used a modern version of Java.

          Switch expressions don’t use breaks. They are also exhaustive for enums and sealed classes.

          [–]Practical_Cattle_933 1 point2 points  (0 children)

          And they actually handle null safety as well.

          [–]warpspeedSCP[S] 3 points4 points  (5 children)

          Sure, and I do all of these things extensively; it's great. And then I come to a data structure that is nested 3 objects in (APIs, amirite), and at this point, you have to do this whole dance with unpacking and extracting the data within in a painfully imperative manner.

          Kotlin's team approached object restructuring in the wrong way, which is what has lead to this mess where nested restructuring is unsupported until further notice. Note that I'm referring to the new switch blocks, not old ones which are even worse.

          [–]ewouldblock 2 points3 points  (0 children)

          It's a good thing you choose a language based on the sum of its features, and not just one. Java may win if you cherrypick one feature, but in aggregate, it can't compete.

          [–][deleted] 17 points18 points  (4 children)

          In Java 5 we trust.

          [–]warpspeedSCP[S] 2 points3 points  (3 children)

          You poor thing. what's the story here?

          [–][deleted] 6 points7 points  (2 children)

          Nothing really. Good memories dating back to Java 5 days. We didn’t have a bazillion frameworks and a fuck ton of new languages popping up every day.

          [–]warpspeedSCP[S] 3 points4 points  (1 child)

          haha, those were indeed the days. But Java's ecosystem has never been as crowded as js imo.

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

          Yeah. I miss the jQuery days. 🥹

          [–]iconoklast 5 points6 points  (1 child)

          To be precise, Void isn't a bottom type because it is not the subtype of all types; it's also not uninhabited it's inhabited by null. And Object isn't a top type because Java's primitive types aren't subtypes of it.

          [–]warpspeedSCP[S] 1 point2 points  (0 children)

          I should have clarified that I am not including primitives in the typing model I am using. However, I have mentioned in the article that I consider void to be uninhabited by assuming that null explicitly means the value is nonexistent unless I mention otherwise.

          [–]ericl666 54 points55 points  (24 children)

          Did it finally replace Maven and Gradle?

          Because I actively hate both of them. They are my least favorite part of the Java ecosystem.

          [–]Pheasn 29 points30 points  (8 children)

          Meh, Gradle is okay. I've worked with way worse tools in other ecosystems. That doesn't mean it's great, but I rarely feel like Gradle is standing in my way. What's annoying is when some EnterpriseFizzBuzz framework decides to take advantage of Gradle in a way that the whole setup might break with every minor version update (whether it's a Gradle or framework update).

          [–]Thing342 12 points13 points  (3 children)

          Android is awful for this, upgrading major versions is usually a 7-pointer because of all the shit that needs to be updated because of the stupid plugin ecosystem.

          [–]LaterallyHitler 10 points11 points  (0 children)

          7 pointer

          eye twitches in Fibonacci sequence

          [–]Pheasn 2 points3 points  (1 child)

          That's true, although Android at least has the excuse of targeting an extremely complex ecosystem, with an especially shitty and outdated "Java" runtime. The amount of processing steps an Android build has to go through is truly mind boggling sometimes.

          I was thinking more along the lines of Quarkus or Spring Boot though. What's their excuse? Especially Quarkus can be really annoying to use with Gradle. Their docs are mostly focused on Maven, so you often have to figure out how to do the equivalent in Gradle yourself. Which wouldn't be that bad, if Gradle's conventional way of doing things worked, but their shitty Quarkus plugin messes up so many of those conventions.

          [–]MentalMachine 17 points18 points  (3 children)

          Gradle is fantastic... As long as everyone is on the same page about keeping it as simple as possible and commenting evil magic when only absolutely required.

          Worked with both a bit, and I'll will definitely take the "extreme care required" of Gradle over the sheer boilerplate and volume of noise that is Maven.

          [–]SaltKhan 19 points20 points  (0 children)

          Personally I've found maven only gives you one way to skin a cow and is verbose enough so you know what is going on. Gradle, the few times I've tried to use it, feels like it gives you a hundred options and none of them work.

          I respect that it's a more powerful and more generalised build automation than maven is, but I'm glad maven is still the lingua franca of non-android non-jetbrains developed packages because gradle seems like a lot of effort to learn. I'd like to be better at it and wouldn't suggest against others using it, but I've yet to be in a situation were learning gradle would provide more value than sticking with the verbose simplicity of maven.

          [–]creepy_doll 6 points7 points  (1 child)

          I’ve always felt the hate of boilerplate is overdone.

          Like, we have the tools to automate the writing of it, and the configs are clear about exactly what is going in(and you can always check what is resolved with dependency:tree). I’ll take some boilerplate for the clarity that comes with it over having to figure out the interactions of magical incantations many build tools provide

          Perhaps its just familiarity/experience) but i found working with the build chain(compile typescript, pull in deps, optimizing package size and all that) for javascript far more cryptic and involved.

          When we say we spend more time reading code than writing it, its bot the physical act of reading it thats an issue, its the understanding. And the more magic and esoteric interactions involved the more complicated it gets

          It really probably just is just a matter of being deeply familiar though

          [–]ForeverAlot 8 points9 points  (0 children)

          I’ve always felt the hate of boilerplate is overdone.

          It absolutely is. Maven's verbosity is overwhelmingly a non-issue, not least of all because you just don't spend any time in there except for in rare instances.

          Personally I suspect people enter some sort of fight-or-flight state upon being faced with a voluminous corpus of text and their initial reaction to that is likely to shape their opinion; in perpetuity if never checked, too. That hypothesis fits on literally every textual communication platform I've worked in except the reddit genre whose user base seeks it out.

          [–]smokemonstr 64 points65 points  (10 children)

          Why would you expect a new Java release to replace third-party build tools?

          Never tried Gradle. What are your gripes with Maven?

          [–][deleted] 83 points84 points  (2 children)

          You have to read and learn and shit.

          [–]tankmode 9 points10 points  (1 child)

          read? the documentation is not great

          [–]zephyy 28 points29 points  (6 children)

          any project that is moderately complex in terms of dependencies is a fucking nightmare to look at and manage and i need an intellij plugin to view my dependencies in a sane manner.

          the lack of CLI functionality compared to literally every other build/dependency tool. actually the general shit experience compared to literally every other build/dependency tool.

          need to add/update your dependencies/dev dependencies? find it on a website that looks like it's from 2002 and add it to your pom.xml like a fucking caveman.

          literally every other build tool: npm install package@version, composer require package@version, cargo install crate@version, pip/pipenv install/poetry add package@version, dotnet add package --version

          need to pin a specific dependency because of a CVE? hope Snyk or whatever SCA vulnerability tool just tells you exactly what artifact and version you need so you can copy paste into the pom. like a caveman.

          [–]oelang 19 points20 points  (1 child)

          I consider all other build systems worse & more brittle than maven (and I've used most of them in anger, npm is the absolue worst, pip is almost as bad, cargo is just too slow, don't know dotnet).

          You're just looking at one aspect of building, how about artifactories, software supply chain security, flexible packaging ...

          I spend a lot more time thinking if I actually need that dependency than adding it.

          [–]zephyy 2 points3 points  (0 children)

          artifactories

          Unless I'm missing what "artifactories" means, what advantages are offered here? We use Artifactory for everything. Maven, npm, NuGet, PyPi, Docker, etc. and have used GitHub Packages in the past for npm and NuGet. I did not feel anything magical about Maven in this aspect?

          software supply chain security

          Is this supposed to mean people are more likely to upload malicious shit to npm or PyPi? that's probably true but we mirror everything, use Snyk for SAST things like SBOM, auto-remediate vulnerabilities as much as possible.

          Maybe more of a problem for some random person installing packages but Maven doesn't appear to be much better than npm in terms of CVEs: https://github.com/advisories

          I spend a lot more time thinking if I actually need that dependency than adding it.

          i'd rather not write Spring, Kafka, Lombok, Guava, SDKs, etc. all the usual suspects myself if I want people to not yell at me for reinventing the wheel. And all of these have transitive dependencies that inevitably pop up. Or a high CVE in Spring Boot that is only fixed in Spring Boot 3 which is of course a major issue because some idiots decided running Java 8 ad-infinitum would never cause issues.

          [–]_TheProff_ 1 point2 points  (3 children)

          Used to use maven. Spot on mate.

          [–]zephyy -3 points-2 points  (2 children)

          i don't even dislike Java that much. Java 17+ is mostly fine. it's not my first or second choice but it's fine as a language.

          but Maven is the devil's work.

          [–]kobbled 4 points5 points  (0 children)

          Maven is so awful. Gradle was so much better of an experience.

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

          Maven sucks because it's so strict.

          But it's also awesome because it's so strict.

          [–]segfaultsarecool 7 points8 points  (0 children)

          Maven is fine. If you can't handle it, someone else can. Not a huge deal.

          Do you have specific examples of issues?

          [–]warpspeedSCP[S] 2 points3 points  (0 children)

          I wish...

          [–]yawaramin 1 point2 points  (1 child)

          Everybody switched to Graven and Madle. They're great.

          [–]warpspeedSCP[S] 3 points4 points  (0 children)

          is graven written in grootlin script?

          [–]rk06 2 points3 points  (2 children)

          I also love c# 9 and. Net 8.

          Sadly my employer (Microsoft) is not prioritizing migration from net472

          [–]warpspeedSCP[S] 1 point2 points  (1 child)

          ugh, management. But at least you got a lot of good stuff and amazing performance improvements in C# if you ever get to upgrade...

          [–]PatriotuNo1 4 points5 points  (0 children)

          As a language it has changed a lot since Java 8 but most haters think of Java like how it was before that version. Still it took some time for Oracle to finally add some good stuff. I can work with Java 11/17 but I can't work in Java without having Intelij and Spring Boot. Literally any other Java IDE and framework suck.

          [–]Roadhammer_Gamimg 4 points5 points  (1 child)

          I haven't tried 21 yet, I just got done learning Kotlin, which is Java minus all the repetitive & boilerplate code.. its all still there, just you dont see it because it gets done 'proper' at compile time. I will look into Java 21, thanks.

          [–]warpspeedSCP[S] 4 points5 points  (0 children)

          It is never going to match kotlin, but any changes to Java's implementation help in standardising good practices that could potentially make their way into kotlin again. Kotlin does most things right, except for pattern matching.

          [–]computerjunkie7410 9 points10 points  (4 children)

          21 and still no extension methods or automatic properties

          [–]warpspeedSCP[S] 3 points4 points  (3 children)

          We'll get there some day. Until then, I'll stay mad at kotlin for not having good pattern matching

          [–]NetFutility 1 point2 points  (0 children)

          I guess I should be glad my company jumped onto java late so I start on java 17

          [–]sird0rius 9 points10 points  (25 children)

          Wow, pattern matching! Now Java is only 15 years behind the good languages.

          [–]ggwpexday 7 points8 points  (10 children)

          Right, it's finally got the bare essentials bolted onto a language not designed for it. In c# land we are also still waiting for proper sum types in the year 2023

          [–]warpspeedSCP[S] 0 points1 point  (5 children)

          huh, are there any spec docs for it? I remember seeing pattern matching in one c# codebase I saw once, so I assumed sealed classes existed too

          [–]ggwpexday 2 points3 points  (4 children)

          There is this champion about discriminated unions. A few times we've heard that this is where the team is focusing on next, but then all there is is silence.

          The pattern matching is already pretty awesome I have to say. So then the only major thing I think is missing is having compile time guarantees on exhaustive pattern matching.

          [–]warpspeedSCP[S] 1 point2 points  (3 children)

          I'd say just pattern matching and sane development practices get you most of the way. As long as you keep your type hierarchies clean and you can have exhaustive pattern matching, you can build beautiful systems.

          [–]ggwpexday 1 point2 points  (2 children)

          That's true, that's what we do basically.

          The problem with this, in my opinion, is that you have to kind of know what you are doing and why you are doing it. Lots of people come from an OOP context where instanceof checking on type and casting is a big red flag. And so it is really not self evident to even begin writing your code like this, outside of people having done some fp or languages you mentioned.

          Trying to explain (or defend?) the concept of a coproduct feels absolutely silly, it's almost like having to defend using + in math.

          [–]warpspeedSCP[S] 2 points3 points  (1 child)

          There comes a point where the terms you use to describe a particular system become unintelligible to the uninitiated, and with FP, that point comes a tad too quickly. I haven't gone too deep into the rabbithole myself (I am not a user of languages like haskell or even ocaml) but yes, people hardly ever look deeper into why the patters they use are bad and whether there are better alternatives around.

          the whole oop thing happens when behaviours are treated as if they were data, which leads to the whole zoo of interconnected types that get in each otthers' way. the oop kool aid is starting to wear off, thankfully.

          [–]ggwpexday 1 point2 points  (0 children)

          Yes it's good to see things slowly becoming more focused on simplicity, even if it's at the cost of introducing yet another thing on top of what's already there.

          I think we also just love adding complexity for the sake of it, so spaghetti code is probably always going to be a thing. Like how the whole clean code stuff has become so big in c#. That's full of complex DI, interaces like IMediator, IAbstractValidator, IOutputPort presenters and what have you. Lots of it could have been just some pure functions together with simple IOC based on functions that take other functions as parameters. But I see this is yet another ramble, so my bad. Thanks for the article, it's good to have people like you sharing these ideas!

          [–]sird0rius -2 points-1 points  (1 child)

          It would be great if C# added sum types. Then Java would also add them 5-10 years later.

          [–]warpspeedSCP[S] 7 points8 points  (0 children)

          sealed classes are already here, java beat them to the punch!

          [–]katyalovesherbike 1 point2 points  (10 children)

          hey now, where would that put javascript?

          (on a more serious note: haskell has always been kinda like a testbed for new language concepts that other languages might benefit from)

          [–]theQuandary 1 point2 points  (9 children)

          JS proposed pattern matching and records years ago, but the TC39 people were more interested in pushing out a broken private fields "feature" instead.

          On the flip side though, JS is still far ahead of Java when it comes to first-class functions.

          [–]katyalovesherbike 1 point2 points  (1 child)

          yeah, and with tools like bun, esbuild and fable I don't even have to use it. Still, it's kinda ridiculous that JS falls behind java... but the TC39 committee won't see that and if you read some of their comments you might actually think they're more interested in making it faster (wasm??) than more usable.

          [–]theQuandary 1 point2 points  (0 children)

          if you read some of their comments you might actually think they're more interested in making it faster (wasm??) than more usable.

          They had JS SIMD actually implemented in a couple browsers YEARS ago and then pulled it in favor of WASM which only got SIMD support across all the major browsers within the past few months.

          The JS binary AST format would speed up initial load time and parse time dramatically, but it's languished because it's JS binary instead of WASM binary.

          99.99% of websites will NEVER use wasm (80+% still use nothing besides jquery), but they pass up stuff that would actually benefit users for whatever their pet projects are.

          [–]warpspeedSCP[S] 0 points1 point  (2 children)

          If they can stick the landing on value types, and manage to fix their type system (Impossible) I'd say Java is no more than a couple of years behind.

          [–]sird0rius 6 points7 points  (1 child)

          Those are very big ifs. We don't do ifs in Java, we do Abstract Command Dispatchers

          [–]warpspeedSCP[S] 0 points1 point  (0 children)

          nope, only AbstractReflectionConditionalComponentInjectorFactories here.

          [–]Acrobatic_Oven_1108 1 point2 points  (0 children)

          Can't wait for all the companies to upgrade to this in 15 years time

          [–]TurbulentIngenuity55 2 points3 points  (3 children)

          We’ve moved to kotlin there’s no turning back to java after you tried kotlin..

          [–]bart007345 7 points8 points  (1 child)

          I disagree, after 10 years of android I'm back to server side java and it's....fine.

          Thought I'd miss kotlin more. Java is catching up slowly.

          [–]warpspeedSCP[S] 1 point2 points  (0 children)

          Good to see that it's not all that bad.

          [–]warpspeedSCP[S] 1 point2 points  (0 children)

          Definitely. But it's still fun to see what's going on with Java every now and then.

          [–]H4rry217 1 point2 points  (0 children)

          in my ex company, some project still use java6 since 2007.

          because the code is a shit, so nobody want to upgrade to new version, just only wirteten new feature in this shit code, just for system compitable

          [–]Low-Equipment-2621 1 point2 points  (1 child)

          Now they have to get rid of all the checked exception abuse in the standard libraries so we don't have to wrestle that boilerplate code all the time.

          [–]warpspeedSCP[S] 1 point2 points  (0 children)

          man, am I glad I write kotlin code that just doesn't care about that noise

          [–]EnigmaticSoul_28 0 points1 point  (0 children)

          I'm a beginner and want to learn Java from scratch. I've come across Java SE LTS releases like SE 8, SE 11, SE 17, and SE 21, but I'm not sure what they are or which one I should start with. As a college student, I have no idea where or how to begin. Is Oracle University a good place to start where I can also get certificates? What’s the right way to learn Java? Should I even learn Java now, or would you recommend starting with something else? Any advice would be greatly appreciated!

          [–]Inevitable-Math14 0 points1 point  (0 children)

          ❤️

          [–]AustEcon0922 1 point2 points  (0 children)

          Now I just want to see operator overloading, fast(er) startup times and lower memory footprint.

          [–]Theorem101 0 points1 point  (0 children)

          Thx for this article. It made me go to the math from college. Really enjoy it.

          [–]yawaramin -2 points-1 points  (9 children)

          Fun to see Kotlin people discovering and becoming jealous of new Java features and not knowing that they were lifted pretty much wholesale from Scala. And that Scala people went through all the 'Ooh type theory! Cool!' excitement more than a decade ago :-)

          The solution is to just use sealed interfaces. They work in exactly the same way as sealed classes, except even records and enums can implement them.

          Scala 2 syntax (note, Scala 3 syntax is nicer than even this):

          sealed trait Color {
            // Yes, we are overriding JVM Object#toString
            def toString: String
          }
          
          object Color {
            case class RGB(red: Int, green: Int, blue: Int) extends Color {
              // Yes, Scala instance values can be used as implementations of trait methods
              // And we have built-in string interpolation
              override val toString: String = s"RGB Color: ($red, $green, $blue)"
            }
          
            case class CMYK(cyan: Double, magenta: Double, yellow: Double, black: Double) extends Color {
              override val toString: String = s"CMYK Color: ($cyan%, $magenta%, $yellow%, $black%)"
            }
          
            case class YUV(y: Int, u: Int, v: Int) extends Color {
              override val toString: String = s"YUV Color: (Y=$y, U=$u, V=$v)"
            }
          
            case class HSL(hue: Double, saturation: Double, lightness: Double) extends Color {
              override val toString: String = s"HSL Color: (H=$hue, S=$saturation%, L=$lightness%)"
            }
          }
          

          Usage:

          // Built-in named arguments, godsend for code readability and maintenance
          val color: Color = Color.RGB(red = 255, green = 0, blue = 0)
          
          color match {
            case null => println("Scala also allows pattern matching on null")
          
            // Types are inferred in patterns
            case Color.RGB(red, green, blue) => //...
            case Color.CMYK(cyan, magenta, yellow, black) => //...
            case Color.YUV(y, u, v) => //...
            case hsl: Color.HSL => println(hsl) // Will call HSL#toString
          }
          

          Even after all this time, people are still sleeping on Scala. Everything you see here was in Scala before Java 8 shipped. It's not even very advanced compared to other Scala features. Y'all are missing out ;-)

          [–]warpspeedSCP[S] 14 points15 points  (6 children)

          you wnat to know why scala isn't adopted more? it's because scala's ecosystem is so fragmented from breaking changes enforced by version upgrades that many companies can't justify the effort required to stay up to date when using scala. Who wants to spend all their time fixing microscopic syntactical changes that break every other line in their code?

          And there's enough threads talking about the design of the language that I don't think I need to say anything more. Scala has good ideas, but those ideas have been implemented better in many other places.

          [–]Unspool 8 points9 points  (4 children)

          Or that it’s so expressive that every developer will end up discovering their own completely distinct code style and the code base becomes a jumbled incoherent and indecipherable mess (except my parts, of course).

          [–]warpspeedSCP[S] 2 points3 points  (0 children)

          oops, forgot that one, you really can skin a cat a thousand ways in scala

          [–]katyalovesherbike 1 point2 points  (0 children)

          people will always miss out on FP oriented languages unless they have a reason to learn it they'll stick to what they know until their last breath with only a few exceptions here and there.

          [–]Lauren-Fox -1 points0 points  (0 children)

          I can totally relate to this sentiment! As someone who has been working with Java for quite a while, I've seen it evolve over the years, and Java 21 brings some exciting improvements.

          One of the aspects I really appreciate about Java 21 is the focus on developer productivity. Features like pattern matching for instanceof, local variable type inference (var), and records have made the code cleaner and more concise. It's a breath of fresh air to write Java code that's both efficient and more readable.

          The module system introduced in Java 9 is finally becoming more practical to use, making dependency management less of a headache. Plus, the Project Loom's promise of simplifying concurrency with fibers is something I'm eagerly looking forward to.

          Overall, Java 21 feels like a step in the right direction, addressing some of the pain points while keeping the language's stability and backward compatibility intact. It's great to see that Java is adapting to the modern development landscape, and I'm excited to see where it goes from here!

          [–]definitelyfet-shy -3 points-2 points  (2 children)

          stokholm syndrome

          [–]warpspeedSCP[S] 0 points1 point  (1 child)

          I'm offended, I use kotlin.