Читаем Introducing Java 8 полностью

First, notice that Comparator is a functional interface because it only declares a single abstract method called compare, which takes two objects of the same type and returns an integer. This is an ideal situation for a lambda expression, like this one: Collections.sort(invoices, (Invoice inv1, Invoice inv2) -> { return Double.compare(inv2.getAmount(), inv1.getAmount()); });

Since the body of the lambda expression is simply returning the value of an expression, you can use the more concise form of lambda expression: Collections.sort(invoices, (Invoice inv1, Invoice inv2) -> Double.compare(inv2.getAmount(), inv1.getAmount()));

In Java 8, the List interface supports the sort method, so you can use that instead of Collections.sort: invoices.sort((Invoice inv1, Invoice inv2) -> Double.compare(inv2.getAmount(), inv1.getAmount()));

Next, Java 8 introduces a static helper, Comparator.comparing, which takes as argument a lambda to extract a comparable key. It then generates a Comparator object for you. You can use it as follows: Comparator byAmount = Comparator.comparing((Invoice inv) -> inv.getAmount()); invoices.sort(byAmount);

You may notice that the more concise method reference Invoice::getAmount can simply replace the lambda (Invoice inv) -> inv.getAmount(): Comparator byAmount = Comparator.comparing(Invoice::getAmount); invoices.sort(byAmount);

Since the method getAmount returns a primitive double, you can use Comparator.comparingDouble, which is a primitive specialized version of Comparator.comparing, to avoid unnecessary boxing: Comparator byAmount = Comparator.comparingDouble(Invoice::getAmount); invoices.sort(byAmount);

Finally, let’s tidy up the code and use an import static and also get rid of the local variable holding the Comparator object to produce a solution that reads like the problem statement: import static java.util.Comparator.comparingDouble; invoices.sort(comparingDouble(Invoice::getAmount));

Testing with Lambda Expressions

You may be concerned with how lambda expressions are going to affect testing. After all, lambda expressions introduce behaviors that need to be tested. When deciding how to test code that contains lambda expressions, consider the following two options:

If the lambda expression is small, test the behavior of the surrounding code that uses it.

If the lambda expression is reasonably complex, extract it into a separate method reference that you can inject and test in isolation.

Summary

Here are the key concepts from this chapter:

A lambda expression can be understood as a kind of anonymous function.

Lambda expressions and the behavior parameterization pattern let you write code that is both flexible and concise.

A functional interface is an interface that declares a single abstract method.

Lambda expressions can only be used in the context of a functional interface.

Method references can be a more natural alternative to lambda expressions when you need to reuse an existing method and pass it around.

In the context of testing, extract large lambda expressions into separate methods that you can then inject using method references.

Chapter 3. Adopting Streams

In this chapter, you’ll learn how to adopt the Streams API. First, you’ll gain an understanding behind the motivation for the Streams API, and then you’ll learn exactly what a stream is and what it’s used for. Next, you’ll learn about various operations and data processing patterns using the Streams API, and about Collectors, which let you write more sophisticated queries. You’ll then look at a practical refactoring example. Finally, you’ll learn about parallel streams.

The Need for Streams

The Collections API is one of the most important parts of the Java API. Nearly every Java application makes and processes collections. But despite its importance, the processing of collections in Java is still unsatisfactory in many aspects.

For one reason, many alternative programming languages or libraries let you express typical data processing patterns in a declarative way. Think of SQL, where you can select from a table, filter values given a condition, and also group elements in some form. There’s no need to detail how to implement the query—the database figures it out for you. The benefit is that your code is easier to understand. Unfortunately, in Java you don’t get this. You have to implement the low-level details of a data processing query using control flow constructs.

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже