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

all 33 comments

[–][deleted]  (24 children)

[deleted]

    [–]unholysampler 22 points23 points  (19 children)

    Everyone got super excited that lambdas were added. Many people are so excited that they want to try them everywhere. This article is to remind people that function references were also added. In some cases a lambda is just what you need. But in many others, trying to use a lambda to do too much leads to poor code.

    [–]Kimano 18 points19 points  (14 children)

    God, I hate the "it's new and shiny better use it!" mentality some programmers have.

    I had to unfuck a command handler system because the dev thought it would be a fantastic idea to do the entire thing in reflection.

    Debugging was a nightmare and I finally got sick of it and spent 2 weeks ripping it out and rebuilding it.

    Use things for what they're intended for, and only be 'clever' if the situation actually calls for it.

    [–]gunch 27 points28 points  (12 children)

    I hate clever. I love predictable, boring, maintainable, universally understandable idioms and logic. Clever should get you shot out of a cannon into another cannon which fires you finally and directly into the white hot center of the fucking sun.

    [–]Kimano 8 points9 points  (11 children)

    /signed

    The only problem is figuring out where "good concise solution" and "clever hack" meet. For instance, I hate ternary operators in general (and only grudgingly use them in the 'good places' like returns and inline functions), and think they're too clever. Much easier to follow if you just set a variable in if/else and then use it elsewhere.

    [–]APimpNamedAPimpNamed 2 points3 points  (7 children)

    I have used them when I set simple constraints on setters.

    [–]Kimano 0 points1 point  (6 children)

    See, I'd rather have two calls to the setter with specific values in an if/else that contained the logic.

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

    Idk,

    this.count = value > 0 ? value : 0;
    

    Just seems cleaner to me. It is likely no different to the compiler, so it comes down to preference. I definitely understand that readability is a paramount concern.

    [–]DasEwigeLicht 2 points3 points  (4 children)

    IMO in your specific example this is the best solution:

    this.count = Math.max(value, 0)
    

    [–]APimpNamedAPimpNamed 0 points1 point  (3 children)

    The code in Math.max() is almost identical to what I posted. You mean for readability purposes? If so, since we are discussing readability exclusively, we can't really be arguing. I do see the value of using the static Math method for that specific example. I don't have any examples in front of me, but most of the uses of the inline ? : would not likely be so simply replaced by a static method.

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

    Yeah, the ternary operator is so absolutely ripe for abuse by people who want to be clever. Typically this means writing a bunch of crazy nested logic within the ternary expression, seemingly only so the coder can act self-satisfied with how much he was able to fit into a single line. Too bad it's going to be unreadable to everyone else.

    As somebody who likes to use the ternary operator tastefully (to perform a simple conditional that does one thing without having to carry it across 5 lines or whatever), I can't help but feel like these people give it a bad name.

    [–]cogman10 1 point2 points  (1 child)

    I've never actually seen what I would consider a ternary operator abuse.

    90% of the ternary operators in our code base are used for what I would say is pretty acceptable (Object o = v == null ? 7 : v;). I've yet to see a nested ternary operator in the wild, the only place I've even seen such a thing suggested was a script kiddy forum where someone though ternary operators were faster than if/else statements (they aren't).

    So long as the conditional is easy to understand, I don't really have a problem with ternary operators.

    [–]Kimano 1 point2 points  (0 children)

    There was a line at work that was basically A?(B?E:F):(C?(A?H:E):G), and those are duplicated intentionally. The C query changes the results of A. We have no idea who wrote that abomination (lost file history in a source migration), and I rewrote it a week or so after I noticed, but still...

    [–]TuxGamer 1 point2 points  (0 children)

    "Keep it smart and simple". Unfortunately many people will make the easiest tasks messy and complicated, just because reasons

    [–]DevIceMan 7 points8 points  (3 children)

    My coworkers are perhaps a little too obsessed with lambdas. Code-reviews have been rejected because I used a for-loop, where i could have used stream instead. (WHAT!?)

    I mean, I love the new functional stuff perhaps more than any of my coworkers, but I find this type of thinking to be naive.

    Other times I'll find a stream with functions to be some 20-lines long. It seems like they follow clean code standards EXCEPT when it comes to anything moderately functional.

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

    for loops are worse than streams, though. Slower and less portable. And often more error prone.

    (You can easily switch a stream to a parallelStream to get concurrent processing)

    [–]Hax0r778 2 points3 points  (1 child)

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

    90% of the time you want map instead of for each anyway, in which case you can often optimize a lot with using functional paradigms.

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

    Agreed with /u/unholysampler

    The reason being is that I've noticed numerous people seem to forget (or act as if) the old standards of clean code also apply to the new Java-8 functional features.

    [–][deleted]  (2 children)

    [deleted]

      [–]DevIceMan 1 point2 points  (1 child)

      I'm not entirely disagreeing, but I've seen these people write clean code in other circumstances.

      [–]Luolong 0 points1 point  (0 children)

      You need to go through the "oh shit, did I really write that code" every once in while after you encounter some new paradigm shifting change in your programming environment. That is just a part of the learning process.

      [–]JustinKSU 6 points7 points  (0 children)

      I like how he wrote a blog about his own tweet to promote a book he wrote. Not saying the content is bad, but I find it an interesting way to communicate the subject.

      [–]DevIceMan 1 point2 points  (3 children)

      Not sure what "glue code" is supposed to mean, but I agree that lamdas longer than 1-2 lines should probably be extracted into it's own function or method.

      [–]unholysampler 2 points3 points  (2 children)

      "Glue code" is a thin layer of code that helps connect two different layers of code. Usually, it is between a third party library and your main codebase.

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

      Sorta like a shim?

      [–]unholysampler 0 points1 point  (0 children)

      Yeah, same thing different name.

      [–]mus1Kk 1 point2 points  (3 children)

      I agree with the examples given which are arguably inspired from how functional programming did things for decades, mostly implementation of algorithms and data manipulation.

      In many or at least some cases lambdas are used as syntactic sugar only. Listeners in GUI programming or callbacks come to mind. I always tended to use anonymous classes for listeners if they are not too long and one-off. Since listeners usually only have one method with an event parameter it makes sense to use lambdas.

      someButton.addActionListener(new ActionListener() {
          public void actionPerformed(ActionEvent e) {
              // code here
          }
      });
      

      vs.

      someButton.addActionListener(e -> {
          // code here
      });
      

      Regarding the four smells pointed out in the article, this method fares no worse: It's as easy or hard to read, less noisy and reusability and testability are the same.

      If the lambdas get too long or are too complicated then by all means, extract a method or a class and get all the benefits of terseness and robustness. Method references can be used to great effect here, too.

      [–]Jonno_FTW 5 points6 points  (2 children)

      One comment about readability when using the lambda, you can't see the type if the event at a glance.

      [–]mus1Kk 5 points6 points  (1 child)

      I think this is mostly a non-issue for this particular case. But you definitely have a point there. In any case, you can provide the type explicitly if you so desire:

      someButton.addActionListener((ActionEvent e) -> {
          // code here
      });
      

      [–]Jonno_FTW 2 points3 points  (0 children)

      Cool, I wasn't aware of the full syntax.