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

Java 8 introduces a new way to think about asynchronous programming with a new class, CompletableFuture. It’s an improvement on the old Future class, with operations inspired by similar design choices made in the new Streams API (i.e., declarative flavor and ability to chain methods fluently). In other words, you can declaratively process and compose multiple asynchronous tasks.

Here’s an example that concurrently queries two blocking tasks: a price finder service along with an exchange rate calculator. Once the results from the two services are available, you can combine their results to calculate and print the price in GBP: findBestPrice("iPhone6") .thenCombine(lookupExchangeRate(Currency.GBP), this::exchange) .thenAccept(localAmount -> System.out.printf("It will cost you %f GBP\n", localAmount)); private CompletableFuture findBestPrice(String productName) { return CompletableFuture.supplyAsync(() -> priceFinder.findBestPrice(productName)); } private CompletableFuture lookupExchangeRate(Currency localCurrency) { return CompletableFuture.supplyAsync(() -> exchangeService.lookupExchangeRate(Currency.USD, localCurrency)); }

Optional

Java 8 introduces a new class called Optional. Inspired by functional programming languages, it was introduced to allow better modeling in your codebase when a value may be present or absent. Think of it as a single-value container, in that it either contains a value or is empty. Optional has been available in alternative collections frameworks (like Guava), but is now available as part of the Java API. The other benefit of Optional is that it can protect you against NullPointerExceptions. In fact, Optional defines methods to force you to explicitly check the absence or presence of a value. Take the following code as an example: getEventWithId(10).getLocation().getCity();

If getEventWithId(10) returns null, then the code throws a NullPointerException. If getLocation() returns null, then it also throws a NullPointerException. In other words, if any of the methods return null, a NullPointerException could be thrown. You can avoid this by adopting defensive checks, like the following: public String getCityForEvent(int id) { Event event = getEventWithId(id); if(event != null) { Location location = event.getLocation(); if(location != null) { return location.getCity(); } } return "TBC"; }

In this code, an event may have an associated location. However, a location always has an associated city. Unfortunately, it’s often easy to forget to check for a null value. In addition, the code is now more verbose and harder to follow. Using Optional, you can refactor the code to be more concise and explicit, like so: public String getCityForEvent(int id) { Optional.ofNullable(getEventWithId(id)) .flatMap(this::getLocation) .map(this::getCity) .orElse("TBC"); }

At any point, if a method returns an empty Optional, you get the default value "TBC".

Chapter 2. Adopting Lambda Expressions

In this chapter, you’ll learn how to adopt lambda expressions, the flagship feature of Java 8. First, you’ll learn about a pattern called behavior parameterization, which lets you write code that can cope with requirement changes. Then, you’ll see how lambda expressions let you use this pattern in a more concise way than what was possible before Java 8. Next, you’ll learn precisely where and how to use lambda expressions. You’ll also learn about method references, another Java 8 feature that lets you write code that is more succinct and descriptive. You’ll then bring all this new knowledge together into a practical refactoring example. Finally, you’ll also learn how to test using lambda expressions and method references.

Why Lambda Expressions?

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