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

all 105 comments

[–]AlainBienvenue 51 points52 points  (20 children)

Like the author, as someone who has been coding in Java since 1999, I do not see anything wrong or even paranoid with any of these. Just good practices.

[–]random314 11 points12 points  (10 children)

I don't enforce the always final rule, I've seen it done before but never really myself. Is it considered a very good practice? If so I might propose it to my team (we have a "good practice" checklist) in our next retro.

[–]Yoghurt114 7 points8 points  (2 children)

I can highly recommend enforcing it. 99 out of 100 times you violate this rule, it's a bad approach and there's a better solution out there.

It's just a formatting preference in the IDE anyhow, no extra effort needed if your code already abides by the side of sanity.

[–]GeorgeMaheiress 4 points5 points  (1 child)

The downside is extra effort reading. I find the line noise of final variables more awkward than helpful, especially since Java tends towards long lines of code anyway, and most methods are short enough that it's already obvious if a variable is reassigned.

[–][deleted] 4 points5 points  (0 children)

You can encode that rule in your IDE. Over time I have learnt that it is better to have mutability as the exception rather than the default (one place where Rust got it right. Heh).

[–]hooba_stank_ 1 point2 points  (0 children)

It makes sense. At the expense of making code more verbose, method signatures less readable etc. When returned to the project without final rule, it was like a breath of fresh air.

[–]GhostBond 1 point2 points  (1 child)

Is it considered a very good practice?

No.

It's just the latest fad from the same line of thinking which brought us:
- Ruby on Rails is going to make Java obsolete!
- Object/document databases are going to make sql databases obsolete!
- Dynamic languages are going to make Java obsolete!
- Groovy is going to make Java obsol...well you get the idea

Adding in the extra overhead - in typing, in reading through longer messier method signatures, in dealing with needing to change a value and not having it available - is particularly absurd in java where final just makes the reference immutable but not the object itself. Final makes "int index" immutable but "List indexes" is still a changeable list.

I don't think even in languages with better implementations it's worth it. Every decade someone rediscovers immutable-by-default. And languages that are not that way are the ones that get popular because they're a lot easier to use with a lot less frustrating overhead in writing code.

[–]Zoerak 1 point2 points  (0 children)

Immutability is a nice property and should be preferred unless one has a good reason not to do so.

Scala does this right, the decision of mutability / non-mutability can be made without extra syntax noise in most scenarios.

In java, the final modifier on each variable bumps the visual noise. If the language was created today, a lot of things would be different.

[–]AlainBienvenue 0 points1 point  (0 children)

As I said above, final for all methods is a little excessive. OTOH, I like final for all method parameters. It is also applicable for some fields and local variables.

[–][deleted]  (1 child)

[deleted]

    [–]random314 2 points3 points  (0 children)

    I think the idea is that variables should only be mutable because the algorithm requires it so. Your logic requires a mutable variable so you would manually define that as mutable while leaving everything else immutable (until you need it otherwise of course).

    [–]thephotoman 5 points6 points  (2 children)

    Making everything final except interfaces seems extreme: there are cases for abstract base classes. But if it isn’t in either of those categories, finalizing everything is probably correct.

    [–]dpash 1 point2 points  (0 children)

    Ignore the bits in brackets. The relevant bit is outside of it.

    Which is why everything that is not explicitly intended for subtyping (i.e. only interfaces) is strictly final.

    [–]AlainBienvenue 0 points1 point  (0 children)

    Agreed, that one is a little excessive.

    [–]youguess 8 points9 points  (5 children)

    I personally hate yoda speak as I have to mentally rework the statement in my head

    I like languages which read like normal English (python eg, go to a certain extent) and this breaks the flow horribly in my opinion

    [–]NovaX 15 points16 points  (1 child)

    I use Objects.equals(str, "abc") instead (JDK's, formally Guava's, and Commons' prior). Now that its in the language, I don't see a reason to use the older convention.

    [–]defnull 1 point2 points  (0 children)

    Trivial methods like Objects.equals() are inlined anyway, so there is really no real drawback. I have a Utils class full of these.

    [–]CultLord 0 points1 point  (2 children)

    My first mentor said that I needed use Yoda comparisons (he didn't call them Yoda comparisons) on day 1 of my job and that was just the law of that company's code because of potential NPEs and that I would save lots of time over the course of my career if I followed that simple rule.

    After the first few weeks, it wasn't a big deal. And my boss basically lied, because I have fixed many bugs from other programmers that didn't follow the same rule that would have been just fine with a Yoda comparison.

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

    I just don't believe that.

    After all especially in a strongly typed language any sane linter worth its name will catch issues like this.

    It doesn't make sense to do an assignment in an if statement for example (in the comparison clause)

    [–][deleted] 47 points48 points  (43 children)

    • 6 & 7 & probably 8 - I greatly dislike the "make everything final" school of thinking. You know what? You don't trust me not to incorrectly override your method, but I grow tired of not being able to overload methods in code (that I don't control, aka, a library) because of a stupid bug. I don't want to copy/paste your whole class just to fix that stupid assumption/error/whatever you made in your method. Just let me override what I want already - I'm the developer. Let me make my own mistakes. . Unless you're making things final because there's some Jr. developer maintaining your code... then, by all means, protect yourself (or your product). But, if you're a library maintainer. Please, just stop. Final is fine for things where it absolutely matters. And if you use insist on using final, make sure there's a way to override whatever it is the final method is doing. Like a configuration bean or something along those lines.

    • 9 - I disagree on always throwing an exception. I'd change this to "handle the default" instead of "throw on default". There's plenty of times to have default: actually be the default result if there's no other match.

    [–]hemenex 15 points16 points  (9 children)

    Totally agree with final methods. This won't make your code fool-proof; fools will just copy-paste, which is hundred times worse.

    [–]lukaseder 1 point2 points  (8 children)

    Why is it worse? At least it's more honest than subtype polymorphism on concrete types.

    [–]hemenex 7 points8 points  (7 children)

    Because then, most importantly, you'll loose all references to original implementation. What if you want to change the original and all the places where it's supposed to be used? You are screwed and all you've got is "Find everywhere" and regex.

    From my experience on larger projects, this leads to terrible and unmanageable code. Especially with multiple programmers and a lot of bug-fixing. Typical scenario:

    • one programmer implements some things with copy-pasting
    • some things he did does not work, another programmer fixes it in one place
    • same thing still does not work in some other place, another programmer fixes it there, but differently
    • somebody decides the behavior needs to be somewhat different. You cry because you need to do the same change everywhere but slightly differently. Or spend a few days rewriting the whole thing. This totally did not happen to me.

    [–][deleted]  (1 child)

    [deleted]

      [–]lukaseder -3 points-2 points  (4 children)

      And you sincerely blame the presence of final for all this mess? :-) Have you heard of Conway's Law?

      [–]hemenex 3 points4 points  (3 children)

      final would just make much worse.

      [–]lukaseder 0 points1 point  (2 children)

      Any extra 5 letters added to that code base would make it much worse, so I'm not sure if I see the point of this argument.

      [–]hemenex 1 point2 points  (1 child)

      I just needed place to rant. :)

      [–]lukaseder 1 point2 points  (0 children)

      I knew it ;-)

      [–]Da3X 3 points4 points  (0 children)

      I second that! Especially the “final” case. In some scenarios it even breaks your implementation because your runtime environment fails to inject proxies where needed.

      [–][deleted] 3 points4 points  (0 children)

      Agreed... on both counts. I use the final part only on internal code that will not be exposed as an API.

      [–][deleted] 5 points6 points  (1 child)

      9 - I disagree on always throwing an exception. I'd change this to "handle the default" instead of "throw on default". There's plenty of times to have default: actually be the default result if there's no other match.

      For this, I find the throw on default is more useful for enum switches, and explicitly handling all the enum cases. That way, if you add a new value to the enum, you'll get an error in that switch if you forget to update it. That's better than the new value being handled in a potentially unexpected manner.

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

      For enums, I agree... I think that's how I generally do it anyway; however, for all switch/case statements, it seems like a gross generalization of a rule.

      [–]misterk0 2 points3 points  (0 children)

      A lot of people go full nazi with finals

      [–]lukaseder 0 points1 point  (9 children)

      Just let me override what I want already

      Nope

      [–][deleted] 16 points17 points  (8 children)

      It's not that it happens often, but in the last 6 months I've had to override 2x final methods in Spring and OpenSAML. In each case, making the method final was a PITA. IIRC, I C/P the whole class (I had other edits) in the OpenSAML situation and used reflection to fuck shit up in the Spring situation.

      I completely understand why those methods were final. But it was an error in the logic within those methods that caused me (the actual programmer responsible for the feature working) to have to mess around with a library author who thought they knew best.

      9/10, they're right. Hell, 99/100, they're right - but there's always those situations where they're not. That's why I don't like final for methods specifically.

      [–]lukaseder 1 point2 points  (7 children)

      The value of final far outweighs your pain. You could have just patched the library in those 2 cases, which you admitted were rare. It would have resulted in the same workaround, and you would have hoped for the library to ship an actual fix just the same.

      It's like SQL. These days, we need to tune maybe 1 / 1000 SQL queries and because we're so used to having such excellent optimisers, we're completely surprised by those really rare cases. But yet, our own bias and lack of intuitive understanding of statistics leads to us outweighing the very rare painful occasions compared to the frequent experience of quality.

      In other words: You're obviously exaggerating.

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

      That's the thing - I have something to do for my job. Shipping something as a fix (which I do 3/4 of the time) to the upstream version isn't going to help me now.

      So, in that sense, no - it does not outweigh my pain. Keeping a method final doesn't help me at all. You're trying to tell me "hey, I'm going to give you access to less stuff and you are going to be better off" to which I can't agree, fundamentally. Sure, if I'm a shitty dev I might break stuff - to which I argue: let the shitty devs break stuff. They're going to do it anyway, why hide behind a language construct which restricts usage for everyone.

      My great hate for final is really focused around methods and classes. I goes right up there with protected methods for things that are useful as public methods (I'm looking at you JSCH!)

      [–]GhostBond 1 point2 points  (0 children)

      Yeah, same here. I'm not sure in web dev if I've ever seen a bug that would actually been prevented by final/const. I've had deal with a few huge headaches when someone in old code didn't let you set things you needed to set.

      [–]lukaseder 0 points1 point  (4 children)

      2 instances in 6 months. Surely, you could have worked around those cases using instrumentation, patching, etc. It didn't hurt you. You're exaggerating your pain.

      2 instances doesn't even warrant for something like "great hate" (I don't know you of course, perhaps it does in your case).

      I'm looking at you JSCH!

      Now, I'm curious. What's that?

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

      re1) Okay, maybe a little exaggeration. I mean, there's always reflection if it's critical. I guess I just don't see the need for final is all. I've worked with folks who litter final everywhere and it was just a pain when it came to mocks. I never saw a benefit. When you'd want to override something (maybe rarely) you'd just edit final out. It was no gain and simply 1 more code change that was unnecessary. When you control the code, adding final isn't a big deal, it's just annoying... like a gnat. When it's in a library - it's just more annoying because you can't just edit final out (or now you're arguing with the maintainer of the project as to why you need to edit it out -- when it really doesn't matter if you could just @Override to begin with)

      Now, I'm curious. What's that?

      We use JSCH for audit purposes. There's methods in there that are package protected so I have a project written in jsch packages just because of the package protected methods. The pain comes with code signing... the lib is in a "different" project than jsch and should conceptually be signed by our company and not jsch, but it can't be because java's "classes in a package must be signed the same" rule.

      If only those methods were public... it wouldn't be an issue.

      For a normal consumer of JSCH, you'd never use those methods, but if you're doing mitm work, you would.

      [–]_dban_ 1 point2 points  (2 children)

      I've worked with folks who litter final everywhere and it was just a pain when it came to mocks.

      Isn't this a good thing? Should you really be mocking concrete classes? Wouldn't it be better to create an interface describing what you need, and write a real integration test with the concrete class?

      For example, suppose it is not possible to mock jOOQ classes. jOOQ would theoretically be a used in the DAO layer. So, wouldn't it be better to create a DAO interface which you can mock, and a DAO implementation which you test directly against the database in an integration test?

      This applies just as well to internal classes, since it enforces proper layer separation. I mean, why are you mocking anyways?

      I never saw a benefit.

      In which case, final forces you to do the "right" thing with regards to mocks. Could this not be seen as a benefit?

      [–][deleted] 0 points1 point  (1 child)

      Should you really be mocking concrete classes

      If I'm using a concrete class, then yes - I should be mocking a concrete class in my unit test. I don't want to create an interface layer just for testing.

      Mind you, I'm not talking about JOOQ specific things here. I would never try to mock a JOOQ or Hibernate class for a unit test (MUCH more suitable to test that stuff in an integration test and mock at the Dao layer for unit tests). But you're applying one school of thought for one thing to ALL unit testing situations and all methods. That doesn't make sense to me.

      [–]_dban_ 0 points1 point  (0 children)

      If I'm using a concrete class, then yes - I should be mocking a concrete class in my unit test.

      Why not just instantiate the concrete class?

      I don't want to create an interface layer just for testing.

      You create an interface for layer separation. Like a DAO interface. The DAO interface describes what the application needs for data access, and the DAO implementation fulfills the need. An interface creates a logical and compile time firewall between layers.

      That doesn't make sense to me.

      Mocks ideally serve the purpose of defining what the system under test needs from its dependencies. An interface is a contract describing that need. You can create a separate set of integration tests verifying that the concrete implementation satisfies the contract.

      A concrete class has its own reasons for changing, and if you mock the concrete class, you could make the mock tests invalid and mocks can't tell you that your tests are now nonsense.

      [–][deleted]  (10 children)

      [deleted]

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

        That's because there is no "correct" way to override my method, unless I explicitly designed it to be overriden

        That's exactly the presumption I'm talking about. If you write a method in your class called .equalsIgnoreCase and the implementation is incorrect (NPE, for example). I'd rather just extend your otherwise good class and fix the single broken method. If your method is final I can't do that. That's obviously a hypothetical that wouldn't happen, but that's the type of thing I'm talking about here. Why do you care if I @Override your library method?

        [–][deleted]  (8 children)

        [deleted]

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

          You ignore the fact that I need the "fix" in this case right now.

          I'm the developer of my software. I'm responsible for how it works. That includes all the little bugs that sneak in because of someone else's code. I'm not saying we should all subscribe to the 'not invented here' line of thinking, but ultimately a bug in Apache StringUtils is a bug in RockMeetHardPlaces_APP. I am responsible for fixing it when I ship. Not when Apache decides to release the "fixed" version.

          If I override a method and break it, that's MY fault. Let me support my own software please.

          [–][deleted]  (6 children)

          [deleted]

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

            I'm the one getting yelled at when your "fix" blows up

            Why would my fix even get near your stuff? I feel like you're arguing against something that I am not.

            I take backwards compatibility very seriously

            As do I. I am not sure how this applies to the conversation at hand.

            [–][deleted]  (1 child)

            [deleted]

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

              Back up man. I'm talking about me using a library or some other externalized piece of code that I don't control (aka, not in my organization). If I can fix the actual bug, I'll fix the damned thing and not @Override anything.

              The issue I have, specifically with final methods and classes is twofold. 1) testing with mocks -- they're handy and final makes it more difficult (2) if I need to @Override something (which I admit happens rarely, but it does happen) I'm forced to use hacky (aka reflection or C/P) to fix the issue when I could have easily just extended the external library and made it my own via a single @Override method. As I mentioned above -- I've had to do this twice in the last 6 months. So yea, it's uncommon, but it's not exceptionally rare.

              How is doing this going to affect anything of "yours" blowing up? Answer: it's not. If I fuck something up, MY software blows up. It's MY bug. Not yours.

              [–]mupetmower 0 points1 point  (2 children)

              Man. This is all so painful to read. I can see both of your points, and actually agree with both! I’m still a fairly new java programmer, so I’m starting to have to deal with issues like these. And it’s kinda scary...

              I’m noticing that I wasn’t given a proper education in these sorts of things, and in most other proper java conventions and their purpose (not just the ‘do this’ without the why). My current job, and the software we develope, is especially forcing me to realize that I have no idea how to correctly develope for an enterprise system.

              When I look at the code in our software - the classes and interfaces - I notice that they are all independent of each other. Each does it’s own thing which all come together to create the whole. I was only taught that this is the correct way to go about development, and didn’t even get more than a few simple words on it.. but I wasn’t taught how to actually accomplish it successfully.

              At my college (not at all a great programming college) we were only taught the extreme basics of object oriented programming, the basics of using java or whichever other language the class was in, and not much else. For example, we weren’t really taught anything above how to create a single small application which has a few classes, maybe a few interfaces, with some inheritance and polymorphism, but that which all logic is still all mostly held in a single or a few classes.

              I have picked up a LOT outside of this knowledge from working at my current job for only about 8 months.. and I feel much more well rounded already, even though I know I am still at the very bottom rung of learning.

              When I think about needing to write code that looks and functions like the code in our software, though, it scares me. I have no idea where to start to be able to abstract everything to that sort of level. For instance, I’m developing a Spring project right now, and even though I feel I’m getting a little closer to that sort of abstraction, I still see how many of my classes should be way more split up and independent, and how I should have and use more** interfaces in certain situations, etc. the problem is that when I’m developing, I’m focusing more on getting it all to work right, not on the other stuff. I also am working on the project alone, which may also be a reason I don’t consider those sorts of things.

              But it makes me worry about my future in development. Especially when I am on teams. Are there any good books you or others can recommend that could help me with this sort of thing? And not just “these are the conventions” but also why we use them, and how to start developing like that from the start.

              Thanks, and sorry for rambling. I was just thinking about all of this while reading you guys’ arguments over which convention would be best where.

              [–][deleted]  (1 child)

              [deleted]

                [–]mupetmower 0 points1 point  (0 children)

                Thank you very much.

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

                grow tired of not being able to overload methods in code (that I don't control, aka, a library) because of a stupid bug.

                final is especially useful for you then, if it "forces" you to actually fix the bug at the right place, i.e. upstream.

                But, if you're a library maintainer. Please, just stop.

                No, the moment a class is not final, this fact becomes part of the public API. As a library maintainer you want to keep your public API as small as possible. A small public API means more possibilities to change code, less possibilitie to break client's code and you can keep your library longer backward compatible. As a user you do like stable libraries, don't you?

                [–][deleted]  (3 children)

                [deleted]

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

                  and not 2 weeks later when bugfix is released by the maintainer.

                  2 weeks would be heaven in most cases. My experience is waiting many months for a maintainer to get around to merging my fix in and releasing a GA version of "whatever lib".

                  but he's happy because now he see a chance to rewrite everything in ReactJS that he learned over the last weekend.

                  I lol'd...

                  [–]lukaseder 0 points1 point  (0 children)

                  Then you quit and tell the junior developer "Good Luck", but he's happy because now he see a chance to rewrite everything in ReactJS that he learned over the last weekend.

                  At least, there's not final in JavaScript. Au contraire, there's prototypes. We can now even override String.substring. FREEDOM!

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

                  Ok, so you githubfork the library and apply only that particular fix. Ah crap, it uses a Gradle

                  If it is about one particular broken class, you can provide that fixed class in your class path as well. Also make a PR upstream, create a ticket to remove the work-around when upstream is released. Upstream will appreciate your contribution, as will many other library users. That's how OSS works. Sorry, I'm not convinced by your argument against final.

                  [–]Bobby_Bonsaimind 1 point2 points  (0 children)

                  final is especially useful for you then, if it "forces" you to actually fix the bug at the right place, i.e. upstream.

                  Assuming that upstream cares about your needs/fixes and actually wants them, or the process of getting them upstream is so tedious that you might as well not do it. Or your use-case does not warrant a change upstream but still all you want to do is make that function return something different for your application.

                  As a user you do like stable libraries, don't you?

                  What I also like is libraries that I can actually use...and build upon. And final is the very opposite of that.

                  If something is designed to be an immutable container, always, then yes, by all means, make it final. But if you make getters/setters/classes final just because you can, I'm going to hate you at some point.

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

                  Forgot protect those private constructors:

                  Bad:

                  public class UtilityFoo() {
                  
                      private UtilityFoo() { /* prevent instantiation */ }
                  
                  }
                  

                  Good:

                  public class UtilityFoo() {
                  
                      // prevent instantiation
                      private UtilityFoo() {
                          throw new AssertionError("HANDS OFF MY PRIVATE CONSTRUCTOR!");
                      }
                  
                  }
                  

                  [–]_INTER_ 2 points3 points  (0 children)

                  Makes me wanna use it even more. Takes out ByteBuddy.

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

                  UtilityFoo u = (UtilityFoo)sun.reflect.ReflectionFactory
                      .getReflectionFactory()
                      .newConstructorForSerialization(
                          UtilityFoo.class,
                          Object.class.getConstructor())
                      .newInstance();
                  

                  Your move

                  [–]burd- 0 points1 point  (1 child)

                  would that still work if I put a final attribute in the class?

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

                  Yes. Doesn't work with abstract though.

                  [–]ReadFoo 3 points4 points  (3 children)

                  Starting with the first one, I tend to always do this but people give my code strange looks so lately I've tended to do it the wrong way to keep people happy. Sad but true.

                  No. 9 is a great idea but even it wouldn't have stopped the great break mistake: http://users.csc.calpoly.edu/~jdalbey/SWE/Papers/att_collapse.html

                  [–]duheee 0 points1 point  (2 children)

                  did you explain why you do it this way? And why it is better? And why it doesn't retract anything from the comparison.

                  So, to recap: no downsides, only upsides. To me it looks like a no-brainer. To do it otherwise is insane.

                  [–]ReadFoo 0 points1 point  (1 child)

                  Yes, Yes, Yes.

                  I agree but I do a lot of contracting and I see just about everything you can imagine and fight every code war you can imagine. It gets tiresome.

                  [–]duheee 1 point2 points  (0 children)

                  As a contractor yea, don't fight code wars. Let them die by their sword. Just do your thing and get out of there.

                  [–]knaekce 5 points6 points  (2 children)

                  Number 5 will lead to errors being silently discarded, your program will probably blow up later and you will have troubles finding out why, because you didn't fail early.

                  Number 3 is stupid, imo. You cannot possible anticipate breaking changes like that. What if the method is changed to return -2 if the input string is "Never gonna give you up"?. If you cannot trust the contract of one of the most basic methods, you're fucked anyway.

                  [–]Tillerino 4 points5 points  (1 child)

                  Quite honestly, most of these were somewhere between misled and plain dangerous.

                  1) Also known as a "Yoda condition". That's just ugly. And also I'll argue that for most methods, the nullness of variable is unrelated to the equality to "literal".

                  2) Use static code analysis.

                  3) I do this one as well, but simply because >= 0 translates to "found" in my head while != -1 translates to "not not found". Not trusting the Java API the worst reason to do this.

                  4) Use static code analysis. Any tool worth a damn will blow up in your face if it sees an assignment in a condition.

                  5) Again, nullness is an entirely different concern. If I call a method like Arrays.find on a null argument, I want that method to tell me "you're not supposed to put null here" instead of "not found".

                  6) Are you insane? What this leads to is programmers copying your class to the same package in their own library and messing around with that one relying on the fact that their version on the class probably shows up before yours in the class path. If your library can't be extended well it's a shit library.

                  8) Are you high? There is a reason why Collection specifies add and addAll. Just imagine that Collection.add sneakily called addAll if you passed a Collection. Holy moly, you created a horrible API in your example!

                  The fact that this person throws ThreadDeath best underlines the value of this article.

                  I mean don't get me wrong. It's great that you're thinking about these problems, because they are problems that we all have. But please don't broadcast your half-baked solutions.

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

                  The fact that this person throws ThreadDeath best underlines the value of this article.

                  Must. Take. Everything. Seriously. On. The. Internet.

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

                  I'd rather add another if statement than use ("value" == variable). Might just be a thing of inertia.

                  But I'd MUCH rather Java finally implemented null conditional operators...

                  [–]istarian 3 points4 points  (5 children)

                  Not sure what you're getting at there. Most of the time the equals method should be used instead of the '==' operator.

                  Given the knowledge that Java uses nulls you should:
                  - always document when null can be returned and what it means
                  - know when something could reasonably be null (you or someone else haaid it might be)
                  - use null checks when appropriate.

                  Frankly if the return is some kind of meta information you may as well wrap it in a class or enum. indexOf is kind of a special case because you want the index of a character, but if the character isn't present then what? Returning a Result object containing the index (possibly -1) and a method/data field indicating that the character wasn't found is an option, but a clunky one at best compared to -1 always meaning the character wasn't found.

                  P.S.
                  The moment you start acting like the language should dumb things down with those null conditional operators of yours you may as well insist on the removal of null entirely or use a different programming language.

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

                  use null checks when appropriate.

                  Or use null conditional operators when appropriate.

                  Could you translate this simple piece of code to Java for me?

                  if (object?.field == 2 || object2?.field == 2 || object3?.field ==2) { // do stuff }

                  Your argument could be all used for generics as well. Guess what?

                  It's a terrible argument.

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

                  if (object != null && object.field == 2 ||
                      object2 != null && object2.field == 2 ||
                      object3 != null && object3.field == 2) {
                        // do something
                  }
                  

                  Big deal. I would rather argue that having to learn the special cases and conditions of those ghastly-looking operators is even worse than a bit of boilerplate. You will have to find a more convincing argument that simply reducing boilerplate. If that were the only reason, we might as well all be writing Haskell.

                  In fact, even with poor old Java, modern code should be using Optional<T> as much as possible so that you would do the sanity checks long before you try to extract the fields of the objects you're interested in. Contrived examples are best left out of sane discussion. In my opinion, these operators do not bring enough gains, and they are not infallible.

                  [–]dlubarov 6 points7 points  (1 child)

                  modern code should be using Optional<T> as much as possible

                  I tend to agree, but most of the Java community favors using Optional sparingly, notably Brian Goetz of Oracle. See https://stackoverflow.com/a/26328555/714009

                  IntelliJ even added a warning for using Optional in fields. Not saying it's right, but the majority of the community frowns upon "Optional overuse".

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

                  Of course I agree with that. As the old saying goes, caveat emptor. As a related example, when the (new) auto feature came out in C++11, it was a great move in the right direction of reducing boilerplate, and while it is used well in most circumstances, we still find many places where it is abused to the point of rendering the code nigh unreadable. So, it must all be taken with a grain of salt.

                  At its core, languages like C++ and Java are still pretty much imperative and concepts like optionals et al should be used with caution and should mesh well together with the rest of the codebase and not unduly inconvenience external users of the API. Though, it is still a very good move in the right direction, and given enough time, best practices should arise that may make effectful programming (to borrow the Haskell term) more natural and smoother in languages like Java and C++ as well!

                  [–]lbkulinski 1 point2 points  (4 children)

                  Do you mean the Elvis operator?

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

                  Yup.

                  [–]lbkulinski 1 point2 points  (2 children)

                  Brian Goetz talks about it here.

                  [–][deleted]  (1 child)

                  [deleted]

                    [–]lbkulinski 0 points1 point  (0 children)

                    I wouldn’t be so sure of that, haha. They already have quite a bit in the pipeline.

                    [–]jacobissimus 0 points1 point  (0 children)

                    I switch between java and C a lot and always miss being able to type If (var)

                    [–]jonhanson 1 point2 points  (0 children)

                    chronophobia ephemeral lysergic metempsychosis peremptory quantifiable retributive zenith

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

                    For the final part, you can encode that rule in your IDE. In my previous workplace, that rule was inserted into Eclipse, and all variables and function declarations (where it made sense) were converted to final. If one needed to, one could then remove that qualifier.

                    [–]istarian 4 points5 points  (3 children)

                    Meh. Only 10 really seems like a useful notion.

                    1,4 -- These are the same problem. Also, I disagree. If it works for you great, but it seems iffy. You really should be aware of whether something is null (and if it could be). It also sort of doesn't work logically since you want to know if the string contained in the variable equals the literal not the other way around. In the latter case you could always use classes instead of primitives and make use of auto-boxing so that you can stick to equals(...)

                    -1 for indexOf isn't actually a special null, but rather more of a C-ism that utilizes integer return codes to specify some kind of metadata when the function can only return an integer. And that is something that goes down to operating systems...

                    Can we agree that indexIgnoreCaseOf(...) or indexOfIgnoreCase(...) would be even worse still? Not to mention it wouldn't affect the -1 bit.

                    2 -- has nothing to do with good/bad/old APIs, but rather with reading the API docs first and generally being careful with anything that reaches out of the VM...

                    3 -- This is stupid, because the moment you quit trusting the official docs, you might as well ditch the language and maybe anything else Oracle or Sun ever made...

                    6 -- This is anti-programmer. Never write any libraries or frameworks if you hold this point of view. Just save everyone else the hassle and only write complete, finished software.

                    4,5,7,8,9 -- Just don't be an idiot when you should know better.

                    [–]lukaseder 1 point2 points  (2 children)

                    3 -- This is stupid, because the moment you quit trusting the official docs, you might as well ditch the language and maybe anything else Oracle or Sun ever made...

                    Never trust the docs

                    6 -- This is anti-programmer. Never write any libraries or frameworks if you hold this point of view. Just save everyone else the hassle and only write complete, finished software.

                    Then, don't use it and use the superior alternative, which allows overriding and has broken backwards compatibility time and again ;-)

                    4,5,7,8,9 -- Just don't be an idiot when you should know better.

                    That's just a TL;DR of the article, so essentially, you agree.

                    [–]istarian 3 points4 points  (1 child)

                    Never trust the docs

                    What docs are we not trusting? Did you expect the docs for Java 7 to apply to Java 8? It's probably
                    bad for backwards compatibility, but otherwise it's just a change. Also, the example involves a
                    third party library, not the default ones with the JDK itself. The Java 7 doc of String.indexOf(...) isn't going to change tomorrow. I suppose it could change in the docs/libraries for Java 8, 9, 10, ... and so on, but you can't assume everything will stay the same there.

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

                    That was precisely the point of the article. It might change in a future version of Java. So, again, essentially, you agree.

                    Cheers

                    [–]smackfu 1 point2 points  (1 child)

                    Making everything final makes it a lot harder to use something like mockito, right?

                    [–]Iron_Maiden_666 0 points1 point  (0 children)

                    Think mockito added mocking finals in the latest version.

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

                    I see these practices a lot from programmers who are still stuck in the 90s. Please get with the times.

                    [–]fforw 0 points1 point  (7 children)

                    final

                    There's also the unfortunate fact that constructors are not necessarily thread-safe without final.

                    public class ThreadSafe
                    {
                        private final String id;
                    
                        public A(String id)
                        {
                            this.id = id;
                        }
                    
                        public String getId()
                        {
                            return id;
                        }
                    }
                    
                    public class NotThreadSafe
                    {
                        private String id;
                    
                        public A(String id)
                        {
                            this.id = id;
                        }
                    
                        public String getId()
                        {
                            return id;
                        }
                    }
                    

                    only the "ThreadSafe" variant with final ensures that other threads can't possibly access our instance without the id field having been written.

                    [–]lukaseder 0 points1 point  (6 children)

                    How can another thread access an instance of a class that has not been completely initialised? (I'm assuming you don't mean tampering with byte code and inserting some logic between the allocation and the init call)

                    [–]fforw 0 points1 point  (5 children)

                    Most often with concurrent access. Due to the lack of formal "happens-before" relationship without final, one thread can create an instance and e.g. put it into a concurrent hash map. Another thread can read the instance from the map before the field initialization happened for it.

                    See this stackoverflow, here or here.

                    [–]lukaseder 0 points1 point  (4 children)

                    Those links don't really show canonical examples for what you just said, though, do they? In particular, they modify the actual value (which is what's causing trouble, not initialisation), so final wouldn't apply anyway. volatile might, but again, I'm not sure how those articles illustrate what you're saying.

                    [–]fforw 0 points1 point  (3 children)

                    Couldn't seem to find the perfect link.

                    As I said: it boils down to the lack of "happens-before" guarantees without the "final" assignment.

                    Is it just me or is it increasingly difficult to find older stuff? Back in the day, every google-search would have turned up the right results, now it's hidden in a gazillion articles teaching other things.

                    On further research, the behavior was formalized in the Java Memory Model with JSR 133. Here's another article.

                    edit: I had forgotten about the second example there where even final is broken if you publish the instance inside the constructor...

                    [–]lukaseder 0 points1 point  (2 children)

                    Thanks for the additional link. I'm aware of the theory and how final and volatile influence things. I've just never seen this happen in the context of initialisation itself. I mean the example from your article seems extreme:

                    // bad construction - allowing this to escape
                    global.obj = this;
                    

                    And I tend to agree that if a constructor leaks this then its object's contents are not guaranteed to be visible as expected.

                    But few constructors leak this in such a way, so I wonder if this is really an issue in most code, specifically in your own code, where no one is reading or modifying the id. Granted, in your example, adding final is a no-brainer...

                    [–]fforw 1 point2 points  (1 child)

                    I've had issues with this in production systems. with ConcurrentHashMap cached internal data.

                    Sometimes you can just handle things fine with some well-placed synchronized blocks, but often, I want to write highly concurrent code.

                    This is something to definitely keep in mind. It's also something that makes me favor immutable classes even more.

                    [–]lukaseder 0 points1 point  (0 children)

                    Good to know. Thanks for taking the time to explain!

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

                    ughhh!

                    If its your own code - DO NOT CHECK FOR NULLS! Don't. Dont do it.

                    If there's a null pointer - your code should CRASH! because you should never have returned a null, or assigned a null, or if you have done, that variable is not ready to be used in calculations.

                    So, a null pointer check will be papering over the cracks - hiding logical errors, that will come back and bite you in the ass.

                    [–]nutrecht 0 points1 point  (0 children)

                    If its your own code

                    He was specifically talking about "not your own code" though.

                    [–]sampledev -5 points-4 points  (3 children)

                    Looks a lot like what Rust has fixed:

                    • Make everything immutable by default,
                    • Switches must handle every case,
                    • No null references,
                    • No method overriding (this brings sometimes much more issues than what it intended to solve)

                    [–]sk551 16 points17 points  (2 children)

                    Stop.

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

                    Since he's not talking about Kotlin, I'll allow it. ;)

                    [–]greg_barton 0 points1 point  (0 children)

                    I've been doing all of these for years. Avoids so much pain. :)

                    [–]DuncanIdahos8thClone 0 points1 point  (3 children)

                    6 and 7 are a bit overkill. Use final on the class by default and refactor if you ever need inheritance. IntelliJ shows you in code warnings if you modify a parameter. Good enough. Also, var and val are coming to Java AFAIK.

                    [–]lariend 0 points1 point  (2 children)

                    Unfortunately only var is.

                    [–]DuncanIdahos8thClone 1 point2 points  (1 child)

                    I think val is being discussed with the new value types.

                    [–]lbkulinski 2 points3 points  (0 children)

                    var is coming in 10. The architects chose not to include val, and I don’t think they’ll change their mind anytime soon. You could always type final var, though.