Favor Lambdas Over Anonymous Classes

 class​ Calculator {
 
  Map<Double, Double> values = ​new​ HashMap<>();
 
  Double square(Double x) {
  Function<Double, Double> squareFunction =
»new​ Function<Double, Double>() {
  @Override
 public​ Double apply(Double value) {
 return​ value * value;
  }
  };
 return​ values.computeIfAbsent(x, squareFunction);
  }
 }

In Java 8, several existing classes (such as Map) got a boost with more useful methods. In the code above, you can see one of them named computeIfAbsent(). This method gets a value from the map using its key, and if the key isn’t already present in the map, it computes the value first. Pretty neat. We’ve written similar code many times by hand before.

But to use that new method, you need to provide the logic,how the map should compute the value for an absent key, as an input parameter. Otherwise, it can’t do its job.

Type-wise, computeIfAbsent() requires an instance of a class that implements the interface Function<Double, Double> with its method Double apply(Double value) here. The Double types come from the types inside the values map, and you’ll have different types for a different map.

In the code above, the programmer instantiated an anonymous class to implement that interface. It’s called anonymous because there’s no class name and the class has only a single instance.

However, anonymous classes have a tendency to bloat up the code. They make it considerably larger and add additional levels of indentation. That’s because you need to reiterate the interface type and method. The actual computation—in our example the single line of code return value * value—is hidden in all that verbosity.

With Java 8, we’ve got an excellent alternative to writing anonymous classes.

Lambda expressions can improve the code a lot here:

 class​ Calculator {
 
  Map<Double, Double> values = ​new​ HashMap<>();
 
  Double square(Double value) {
» Function<Double, Double> squareFunction = factor -> factor * factor;
 return​ values.computeIfAbsent(value, squareFunction);
  }
 }

Now that’s way shorter and more readable. You can directly spot the computation logic, and all the verbosity is gone for good. Much more concise, indeed.

Lambdas provide implementations for functional interfaces—that is, interfaces with a single abstract method. Here, lambdas are a perfect fit, because the Function interface has only a single abstract method: apply(). We can write a lambdas in various ways: as one-liners or in multiple lines. Let’s take a look.

 // one-liner
 Function<Double, Double> squareFunction = factor -> factor * factor;
 // multi-liner
 Function<Double, Double> squareFunction = factor -> {
 return​ factor * factor;
 };

Here, you can compare the one-liner and the multi-liner directly. The one-liner has no return keyword, and no curly braces. It’s best for very short and concise glue code. You should avoid the multi-liner whenever possible and Favor Method References Over Lambdas instead. And there’s more: you can have implicit or explicit type declaration.

 // without type definition and braces
 Function<Double, Double> squareFunction = factor -> factor * factor;
 // with type definition and braces
 Function<Double, Double> squareFunction = (Double factor) -> factor * factor;

In Java, you usually have to specify types everywhere explicitly. But for parameters of lambda expressions the compiler can figure out the types on its own in (almost) all cases: it searches for the single abstract method that the lambda expression implements and uses that method signature with its type specifications. This is called type inference. We could provide the types here, but why state the obvious?

Note that the braces are only optional for a single parameter and you have to use them for more than one parameter or if the type is stated explicitly.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.219.71.21