I think Java's handling of this transition compares very favourably to how other languages have handled similar transitions from some old model to a new one (or evolution in general) in terms of balancing the needs of both old and new projects.
I think Java's handling of this transition compares very favourably to how other languages have handled similar transitions from some old model to a new one (or evolution in general) in terms of balancing the needs of both old and new projects.
8->11 was really a pain in the neck. 11->17 had some pain, but mostly was nothing serious.
17->21 has been painless.
And I have some projects running on 24 already with no problems.
The feature delivery has been great and we are getting pretty close to not needing to do anything but update the jdk to move forward.
Now, if only I could get devs to stop using lombok....
One of the only remaining reasons I discard libraries without a further thought
Records also literally do a huge portion of what Lombok does.
There are a lot of fairly popular alternatives to Lombok out there that don't need a constant eye on maintenance. Lombok is probably the most popular but that's really mostly because it's got the first mover advantage.
Official support for compiler plugins (Lombok is an unofficial compiler plugin, not a mere annotation processor!) would effectively allow people to create dialects of Java. This would splinter and blunt the momentum that has carried the language forward for the last 30 years by fragmenting the ecosystem because for many legacy applications it will be impossible to migrate to one of the prevalent dialects.
Other tools and libraries generally do not interact in such an errorprone manner.
That said, when you know how it works, what it needs, and you know how to iron all of those tiny wrinkles, it works fine and saves you some code and/or sanity. It's not the devil, it's a powerful tool with some downsides.
There's one of these for just about every occasion
There are very cool libraries making use of it, e.g. mapstruct.
Now, lombok in its current approach can't make use of it, as it explicitly wants to modify the given class with its annotations. This is forbidden, so they literally hack into the java compiler classes themselves, modifying the AST in-flight. As you can imagine, this might break at a new Java update any time.
It's not a might. If you look at the lombok changelog they have a release for nearly every new jdk version because they break constantly.
When a project can't move up jvm versions it's very frequently been because of lombok.
And if you look at the commit log, it's all a single dev running the show. He's been doing it for years which means the stability of your project is pretty dependant on this one guy keeping things up to date and finding work arounds to get at the jvm internals.
I, personally, avoid Lombok, specifically because I care about implementation details. Because if I would have wanted better Java, I'd go with Kotlin rather than this hacky way of using another Java-like language. But other people hold different opinions.
The 10% lombok can do because it's peaking at internals isn't valuable. I don't, for example, need an annotation to create a static logger. That's dumb.
I dont use lombok and the latter has been actively removed. If you have access to records, lombok is just bad. Even if you dont have - public final fields are sufficient in most case + c-tor and validation there. Just dont use getters & setters.
Records have reduced the advantages of Lombok by a boatload. But there still are some things that can't be records.
That's a fundamental misunderstanding of hashCode, and lombok makes no exception. Not all fields need to be used to calculate hashCode, it makes the overall performance worse in most cases. Equals is of course different, however if you have an identity (i.e. database primary key), only the identity should be used.
I've seen so many performance issues with hashcode because devs will put all fields into it. Even though there's an id column or even fields that imply other fields. Hashing 1000 char strings when there's a UUID or int field that guarantees identity is silly.
I think it's because devs have an preference for symmetry. I see the same thing happen when they preferably add setters for all fields even though they aren't necessary.
Realistically, I have trained quite a few folks on my own.
>I think it's because devs have an preference for symmetry.
Another option is that's the default for all IDEs auto gen, so few clicks/taps and it's done.
My favorite question on interviews is explaining all methods of class Object, including the contract and best practices for equals/hashCode. Failure to answer this question automatically disqualifies applicants to mid-level and senior positions.
finalize() is actually is a very hard mode; I'd not expect any extra senior to be able to explain it properly (incl. the semantics of JMM, the fact half created objects can be finalized; the resurrection ability). Deprecated now, so perhaps no need?
wait/notify/notifyAll - easier, still require some practice, also not that useful any longer; but still I'd expect to know not to use a naked notify and how to properly use a loop around wait
clone() - it'd be a hard nut for many, and I have seen more than enough implementations that straight out use new XXX(); not very difficult but not intuitive
hashCode/equals -> hashCode being by default a random number generator is sort of cool; yes they are the backbone of all collection framework; also the value of the not overridden hashCode() is available through System.identifyHashCode()
getClass() - if included anonymous classes, it might puzzle some
toString() - finally something easy
---flip note: the standard templates for intellij could use some work when it comes to the quality of hashCode;
> Deprecated now, so perhaps no need?
Yes. Worth mentioning existence and “do not touch it”, but no need to go deep. Same with clone. The point of this exercise is to demonstrate that you can use the core library without shooting yourself in the foot. As for wait/notify/notifyAll, I’d expect the correct usage patterns from mid-level.
Doesn't everyone just use Objects::hash?
I hope they do know better, it's actually rather poor. 1st it should not be used for a single parameter - just use hashCode() directly and ensure non-null in the c-tor (or Objects.hashCode). Then, in general you need - only few fields to calc a decent high cardinality hashCode...
Last: 31 as a constant (used in most mul/add schemas by java). It's a single byte prime, so it has some benefits. It can be implemented via shift and add (x<<5 - x) but modern CPUs implement mul quite well and don't have carry flag deps so shift+add is worse in general. However, as a constant is more like to cause collisions in a general purpose hash function. It's close to being power of 2 and multiple of 10 -> 32 and 30.
Right. So the parenthetical clause should more correctly state "(or worse, adding them to hashCode but not equals)". That's fine, but it's still the same problem: there's a hidden dependency between changes in two or more locations. People make errors in those kind of updates all the time.
That's proper bad, however it should be noted in a pull request and explained how hashCode operates - people learn and improve.
> there's a hidden dependency between changes in two or more location
True, of course. However, just do not modify hashCode and consider if the extra fields do contribute to equality either.
Realistically I have not seen this error since very early 00s. I have seen use of mutable fields in hashCode, though (and the latter being modified while added to a hashset, used as map keys. lombok encourages such designs).
Another a lot more common error is "compareTo"
The issue is having plainly useless getters and setter (just use public fields); along with the fact that mutable hashCode/equals
The upsides are: - it generates code and does not do anything funky with internals, - it has a lot of knobs if you need something a little different.
The downside is that it does not provide you with the other Lombok annotations. In practice that has been OK!
that's actually not too hard. It has happened to get them all converted to avid opponents of lombok.
Semantics. Nobody demanded anything, if we want to play word games.
The java philosophy of final, makes software less extensible. This is the point; to have less overriding. Regardless of what the voting body decides (the meaning of users being subtly repurposed), the feature is anti-developer-agency past the point of healthy balance. I dont understand the enthusiasm.
You say ignore. This is unnecessarily pejorative. You mean "change".
Software does not care about explicit intentions or who is leveraging it. Overriding is one of the essential methods of extending software.
However, changing other code (and potentially changing the assumptions on which it was built) shouldn't be as easy as using it in a way that preserves its assumptions. If it were just as easy, you could accidentally break other code's assumptions.
In some situations, all that's required of you is merely to declare that you indeed intend to change some other code's assumptions; in more involved situations (e.g. a library method computes the sum of its argument and you want to change it to compute the product) the work is more involved, but you can still do it relatively easily.
What we have blocked is the ability of a library to change the assumptions of another library or of the application's without the application knowing about it. A library absolutely must not be allowed to do that while hiding that from the application.
People asked for lightweight concurrency, better FFI, faster startup, value classes etc.. How could we have done any of that without the integrity work? It's like saying, nobody asked you to make noise and dust to lay down cable ducts, we just asked for fast internet.
> The java philosophy of final, makes software less extensible. This is the point; to have less overriding. Regardless of what the voting body decides (the meaning of users being subtly repurposed), the feature is anti-developer-agency past the point of healthy balance.
There's absolutely no capability that this JEP removes (also, you seem to be confusing final classes/methods with final fields). All it does is say that the minority of programs that want to mutate final fields just have to tell the JVM about it so that it won't apply some future optimisation. Nothing is being taken away.
The JEP is: if you're mutating finals, you can continue to do so; if you're not -- you'll eventually get better performance. What's not to like?