Imagine a bacon-wrapped Ferrari. Still not better than our free technical reports.
See all our reports

How to avoid ruining your world with lambdas in Java 8

exploding-lambdas

The code and the beast

Amid the hysteria over the upcoming lambda expressions in Java 8, I started noticing how I haven’t really seen anything critical of Project Lambda in the many months since their introduction into the language was made public.

In reality, these already well-known lambdas are only spoken of positively–namely at conferences, in talks and generally around the interwebz–as a net benefit for Java. But are they really as wonderful as an awesome bacon-cheeseburger after a long day? And will you ask for more lambdas if you are required to use them in your daily work?

Let’s jump right in with some wonderful lambdas in our code right now:

public class RuinLambdas {
    public static void main(String[] args) {
        // Easy
        startDream(new Dream() {
            @Override public void dream() {
                // Dream boy, dream ...
            }
        });
 
        startDream(new AugmentedDream() {
            @Override public void dream(String dreamName) {
                // Dream boy, dream ...
            }
        });
 
        // Less easy
        startDream(() -> { /* Dream boy, dream ... */ });
 
        // And now kid ? ...
        startDream((dreamName) -> { /* Dream boy, dream ... */ });
 
        // Do you see which one it is directly by reading this ? ...
        startDream((dreamName, duration) -> { /* Dream boy, dream ... */ });
    }
 
    public static void startDream(Dream md) { md.dream(); }
 
    public static boolean startDream(AugmentedDream ad) {
        ad.dream("Ruin lambdas");
        return true;
    }
 
    public static boolean startDream(ThisIsNightmare hahaha) {
        hahaha.sufferMyKid("Hahaha you're going to hell", 2000);
        return false;
    }
}
 
interface Dream {
    void dream();
}
 
interface AugmentedDream {
    void dream(String dreamName);
}
 
interface ThisIsNightmare {
    void sufferMyKid(String dreamName, int duration);
}

So this is what we have:

  • Three interfaces for having nice dreams
  • A class with three nice methods for starting wonderful dreams
  • A main method that is a nightmare :)

What do we think/code/enjoy/understand?

Looking at the part that is commented is easy and readable. Here is what we can tell from that:

  • Looking at each method’s call we know directly which interface is used
  • Looking at each call we know which methods are implemented
  • The code is directly readable without interpretation
  • A developer that reads the code doesn’t need to know the code very well
  • A junior developer joining the team isn’t lost in the desert without water and cheeseburgers

And for the next lines using lambdas? Well, I won’t put more bullets because they will be the exact contradiction of previous points above.

Indeed, things are less readable by most human programmers that don’t know the code well. You could argue that one only has to look some lines below and I would have all my answers. Well, yes and no. In this particular case, yes, but life isn’t as easy as driving your bacon-wrapped Ferrari on an empty highway. But why is that?

Who could hate a lambda?

It’s tough being a lambda. I consider lambdas as human unreadable and hard to use. Let me ask you this: Do you have such simple projects with everything in one class? Do you have to maintain code that is months or weeks old? Code you haven’t even written yet?

In real life, you use Maven or Gradle-based projects for managing dependencies. Usually you use an IDE in order to develop your applications right? These are just two reasons it is not that easy to use lambdas.

Dealing with lambdas and dependency management

You don’t always have the source of the libraries you are using. When you have such a concise syntax like lambdas, you just have to navigate through the API documentation. When you don’t really know the library you’re using, you might need to spend some quiet hours understanding what is going on. And the syntax doesn’t help you figure out where and what you’re looking at.

Dealing with lambdas without an IDE

We have it good with the wonderful Ctrl + click feature of IDEs that bring you directly to the source code you’re looking for. Great, huh? But don’t take your IDE for granted, because if you don’t have one then you’ll need to go to your source server and modify a Java class with vi (vi? What’s that old boy? ;) ). Then maybe you’ll look at things differently.

In the days of “if I don’t know I Google it”, you can say that it won’t be that hard to identify what code does what. I think for experienced developers this is true. Because you know Java well, you can figure out where to look and get all ninja with writing bytecode directly in the JVM. But if you start on a new project and you’re stressing out because your boss totally sees that you can’t figure out why it’s still buggy after three weeks of trying to figure out why, then maybe things will be tougher.

The big paradox of lambdas is that they are so syntactically simple to write and so tough to understand if you’re not used to them. So if you have to quickly determine what the code is doing, the abstraction brought in by lambdas, even as it simplifies the Java syntax, will be hard to understand quickly and easily.

Lambdas, I still love you

Even if this article is about ruining the reputation of lambdas that are mostly sold as a revolution in Java 8, I still love them. Indeed if you’re used to them, they are really nice to use, mainly for quick treatments as displaying the value of each object in a list.

For complex algorithms maybe some developers will think of them as inappropriate. Java has never been a functional language, contrary to them lambdas now entering the heart of it. And in my humble opinion, things don’t have to be all and nothing…could we not keep lambdas where they are good, and rely on ultimately readable code for the rest? Context is important–you wouldn’t want to drive a cement truck to the supermarket for a bottle of milk, right?

I’m not sure if I’m the only one out there who is not 100% thrilled with the introduction of lambdas into Java 8, so leave your comments below if you agree/disagree.

Finally, I would like to leave you with this little lambda expression …

readers.stream()
               .filter(reader -> reader.isNinja())
               .forEach(reader -> reader.cheers());

Want to learn more about lambdas in Java 8? Check out Java 8 Revealed: Lambdas, Default Methods and Bulk Data Operations by Anton Arhipov, JRebel Product Manager at ZeroTurnaround.

Download the PDF version

 

  • Oleg Šelajev

    I don’t think that editing code that you don’t know well in VI/notepad is a good idea at all. And it has nothing to do with lambdas, plain old imports will kill the mood.

  • Thierry Wasylczenko

    I totally agree with the fact of not editing code you don’t know well with a basic editor, as well as it is not related to lambdas. And even if you know well the code, it still is difficult. But it was a simple example to say that if you have not the right tool to read your code, you won’t be able to do it. Without the lambdas syntax, you are in my humble opinion :)

  • http://www.jooq.org Lukas Eder

    I haven’t really seen anything critical of Project Lambda in the many months since their introduction into the language was made public.

    Just wait. I’m holding back a dozen of serious issues that I’ll unleash to the public in a future blog post :-)

    Yes, one big issue with lambdas is method overloading. Overloading was already a big issue with generics and/or varargs (see bottom item).

  • Thierry Wasylczenko

    Nice, can’t wait for your post! :)

  • Bilal Soidik

    But you will use it in control’s events and actions (swing,Javafx, swt), workers, collections, streams, collectors, and defined APIs, when you’r defining your own api or when you are designing your application and you need to do inheritance of some functions for several classes. But it is not made to be used where you just need to define the methods of the class. Every concept must be used with his philosophy.

  • http://blog.blzr.me/ Constantine

    Lazy evaluation FTW
    …doConditionally(bar==null, bar, bar.xyz())
    Oops, NPE
    …doConditionally(bar==null, () -> bar, () -> bar.xyz())

    Legal AOP

    …wrap(()->some.doSomething())
    where

    wrap(Runnable forExample){
    doBefore();
    forExamle.run();
    doAfter();
    }

  • Thierry Wasylczenko

    I totally agree with you: use everything where it has to be used, not everywhere ! Good point !

  • Iain Hull

    I believe overloading is the primary issue here not lamdas. There are some good uses for overloading, but most uses are wrong. For example:the developer was too lazy to think of a new name for their new method, or was to lazy to refactor existing code to use the new signature.

    If those methods were call startDream, startAugmentedDream and startThisIsNightmare there would be no issue with lamdas. Although the API would suck, this smell is probably a sign of a deeper malaise in the design that requires three slightly different dream methods. But who said API design was supposed to be easy :-)

  • Thierry Wasylczenko

    Well, I don’t totally agree because architecture is also the way of implementing interfaces in our Java world. So you can not always rename your methods. If you could it would just be too easy right and not alway lazyness? :)

    But as said, lambdas have to be used where it is useful, not everywhere. Moreover my main point is the difficulty to understand/read them when you’re not used to, especially when you’re a young developer. And like I said, I stil love lambdas :) Cheers :)

  • ryantk

    Not seeing the issue, if you have to know what interface it is you just look at the type of the parameters passed.

  • Scott C

    The problem above is with your API design. Don’t name those three things the same.

    Anyone can write a hard to use API, with or without lambdas. Don’t confuse poor names and API design with a language feature.

  • michaell

    I don’t see why it is important to know which functional interface is being used. At the end, it’s just an interface with exactly one method and your implementation detail is all there in front of you. Boiled down it is just the lever for lambdas.

  • Jon

    Agreed. If the author can come up with a sensible API design and show how lambdas make it worse, then that would be a legitimate criticism. Deliberately writing idiotic code that happens to use lambdas proves absolutely nothing.

  • lmollea

    Man, wait, sure you put up the worst example around, but don’t bash them too early.

    Sure as every tool someone will misuse them, but I welcome the small reduction in verbosity that they will bring.

    Writing new Runnable() { /* et cetera */ } instead of just passing a function pointer (or something that now mimc that) that can be written in the call is a too long waited improvement in readability.

  • Anonymous Coward

    Silly strawman argument. You picked a bad API design approach, and then you feigned surprised that interaction with a new feature makes this bad design EVEN WORSE — and then blamed the feature rather than the (deliberately) bad design.

    Its pretty obvious that overloading on functional interfaces with the same arity is going to be a problem; just look at the new lambda-inspired JDK classes for examples. Yes, it may take some time for people to discover the proper principles of API design in this new world.

  • William

    readers.stream()
    .filter(Reader::isNinja)
    .forEach(Reader::cheers);

  • Greg

    I agree that Lambdas are not very much human-readable. I think that less verbosity is not always a better choice (analogy to Java against Scala debate). Though coding Ninjas will be keen on playing with concise Lambdas, some will need much more time than usual to thorough understanding such pieces of code, which I consider to be a disadvantage.
    However there is also a big advantage – the evolution of the language.
    Some developers will need Lambdas for some specific reasons.
    As more and more Java code will contain Lambda closures the developers will get used to them and as today they heavily use Generics/Annotations/Enums/Diamond Operators/foreach/callbacks etc., the Lambdas will be their next preferred choice (of “pattern”) with fluent streams api and closures. I believe it will spur the adoption of parallel multi-core processing and replace anonymous inner classes with cleaner, leaner code.
    Perhaps it will further evolve into BYODSL (Build-your-own Domain Specific Language)
    and enable to write better parsers/compilers/interpreters/pipelines or kind thereof.

    Java was always about “why?” not “how?” and even though you get the first impression that you must understand “how it [lambda] works?” I think it’s just because it’s still “new” and looks “awkward” within your old-coding guidelines. The question is only when :) it will become your best buddy.

  • dantheperson

    How are Lambdas leaner than inner classes? Isn’t it just syntatic sugar. Where is the reduced memory footprint going to come from?

  • http://www.jooq.org Lukas Eder