Nya funktioner i Java 8

1. Översikt

I den här artikeln tittar vi snabbt på några av de mest intressanta nya funktionerna i Java 8.

Vi pratar om: gränssnittsstandard och statiska metoder, metodreferens och valfritt.

Vi har redan täckt några funktioner i Java 8: s release - stream API, lambda-uttryck och funktionella gränssnitt - eftersom de är omfattande ämnen som förtjänar ett separat utseende.

2. Gränssnittets standard- och statiska metoder

Innan Java 8 kunde gränssnitt endast ha offentliga abstrakta metoder. Det var inte möjligt att lägga till ny funktionalitet i det befintliga gränssnittet utan att tvinga alla implementeringsklasser att skapa en implementering av de nya metoderna, och det var inte heller möjligt att skapa gränssnittsmetoder med en implementering.

Från och med Java 8 kan gränssnitt ha statiska metoder och standardmetoder som trots att deklareras i ett gränssnitt har ett definierat beteende.

2.1. Statisk metod

Tänk på följande metod för gränssnittet (låt oss kalla det här gränssnittet Fordon ):

static String producer() { return "N&F Vehicles"; }

Den statiska producentmetoden () är endast tillgänglig via och inuti ett gränssnitt. Det kan inte åsidosättas av en implementeringsklass.

För att ringa det utanför gränssnittet bör standardmetoden för statisk metodanrop användas:

String producer = Vehicle.producer();

2.2. Standardmetod

Standardmetoder förklaras med den nya standard nyckelordet . Dessa är tillgängliga via förekomsten av implementeringsklassen och kan åsidosättas.

Låt oss lägga till en standardmetod i vårt fordonsgränssnitt , vilket också ringer till den statiska metoden för detta gränssnitt:

default String getOverview() { return "ATV made by " + producer(); }

Antag att detta gränssnitt implementeras av klassen VehicleImpl. För att utföra standardmetoden ska en instans av denna klass skapas:

Vehicle vehicle = new VehicleImpl(); String overview = vehicle.getOverview();

3. Metodreferenser

Metodreferens kan användas som ett kortare och mer läsbart alternativ för ett lambdauttryck som bara kallar en befintlig metod. Det finns fyra varianter av metodreferenser.

3.1. Hänvisning till en statisk metod

Hänvisningen till en statisk metod innehåller följande syntax: ContainingClass :: methodName.

Låt oss försöka räkna alla tomma strängar i listan med hjälp av Stream API.

boolean isReal = list.stream().anyMatch(u -> User.isRealUser(u));

Ta en närmare titt på lambda uttryck i anyMatch () metoden, bara gör det ett samtal till en statisk metod isRealUser (User användare) i användarklassen. Så det kan ersättas med en hänvisning till en statisk metod:

boolean isReal = list.stream().anyMatch(User::isRealUser);

Denna typ av kod ser mycket mer informativ ut.

3.2. Hänvisning till en instansmetod

Hänvisningen till en instansmetod innehåller följande syntax: c ontainingInstance :: methodName. Följande kod anropar metoden isLegalName (String sträng) av typen Användare som validerar en inparameter:

User user = new User(); boolean isLegalName = list.stream().anyMatch(user::isLegalName); 

3.3. Hänvisning till en instansmetod för ett objekt av en särskild typ

Denna referensmetod tar följande syntax: C ontainingType :: methodName. Ett exempel::

long count = list.stream().filter(String::isEmpty).count();

3.4. Hänvisning till en konstruktör

En referens till en konstruktör tar följande syntax: ClassName :: new. Eftersom konstruktör i Java är en speciell metod kan metodreferens tillämpas på den också med hjälp av nytt som metodnamn .

Stream stream = list.stream().map(User::new);

4. Valfritt

Innan Java 8-utvecklare var tvungna att noggrant validera värden som de hänvisade till på grund av möjligheten att kasta NullPointerException (NPE) . Alla dessa kontroller krävde en ganska irriterande och felbenägen pannkodskod.

Java 8 Valfri klass kan hjälpa till att hantera situationer där det finns en möjlighet att få NPE . Det fungerar som en behållare för objektet av typen T. Det kan returnera ett värde för detta objekt om detta värde inte är noll . När värdet i denna behållare är noll tillåter det att göra några fördefinierade åtgärder istället för att kasta NPE.

4.1. Skapande av tillvalet

En instans av klassen Optional kan skapas med hjälp av dess statiska metoder:

Optional optional = Optional.empty();

Returnerar ett tomt tillval.

String str = "value"; Optional optional = Optional.of(str);

Returnerar ett valfritt som innehåller ett icke-nollvärde.

Optional optional = Optional.ofNullable(getString());

Will return an Optional with a specific value or an empty Optional if the parameter is null.

4.2. Optional Usage

For example, you expect to get a List and in the case of null you want to substitute it with a new instance of an ArrayList. With pre-Java 8's code you need to do something like this:

List list = getList(); List listOpt = list != null ? list : new ArrayList();

With Java 8 the same functionality can be achieved with a much shorter code:

List listOpt = getList().orElseGet(() -> new ArrayList());

There is even more boilerplate code when you need to reach some object's field in the old way. Assume you have an object of type User which has a field of type Address with a field street of type String. And for some reason you need to return a value of the street field if some exist or a default value if street is null:

User user = getUser(); if (user != null) { Address address = user.getAddress(); if (address != null) { String street = address.getStreet(); if (street != null) { return street; } } } return "not specified";

This can be simplified with Optional:

Optional user = Optional.ofNullable(getUser()); String result = user .map(User::getAddress) .map(Address::getStreet) .orElse("not specified");

In this example we used the map() method to convert results of calling the getAdress() to the Optional and getStreet() to Optional. If any of these methods returned null the map() method would return an empty Optional.

Imagine that our getters return Optional. So, we should use the flatMap() method instead of the map():

Optional optionalUser = Optional.ofNullable(getOptionalUser()); String result = optionalUser .flatMap(OptionalUser::getAddress) .flatMap(OptionalAddress::getStreet) .orElse("not specified");

Another use case of Optional is changing NPE with another exception. So, as we did previously, let's try to do this in pre-Java 8's style:

String value = null; String result = ""; try { result = value.toUpperCase(); } catch (NullPointerException exception) { throw new CustomException(); }

And what if we use Optional? The answer is more readable and simpler:

String value = null; Optional valueOpt = Optional.ofNullable(value); String result = valueOpt.orElseThrow(CustomException::new).toUpperCase();

Notice, that how and for what purpose to use Optional in your app is a serious and controversial design decision, and explanation of its all pros and cons is out of the scope of this article. If you are interested, you can dig deeper, there are plenty of interesting articles on the Internet devoted to this problem. This one and this another one could be very helpful.

5. Conclusion

In this article, we are briefly discussing some interesting new features in Java 8.

There are of course many other additions and improvements which are spread across many Java 8 JDK packages and classes.

But, the information illustrated in this article is a good starting point for exploring and learning about some of these new features.

Slutligen finns all källkod för artikeln tillgänglig på GitHub.