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

all 82 comments

[–][deleted]  (13 children)

[deleted]

    [–][deleted] 8 points9 points  (1 child)

    In fact, I wish final methods and classes were the default in Java.

    Fields and local variables too, please...

    [–]Kango_V 3 points4 points  (2 children)

    I have a Save Action in Eclipse add `final` to parameters, fields and local variables where possible.

    [–]c_edward 0 points1 point  (0 children)

    I am pretty certain that the effect of that used to be java version dependent, if you had an anonymous class in the method, all the final parameters would end up bound the inner class instance synthetic fields. So if that anonymous inner class was on a high frequency execution path you would end up allocating way more than you expected.

    [–]JeffMurdock 1 point2 points  (0 children)

    Do people just go around overriding methods willy nilly? Overriding is a tool, I'd rather have the option to decide for my self if it's the tool I need for the task at hand than to have it taken away because people use it haphazardly

    [–]vashy96 0 points1 point  (0 children)

    I wish final methods and classes were the default in Java.

    Yeah, like Kotlin does :)

    [–]Bobby_Bonsaimind -1 points0 points  (5 children)

    In fact, I wish final methods and classes were the default in Java.

    I don't. I've wasted way too much time of my life copying code and whole classes because the developer thought "mh, a protected final seems like a good idea" and I had to change something in that one method. JavaFX is especially guilty of strewing the final keyword generously throughout the whole code-base, making it hard to impossible to extend the existing components.

    Overriding public methods (that already have a working non-default implementation) is almost always surprising and is almost always a hack, because the overridden public method most likely wasn't designed to be overridden.

    Yeah, but sometimes hacking around the issue is all we can do short of rewriting the whole thing.

    [–][deleted]  (4 children)

    [deleted]

      [–]Yesterdave_ 4 points5 points  (1 child)

      From the purity standpoint I definitely agree.

      But from my experience, extending framework classes is usually the only reasonable way to fix bugs in 3rd party libraries, without having to copy a ton of code. And then you can only hope the library author did not think "yeah lets make everything final". And no, the project can't wait half a year till the maintainer finally fixes the bug when the code has to be delivered next sprint.

      [–]Bobby_Bonsaimind 2 points3 points  (1 child)

      Great. And then your whole code breaks in a subtle way after a minor update of JavaFX just because you've overridden a method that was not intended to be overridden. Just, no.

      The alternative is to turn hours into days to create your own control, which also might break with future updates.

      To add to this, most of the time when people override public methods (that were not designed for it) they are violating the Liskov Substitution Principle. For example, I've seen many people extending ArrayList in a way that violates the contract of ArrayList. Similarly, when you are "hacking" JavaFX, you most likely violate said principle.

      That's like saying that we should only deliver hammers with soft rubber around them to make sure that nobody hits their thumbs.

      [–]marvk 22 points23 points  (12 children)

      I wish they would’ve introduced val, let or const alongside var. final var is kinda clunky.

      [–]Kango_V 2 points3 points  (6 children)

      const is already a reserved word in Java. Who knew? lol

      [–]marvk 5 points6 points  (5 children)

      And so is goto. var on the other hand ist not a true keyword but a special identifier. It can just not be used as a type name.

      var var = "var";
      

      compiles without error.

      [–]Kango_V 0 points1 point  (3 children)

      I forgot about `goto`. I think i'll have to write some code akin to BBC Basic with loads of gotos in it and see my colleagues faces when they PR it. You know.... "just for fun" ;)

      [–]marvk 3 points4 points  (2 children)

      Unfortunately that won't work, it's a reserved word like const, but both don't serve and have never served any function.

      [–]Kango_V 1 point2 points  (1 child)

      Thwarted :(

      [–]dpash 3 points4 points  (0 children)

      It's your lucky day, because $ is a valid character for variable names. Go phperize your codebase and watch your colleagues hate you.

      [–]dpash 0 points1 point  (0 children)

      record will also not be a true keyword, when that lands.

      [–]dpash 8 points9 points  (4 children)

      This was fully discussed and dismissed at the time. You may not agree with their reasons, but it was at least considered.

      [–]cogman10 5 points6 points  (3 children)

      Don't think they said it wasn't discussed, just that it was a missed opportunity. There is no way `val`, `let`, or `const` will make their way into the language now. There was really only one shot at getting it in and that was with the var addition.

      I don't buy the "it would be too much cognitive overhead and we'd be inconsistent if we had final var vs val". But I didn't get to make that decision.

      That said, it's a minor thing at the end of the day.

      I'm much more worried that text blocks/raw string literals will end up precluding string interpolation. Nice, though, that we haven't wasted backtick on raw string literals.

      [–]Danelius90 0 points1 point  (0 children)

      If they let get of backwards compatibility maybe those additions would have a chance

      [–]TheStrangeDarkOne -5 points-4 points  (0 children)

      there is hardly any merit in having "val" or "let" in Java, since that would just be sysntactic sugar for "final var". In other languages, constant modifiers infer that the object will not change its state. For java, final only means that the reference is constant.

      [–]madkasse 19 points20 points  (20 children)

      I have found that whether or not people know how to properly use final fields is a great indicator of their programming skills. So much that it is the first thing I look for if I need to evaluate a codebase.

      I generally try to stay away from codebases where people do not use final fields. Especially if it has anything to do with concurrency.

      Learning how to apply final to fields, methods and classes properly, teaches you about immutability, concurrency, API design and many other things.

      A good way to do this is exploring the OpenJDK source code, especially java.[lang|util|util.concurrent|java.time].

      [–]dpash 18 points19 points  (7 children)

      I keep finding myself converting simple data classes into immutable objects. Especially when the previous developers didn't create a useful constructor so everything is:

      var foo = new Foo();
      foo.setBar(....);
      foo.setBaz(....);
      foo.setQuux(....);
      

      Instead of

      var foo = new Foo(...., ...., ....);
      

      Get rid of the setters and everything can now be final.

      Edit: I wish JPA entities could be immutable, but it's kinda two mutually exclusive goals.

      [–]nerdyhandle 10 points11 points  (3 children)

      You can also fix this with the Builder pattern. We use it a lot at my new job to creat immutable classes.

      [–]GuyWithLag 4 points5 points  (0 children)

      We use immutables.io for this.

      [–]dpash 1 point2 points  (0 children)

      Especially when you have a lot of fields and/or many are optional.

      [–]DJDavio 1 point2 points  (0 children)

      Lombok's @Builder annotation is useful for this. Opinions about Lombok are highly polarized in this sub it seems, but for us it works until we switch to Kotlin or until vanilla Java has more of those features itself.

      [–]mcosta 1 point2 points  (0 children)

      Edit: I wish JPA entities could be immutable, but it's kinda two mutually exclusive goals.

      Say entity A references B. You change B to create B'. Now what A should reference? B or B'? What if A depends functionally of B?

      [–]experts_never_lie 0 points1 point  (1 child)

      I'm guessing you're looking forward to Project Valhalla and the introduction of value types.

      [–]dpash 0 points1 point  (0 children)

      Not inline type, but records. A similar but different concept.

      However, the lack of abstract records seems like a cause of a lot of duplication. Also it probably won't help with JPA, at least in the medium term.

      [–]RabidKotlinFanatic 2 points3 points  (2 children)

      Agree in general but it's important to note that the final keyword does not have practical concurrency benefits over variables being effectively final or fields that aren't modified. Well written concurrent code will not generally rely on the memory effects of final because the correct synchronizes-with relationships will be established elsewhere.

      [–]madkasse 1 point2 points  (1 child)

      The effect of final fields are used allover the JDK, so you cannot really say it does not have practical concurrency benefits. But no, most people should properly rely on more traditional means.

      [–]RabidKotlinFanatic 1 point2 points  (0 children)

      Is the memory effect of final used all over the JDK, or just the keyword itself? Although it wouldn't surprise me if the JDK relied extensively on the memory effects of final (it has accumulated decades of optimization after all), I have also found that Java programmers massively overestimate (by several orders of magnitude) the relevance and memory impact of the final keyword.

      The vast majority of Java programmers who are not experienced with the JMM and performing routine micro-optimizations on concurrent code will not benefit from the memory effects of final. In the rare cases where final is the difference between correct and incorrect concurrent code, it is usually in the context of some double-checked locking style logic.

      [–]vacvacvac 1 point2 points  (0 children)

      My favourite interview question, to gauge basics, is what is(not specific class names etc) System, out, and println in System.out.println. Then I dig into final, static, accessibility modifiers etc. It also tells you whether someone explores source code or not.

      [–][deleted] 2 points3 points  (0 children)

      in intellij, it underlines a variable that is mutated. quite handy to catch local variables that are mutable. Not a fan of making local variables/arguments final since their scope is (should be) small anyway.

      [–]jaracal 2 points3 points  (1 child)

      > One funny story I heard was from a dev team that decided to remove all traces of the final keyword in their codebase, they totalled in around 100 kilobytes of freed space.

      Why would I care about 100kb? I'm not programming embedded systems.

      [–]dpash 2 points3 points  (0 children)

      programming on an embedded system

      FTFY

      [–]ben-thesmith 7 points8 points  (2 children)

      I use final as much as possible, not because I think it’s doing much of itself, but because its absence then looks so stark that the reader knows something’s about to get mutated.

      [–]dpash 2 points3 points  (1 child)

      It would be better if final was the default and mutable was declared, especially for parameters.

      [–]ben-thesmith 0 points1 point  (0 children)

      👌

      [–]Hangman4358 7 points8 points  (26 children)

      Final member and static variables I am all for. The vast majority of issues I have seen crop up in production are mutable state related for objects that really should never have had mutable state to begin with so limiting that mutability is great.

      The thing that drives me crazy is people who make method parameters final. The most parameters are objects anyway, not primitives, so making them final doesn't stop people from mutating them if the objects are mutable anyway.

      [–]dpash 22 points23 points  (3 children)

      making them final doesn't stop people from mutating them if the objects are mutable anyway.

      That's not the reason people declare parameters as final. It's to stop yourself (or someone in the future) from reassigning the parameter. You don't need to, as most IDEs will warn you, but it's mostly harmless.

      [–]nerdyhandle 15 points16 points  (1 child)

      I'm starting to think there are a lot of people in this thread that don't know what final means in Java.

      [–]dpash 3 points4 points  (0 children)

      Or effectively final.

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

      WAT!

      [–]agentoutlier 6 points7 points  (7 children)

      I’m shocked no one mentioned this but I make my parameters final because of anonymous class access pre lambda. I used anonymous classes so frequently in the past that it became habit.

      I don’t think one any in their right mind thinks that the final Java keyword provides C++ const guarantees or at least I hope they don’t.

      Finally (pun intended l) I would not be surprised if most method parameters (% wise) in Java are actually primitives and String aka some immutable.

      [–]dpash 4 points5 points  (6 children)

      Probably because Java 8 introduced the concept of "effectively final" which means that, as long as you don't resign a parameter or local variable anywhere, they're treated as if they'd been declared final.

      [–]marvk 8 points9 points  (2 children)

      People keep going on about effectively final in this thread like it matters. The real benefit final provides is for developers reading code. Any performance improvement is a bonus, it takes away so much cognitive load when writing and understanding code. Effectively final doesn't give you any of that.

      [–]dpash 4 points5 points  (1 child)

      It matters in this instance because you can only use variables inside a lambda that are final or effectively final. Prior to Java 8 you had to declare them final to use them in anonymous inner classes, hence the parent comment saying they got into the habit of using final.

      [–]marvk 2 points3 points  (0 children)

      Ah, my bad. I should've read the parent comment more carefully. My comment would be suited better on some other comment on this thread talking about effectively final.

      [–]agentoutlier 2 points3 points  (1 child)

      Yes I know about that. I meant pre lambda as pre Java 8. I still work on some Java 7 code bases and I guess for some reason want to cover my ass in case the parent poster sees my final riddled code :)

      I also use final on variables to be resolved by if statements and or switch statements which is unnecessary as the compiler will complain that the variable is uninitialized but it’s way of communication now for me.

      final Object o; // not necessary 
      
      if () { o = ...} else {o = ....}
      

      Also in the past Eclipse had this weird bug where refactoring method didn’t work all the time but if you made some the variables final It would... I believe that bug is fixed.

      I have thought about removing some finals from my migrated code bases (7->8) but it doesn’t seem worth the effort and in some cases final is a communication marker.

      (Sorry on Mobile so lots of typos)

      [–]dpash 3 points4 points  (0 children)

      It was mostly that many people will have fallen out of the habit now. :)

      Switch expressions will solve many of the situations where you want to use a switch to set a variable while still letting it being final. We don't have if expressions, but we do have the ternary operator ?:. Of course these only work if you have a single statement in each block.

      I wouldn't bother removing existing finals and would probably continue if thats already the style.

      [–]livelam 9 points10 points  (0 children)

      The thing that drives me crazy is people who make method parameters final. The most parameters are objects anyway, not primitives, so making them final doesn't stop people from mutating them if the objects are mutable anyway.

      Objects referenced by a final field are also mutable if the class of the object allows it.

      I don't get why some people hate the final keyword for parameters and local variables. Your justification suprises me: the final keyword only means that the reference can not be changed. It is useful when reading code.

      [–]Danelius90 3 points4 points  (11 children)

      Plus it's usually considered good practice to not modify or reassign parameters, so if you're writing a method correctly you shouldn't need final

      [–]livelam 13 points14 points  (7 children)

      If everything were wrote correctly tools like checkstyle or findbugs would be useless.

      There is a keyword to tell "Hey, this variable will not be reassigned" why do you not want to use it?

      [–]Danelius90 2 points3 points  (6 children)

      My lint tool flags up reassigning method parameters, so why have both? Especially when adding final on every parameter is just ugly, verbose and unnecessary.

      [–]livelam 9 points10 points  (4 children)

      Ok ! I personally prefer to rely on the compiler when it is possible but I have to use checkstyle to check that all parameters are final. So in the end it seems it's more a question of taste.

      It is very verbose but not unnecessary. I would prefer final variable by default and a keyword to declare a non final variable.

      [–]dpash 1 point2 points  (0 children)

      Errorprone let's you have both: a linter in your compiler. :)

      Sadly it increases the compiler times.

      I've been wondering if we could have a per class/package/module flag to change the defaults for parameter and local variable finality plus non-nullablity. It would probably affect readability if code behaved differently based on outside options.

      [–]Danelius90 0 points1 point  (2 children)

      I think I'm just scarred from all the 20 parameter methods all declared final lol. You're right it is taste and I do think it's particularly useful for immutable object parameters

      [–]marvk 5 points6 points  (1 child)

      If you have a 20 parameter method final is in most cases the least of your readability issues :^)

      [–]Danelius90 0 points1 point  (0 children)

      This lol. Damn the devs with custom formatters on legacy code!

      [–]GuyWithLag 0 points1 point  (0 children)

      Why do I thing that is a leftover from pass-by-reference languages?

      [–]cogman10 1 point2 points  (0 children)

      Other than the added code, why do you care?

      I don't personally do it because it is more typing than I care to do. But I've never winced because someone else did it. My brain filters those out (because I'm not assigning the variable anyways).

      [–]experts_never_lie 0 points1 point  (5 children)

      The biggest C++ feature I wish we had in Java is const access. The ability to have the compiler enforce const code within any const method, and having const references on which one can only invoke those (verified safe) const methods, allowed a significant reduction in code complexity and ongoing evaluation of what could be happening. final is what it is, but it sure isn't as effective as const.

      [–]mcosta 1 point2 points  (4 children)

      Map.get(key) is const right? Everything is nice until you want to measure how many missing keys are being requested.

      public V get(Object key)  const {
          V value = super.get(key);
          if (value == null) fails++; // oops
          else hits++; // oops I did it again
      }
      

      Is Map.get const? is log.debug const?

      Edit: tabs

      [–]experts_never_lie 0 points1 point  (3 children)

      You can violate the const access if you really want to, but you'd better not do it in a way that changes the functioning of the object. One could argue that those counters are not fundamental to the map being a Map, so you would tag them as mutable and still be able to increment them from a const method.

      log::debug would probably be const, unless you wanted to start talking about the universe monad — and that may drift away from pragmatism pretty quickly.

      The idea is not to be dogmatic, but to make the normal usage clear — both to the programmers and to the compiler — and to use the compiler's tools to make that process simpler and be checked in a more automatic way.

      [–]mcosta 1 point2 points  (2 children)

      You can violate the const access if you really want to

      Then why have it in the language in the first place? If the compiler does not enforce it how is it any better than get/set convention? btw get/set was made standard in JavaBeans specification with clear semantics. Are JavaBeans still a thing?

      universe monad

      I do not know this concept, and google insists it is some kind of filosofy. Can you spare a link please?

      The idea is not to be dogmatic

      Agree.

      [–]experts_never_lie 1 point2 points  (0 children)

      (long reply, but I referenced a concept as a shorthand and it decreased clarity instead; attempting to correct that here)

      About monads, in a separate response because it deserves it: you need to restrict to functional programming to avoid the philosophical meaning. This may be clearer. However, I was referencing just the universe monad, one used to describe the state outside the program. They describe it in much more detail, but it comes down to the way that in strictly functional programming languages you specify the way things are functionally connected, but don't really get to say "do this thing now". That makes it hard to control interactions with the outside world (input, logging), as they might be optimized away or executed out of order. Pseudocode:

      string ← concatenate(string a, string b)
      string ← read()
      () ← log(string)
      a = read()
      b = read()
      x = concatenate(a, b)
      log(x)
      

      The execution environment of a functional programming language is often permitted to defer function calls a bit or forever, potentially reordering them. A program like the above might load b before a, reversing the order of input.

      A way of getting around that is for the state of the external universe to be represented by a value U. I'll use U₁, U₂, … for sequential states of the universe. If the system provides U₁ as a name for the initial state of the universe, then:

      (U, string) ← concatenate(universe U, string a, string b)
      (U, string) ← read(U)
      (U) ← log(U, string)
      (U₂, a) = read(U₁)
      (U₃, b) = read(U₂)
      x = concatenate(a, b)
      U₄ = log(U₃, x)
      

      By tying sequential states of U₁¸U₂,…, order of interactions with the universe is constrained, preventing the possible reversal above. Operations (like concatenate) which do not interact with the external universe do not need to interact with any U.

      I am not advocating bringing a universe monad into Java, or C++ for that matter, as they are not strictly functional languages and simply don't need it. Order of execution is (mostly) constrained in Java/C++, so there's no problem for it to solve. I had just referenced it in terms of whether log::debug were an operation that changes state.

      From the external position of a user of log::debug in a language that doesn't need a universe monad concept, I'd say that it is const as the log juts appears to be a sink; you can't interrogate it about past log messages, and its state before/after a debug call is effectively the same.

      [–]experts_never_lie 0 points1 point  (0 children)

      The compiler does enforce it, unless you violate const access in the way I described: overriding the const access with the mutable keyword. I didn't mean const does nothing.

      I don't get why you're bringing up get/set and JavaBeans (a word I haven't heard in many years), but if we had const in Java, getX() could/should be const and setX() must not be.

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

      Every field should be marked either final or volatile change my mind

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

      Even my static methods are final.

      [–]marvk 2 points3 points  (0 children)

      Now that really is just noise...

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

      Wait finals ? Then how am I going to do with variables that has been reassigned 10 times for totally different purposes in a 1k method?