Syntaxe et nouvelles fonctionnalités de Java 8

View more Tutorials:

1- Introduction

De l'invention à la mise à niveau de la syntaxe et des fonctionnalités, Java a franchi plusieurs étapes importantes :
  • Java 1.0: Commencement d'un langage de programmation.
  • Java 1.1, 1.2, 1.3, 1.4 il n'y a pas beaucoup changements sur la syntaxe et les fonctionnalités.
  • Java 1.5 (Ou Java 5) il y a eu de grands changements, avec l'inclusion de quelques nouveaux concepts.
    • Generic
    • Autoboxing/Unboxing
    • fonctionnalité de mise à niveau à la boucle ("foreach").
    • L'énumération est sans danger (énumérations de type-safe).
      (Type-safe enumerations).
    • Varargs
    • Importation statique (Static import)
    • Metadata
  • Java 6,7 il n'y a pas beaucoup de grands changements en matière de langage.
  • Java 8 il y a un grand changement de langage. Avec l'inclusion de quelques nouveaux concepts et fonctionnalités :
    • La méthode par défaut de l'interface (méthodes d'interface par défaut)(Default interface methods)
    • L'expression Lambda (Lambda expressions)
    • Méthode de références
    • Annotations répétable (Repeatable annotations)
    • Stream
Dans ce document, je vais vous présenter sur les fonctionnalités et la syntaxe de Java 8.

2- Méthodes par défaut pour l'interface

Java 8 vous permet d'ajouter une méthode qui n'est pas abstraite dans l'interface en utilisant le mot clé  default. Cette caractéristique est également appelée Extension Methods. Voici votre premier exemple :
Formula.java
package org.o7planning.tutorial.j8.itf;

public interface Formula {

	// Déclarez une méthode abstraite.
	double calculate(int a);

	// Déclarez une méthode qui n'est pas abstraite.
	// Utilisez le mot de clé default.
	// (Fonction de calcule la racine carrée d'un nombre).
	default double sqrt(int a) {
		return Math.sqrt(a);
	}

}
Et la class FormulaImpl implémente interface Formula.
FormulaImpl.java
package org.o7planning.tutorial.j8.itf;

// Une classe implémente l'interface Formula.
public class FormulaImpl implements Formula {

	// Il suffit d'implémenter les méthodes abstraites de Formula.
	@Override
	public double calculate(int a) {
		return a * a - a;
	}

}
FormulaTest.java
package org.o7planning.tutorial.j8.itf;

public class FormulaTest {

   public static void main(String[] args) {
       Formula formula = new FormulaImpl();

       // ==> 5
       double value1 = formula.sqrt(25);
       System.out.println("Value1 = " + value1);

       // ==> 600
       double value2 = formula.calculate(25);
       System.out.println("Value2 = " + value2);

   }

}

3- Functional Interface

Java8 a considére que l'Interface a une seule méthode abstraite qui est  Functional Interface. Vous pouvez utiliser l'annotation @FunctionalInterface pour marquer votre interface qui est Interface fonctionnelle. Elle n'est pas obligatoire. Cependant, le compilateur de Java vous avertir l'erreur si vous ajoutez accidentellement une autre méthode abstraite dans l'interface marquée par cette annotation.
Voici quelques exemples pratique avec  @FunctionalInterface:
L'exemple ci-dessous est un  FunctionalInterface valide, car elle n'y a qu'une seule méthode abstraite.
Foo.java
package org.o7planning.tutorial.j8.funcitf;

@FunctionalInterface
public interface Foo {

  void something();

  default void defaultMethod() {
      System.out.println("..");
  }
}
Non valide :
Valide :
Non valide :
Valide :

4- Expression Lambda

Tout d'abord, nous allons examiner la façon dont la version Java avant 8 arrange une Collection disponible.
Voyez plus :
SortBefore8Example.java
package org.o7planning.tutorial.j8.lambda;

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class SortBefore8Example {

	public static void main(String[] args) {

		// Une liste des fruits.
		List<String> fruits = Arrays.asList("Grapefruit", "Apple", "Durian", "Cherry");

		// Utilisez la méthode utilitaire de Collections pour réorganiser la liste ci-dessus.
		// Fournissez Comparator (Comparateur).
		Collections.sort(fruits, new Comparator<String>() {

			@Override
			public int compare(String o1, String o2) {
				return o1.compareTo(o2);
			}

		});

		for (String fruit : fruits) {
			System.out.println(fruit);
		}

	}
}
Les résultats d'exécution de l'exemple ci-dessus :
Java 8 comprend que les interfaces ont une méthode abstraite unique qui est Functional Interface. Par conséquent, lors de l'implémentation de l'interface, vous n'avez qu'à écrire une méthode implémente cette méthode abstraite unique. Comparator est une interface ayant une méthode abstraite unique, et c'est une Functional Interface. Vous pouvez réécrire l'exemple ci-dessus sous forme de Lambda de Java 8 :
SortJava8Example.java
package org.o7planning.tutorial.j8.lambda;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class SortJava8Example {

	public static void main(String[] args) {

		// Une liste des fruits.
		List<String> fruits = Arrays.asList("Grapefruit", "Apple", "Durian", "Cherry");

		// Utiliser la méthode utilitaire de Collections pour trier la liste ci-dessus.
		// Fournir un comparateur au 2ème paramètre de la méthode.
		// Le comparateur n'a qu'une seule méthode abstraite.
		// ==> Peut écrire des brèves avec des expressions Lambda.
		// Pas besoin d'écrire le nom de l'interface,
		// Pas besoin d'écrire le nom de la méthode abstraite.
		Collections.sort(fruits, (String o1, String o2) -> {
			return o1.compareTo(o2);
		});

		for (String fruit : fruits) {
			System.out.println(fruit);
		}

	}
}
Dans un bloc d'instruction, s'il n'y a qu'une instruction, vous pouvez effacer { }, et vous pouvez écrire cette section de code d'une manière plus concise.
Collections.sort(fruits, (String o1, String o2) -> o1.compareTo(o2)  );
 
Compilateur de Java est même assez intelligent pour identifier le type d'éléments que vous avez besoin d'organiser, dans cet exemple, il est de type String. Ainsi, Comparator est sûrement de comparer des types de données de String. Vous pouvez l'écrire de façon plus concise.
Collections.sort(fruits, (o1, o2) -> o1.compareTo(o2));
Un autre exemple avec les expressions  Lambda.
Converter.java
package org.o7planning.tutorial.j8.lambda;

@FunctionalInterface
public interface Converter<F, T> {
   
   T convert(F from);
   
}
Utilisez l'interface  Converter sous forme de versions Java avant la version 8 (Cela signifie ne pas utiliser Lambda).
ConverterBefore8Example.java
package org.o7planning.tutorial.j8.lambda;

public class ConverterBefore8Example {

	public static void main(String[] args) {

		// Initialiser l'objet Converter.
		Converter<String, Integer> converter = new Converter<String, Integer>() {

			@Override
			public Integer convert(String from) {
				return Integer.parseInt(from);
			}

		};

		// ==> 100
		Integer value = converter.convert("0100");

		System.out.println("Value = " + value);
	}
}
Utilisez les expressions  Lambda de  Java 8 :
ConveterJava8Example.java
package org.o7planning.tutorial.j8.lambda;

public class ConveterJava8Example {

	public static void main(String[] args) {

		// Converter est un FunctionalInterface
		// Utilisez la syntaxe de Java 8 (Lambda)
		// Dans le cas : Créer l'objet directement à partir de FunctionalInterface.
		Converter<String, Integer> converter1 = (String from) -> {
			return Integer.parseInt(from);
		};

		// ==> 100
		Integer value1 = converter1.convert("0100");

		System.out.println("Value1 = " + value1);

		// Ou plus simple :
		Converter<String, Integer> converter2 = (from) -> Integer
				.parseInt(from);

		// ==> 200
		Integer value2 = converter2.convert("00200");

		System.out.println("Value2 = " + value2);
		
		// Si la méthode n'a qu'un seul paramètre, peut ignorer ().
		Converter<String, Integer> converter3 = from -> Integer
				.parseInt(from);

		// ==> 300
		Integer value3 = converter3.convert("00300");

		System.out.println("Value3 = " + value3);
		
	}

}

5- Functional Interface API

Java 8 dispose d'un grand nombre des Functional Interface disponibles dans le package java.util.function. Ici, je vais vous donner des instructions d'utilisation certaines de ces interfaces afin que vous puissiez comprendre plus facilement l'expression Lambda et leur commodité.

5.1- java.util.function.Consumer

Consumer est une Functional interface disponible de Java 8, elle a une seule méthode abstraite qui accepte un paramètre d'entrée et cette méthode ne renvoie rien.
Consumer.java
package java.util.function;

import java.util.Objects;

@FunctionalInterface
public interface Consumer<T> {
	
	// Méthode pour accepter un paramètre d'entrée
	// Et ne renvoie rien.
	void accept(T t);

}
Utilisez la methode  List.forEach(Consumer) :
// java.util.List extends java.util.Collection  (extends Iterable)

// Interface java.util.Iterable:
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
   for (T t : this) {
       action.accept(t);
   }
}
ConsumerExample.java
package org.o7planning.tutorial.j8.api;

import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;

public class ConsumerExample {

	// Utiliser la méthode List.forEach (Consumer) avec la syntaxe de Java <8.
	// Imprimer la liste des éléments de List.
	public static void beforeJ8() {
		List<String> list = Arrays.asList("a", "b", "c", "a1", "a2");

		list.forEach(new Consumer<String>() {

			@Override
			public void accept(String t) {
				System.out.println(t);
			}

		});
	}

	// Utiliser la méthode List.forEach(Consumer) avec la syntaxe de Java 8.
	// Utiliser expression Lambda.
	public static void java8Consumer() {
		List<String> list = Arrays.asList("a", "b", "c", "a1", "a2");

		list.forEach((String t) -> {
			System.out.println(t);
		});
	}

	// Utiliser la méthode List.forEach(Consumer) avec la syntaxe de Java 8.
	// Utiliser expressions Lambda.
	// (Plus simple)
	public static void java8ConsumerMoreSimple() {
		List<String> list = Arrays.asList("a", "b", "c", "a1", "a2");

		list.forEach((String t) -> System.out.println(t));
	}
	
}

5.2- java.util.function.Predicate

Predicate est une Functional interface disponible de Java8, elle a une méthode abstraite qui accepte un paramètre d'entrée unique et la méthode renvoie une valeur boolean ( true/false ). Cette méthode est d'évaluer si le paramètre d'entrée convient à quelque chose de logique ou non.
Predicate.java
package java.util.function;

import java.util.Objects;

@FunctionalInterface
public interface Predicate<T> {

	// Évalue un paramètre d'entrée et renvoie true ou false.
	boolean test(T t);

}
Dans l'exemple suivant, nous allons filtrer une liste d'entiers et imprimer une liste de nombres impairs en utilisant Predicate sous la forme de Java8 et des versions précédentes.
PredicateExample.java
package org.o7planning.tutorial.j8.api;

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Stream;

public class PredicateExample {

	// Utiliser la méthode  Stream.filter(Predicate<T>) avec la syntaxe de Java < 8.
	// Filtrer une liste d'entiers et imprime les impaires.
	public static void beforeJ8() {
		List<Integer> list = Arrays.asList(1, 4, 5, 1, 7, 8);

		// Stream contient les éléments de la liste au-dessus
		Stream<Integer> stream = list.stream();

		// Un nouveau Stream contient des impairs.
		Stream<Integer> stream2 = stream.filter(new Predicate<Integer>() {

			@Override
			public boolean test(Integer t) {
				return t % 2 == 1;
			}
		});
	}

	// Utiliser la méthode Stream.filter(Predicate<T>) avec la syntaxe de Java >= 8.
	// Filtrer une liste d'entiers et imprime les impaires.
	// Avec l'utilisation d'expressions Lambda.
	public static void java8Predicate() {
		List<Integer> list = Arrays.asList(1, 4, 5, 1, 7, 8);

		// Un Stream contient les éléments de la liste au-dessus
		Stream<Integer> stream = list.stream();

		// Un nouveau Stream contient des impairs.
		Stream<Integer> stream2 = stream.filter(t -> {
			return t % 2 == 1;
		});

		// Stream.forEach(Consumer<T>)
		stream2.forEach(t -> System.out.println(t));
	}

	// Simple et plus concis.
	public static void java8ConsumerMoreSimple() {
		List<Integer> list = Arrays.asList(1, 4, 5, 1, 7, 8);

		// Un Stream contient les éléments de la liste au-dessus
		Stream<Integer> stream = list.stream();

		stream.filter(t -> t % 2 == 1).forEach(t -> System.out.println(t));
	}

}

5.3- java.util.function.Function

Function est un  Functional interface disponibe de   Java 8, elle a une méthode abstraite qui accepte un paramètre d'entrée et la méthode renvoie un objet différent.
Function.java
package java.util.function;

import java.util.Objects;


@FunctionalInterface
public interface Function<T, R> {

	// Cette méthode accepte un paramètre.
	// Et renvoie le résultat.
	R apply(T t);

}
Exemple : Donner une liste de String, imprimer les éléments de la liste en majuscules.
FunctionExample.java
package org.o7planning.tutorial.j8.api;

import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Stream;

public class FunctionExample {

	// Utiliser la méthode Stream.map(Function) avec la syntaxe de Java < 8.
	// Imprimer la liste des éléments de List.
	public static void beforeJ8() {
		List<String> list = Arrays.asList("a", "c", "B", "e", "g");

		// Stream contient les éléments de la liste.
		Stream<String> stream = list.stream();

		// Stream.map(Function):
		// <R> Stream<R> map(Function<? super T, ? extends R> mapper);
		// Renvoie un nouveau Stream, avec les éléments ont été modifiés.
		Stream<String> streamUpper = stream.map(new Function<String, String>() {

			@Override
			public String apply(String t) {
				return t == null ? null : t.toUpperCase();
			}

		});

		streamUpper.forEach(t -> System.out.println(t));
	}

	public static void java8Function() {
		List<String> list = Arrays.asList("a", "c", "B", "e", "g");

		// Un Stream contient les éléments de la liste.
		Stream<String> stream = list.stream();

		stream.map(t -> t == null ? null : t.toUpperCase()).forEach(t -> System.out.println(t));
	}

	public static void main(String[] args) {

		beforeJ8();

		java8Function();
	}

}

Certains Functional interface similaires :

  • java.util.function.IntFunction<R>
  • java.util.function.DoubleFunction<R>
  • java.util.function.LongFunction<R>
@FunctionalInterface
public interface IntFunction<R> {
 
    R apply(int value);
}


@FunctionalInterface
public interface LongFunction<R> {
 
    R apply(long value);
}


@FunctionalInterface
public interface DoubleFunction<R> {
 
    R apply(double value);
}

5.4- java.util.function.Supplier

Supplier est un  Functional interface disponibe de   Java 8,  elle a une seule méthode abstraite qui n'a pas paramètre et renvoie un objet.
Supplier.java
package java.util.function;

@FunctionalInterface
public interface Supplier<T> {

	// Cette méthode n'a pas de paramètre.
	// Mais renvoie un résultat.
	T get();

}
SupplierExample.java
package org.o7planning.tutorial.j8.api;

import java.util.function.Supplier;

public class SupplierExample {

	// Une méthode dont le paramètre est Supplier<String>.
	public static void display(Supplier<String> supp) {
		System.out.println(supp.get());
	}

	// N'utilisez pas d'expressions Lambda.
	public static void beforeJ8() {
		display(new Supplier<String>() {

			@Override
			public String get() {
				return "Hello";
			}
		});
		display(new Supplier<String>() {

			@Override
			public String get() {
				return "World";
			}
		});
	}

	// Utilisez l'expression Lambda.
	public static void java8Supplier() {
		display(() -> {
			return "Hello";
		});

		display(() -> {
			return "World";
		});
	}

	// Utilisez l'expression Lambda.
	// (plus concis).
	public static void java8SupplierShortest() {
		display(() -> "Hello");

		display(() -> "World");
	}

	public static void main(String[] args) {

		beforeJ8();
		System.out.println("-----------");
		java8SupplierShortest();
	}

}
Certaines s Functional Interface similaires :
  • java.util.function.BooleanSupplier
  • java.util.function.IntSupplier
  • java.util.function.DoubleSupplier
  • java.util.function.LongSupplier

6- Method reference

C'est une caractéristique qui est liée à l'expression Lambda. Il nous permet de référencer des constructeurs ou des méthodes sans les exécuter. Les références de méthode et Lambda sont similaires en ce sens qu'elles exigent toutes deux un type d'objectif constitué d'une Functional Interface compatible.
Java 8 vous permet de passer des références de méthodes ou de constructeurs via le : : mot-clé
Before looking at details, let's see a simple example.
MyFunction est un Functional Interface. Elle définit une méthode qui prend deux paramètres, int a et b, et renvoie la valeur de int.
MyFunction.java
package org.o7planning.tutorial.j8.mref;

@FunctionalInterface
public interface MyFunction {

	// Cette méthode a deux paramètres, a et b, et renvoie un int.
	public int doSomething(int a, int b);

}
MyMathUtils est une classe avec deux méthodes statiques utilisées pour calculer la somme et la soustraction de deux nombres entiers.​​​​​​​
MyMathUtils.java
package org.o7planning.tutorial.j8.mref;

public class MyMathUtils {

	// Cette méthode a deux paramètres, a et b, et renvoie un int.
	// Cette méthode est différente du nom,
	// mais la structure similaire à MyFunction.doSomething(int,int).
	public static int sum(int a, int b) {
		return a + b;
	}

	public static int minus(int a, int b) {
		return a - b;
	}

}
MethodReferenceExample.java
package org.o7planning.tutorial.j8.mref;

public class MethodReferenceExample {

	// Le troisième paramètre de cette méthode est  MyFunction (Functional Interface).
	// Lorsque vous utilisez cette méthode:
	// Vous pouvez passer la référence d'une méthode au 3ème paramètre.
	// (Les méthodes doivent être du même type que MyFunction)
	public static int action(int a, int b, MyFunction func) {
		return func.doSomething(a, b);
	}

	public static void main(String[] args) {
		int a = 100;
		int b = 30;

		// Passer la référence de la méthode MyMathUtils.sum.
		int c = action(a, b, MyMathUtils::sum);// ==> 130.

		System.out.println("c = " + c);

		// Passer la référence de la méthode MyMathUtils.minus.
		int d = action(a, b, MyMathUtils::minus);// ==> 70

		System.out.println("d = " + d);

		// Passer la référence de la méthode Math.subtractExact.
		int e = action(a, b, Math::subtractExact);// ==> 70

		System.out.println("e = " + e);

		// Passer la référence de la méthode Math.min.
		int f = action(a, b, Math::min);// ==> 30

		System.out.println("f = " + f);
	}
}
A travers l'exemple ci-dessus, vous pouvez voir comment utiliser le mot clé : : pour passer la référence d'une méthode. Si vous appelez une méthode et qu'il existe un argument appelé Functional Interface dans cette méthode, vous pouvez transmettre une référence de méthode dont la structure est similaire à celle définie dans Functional Interface.

View more Tutorials: