Nouveautés de Java 8
Les lambdas expressions
Soit le tableau d’instance de la classe Personne (prénom, nom, age) suivant :
List<Personne> personnes = Arrays.asList(new Personne("Pierre", "Durand", 20), new Personne("Marie", "Durand", 14), new Personne("Albert", "Martin", 12));
Si la classe Personne redéfini equal
et hashcode
en fonction du nom et du prénom et que l’on souhaite trier le tableau par âge, il faut définir une classe qui implante l’interface Comparator<Personne>
ou mieux utiliser une classe anonyme :
Collections.sort(personnes, new Comparator<Personne>() { @Override public int compare(Personne o1, Personne o2) { return o1.getAge() - o2.getAge(); } });
A partir de Java 8 on peut utiliser des lambda expressions. Elles peuvent être vues comme des classes anonymes ayant une seule méthode dont le type de retour est inféré. Les type des paramètres peuvent aussi être inférés.
Une lambda est composée :
- d’un ou ou de plusieurs nom de paramètres (alors entre parenthèse) éventuellement typés
- du symbole →
- d’un corps de fonction, s’il est réduit à une expression le
return
est facultatif.
Collections.sort(personnes, (o1, o2) -> o1.getPrenom().compareTo(o2.getPrenom()));
Les interfaces fonctionnelles
Java 8 définit le concept d’interfaces fonctionnelles (elles ont extactement une méthode). Elle permet de manipuler des lambda expressions ou des références vers des méthodes. Une interface peut être définie comme fonctionnelle avec l’annotation @FunctionalInterface. Un ensemble d’interface classiques est proposé dans le JDK :
- Function<T,R> - takes an object of type T and returns R.
- Supplier<T> - just returns an object of type T.
- Predicate<T> - returns a boolean value based on input of type T.
- Consumer<T> - performs an action with given object of type T.
- BiFunction - like Function but with two parameters.
- BiConsumer - like Consumer but with two parameters.
Function<String, String> at = (name) -> { return "@" + name; }; for (Personne p : personnes) System.out.println(at.apply(p.getNom()));
Supplier<List> listFactory = ArrayList::new; System.out.println("list factory : "+(listFactory.get() instanceof List));
Consumer<String> println = System.out::println; println.accept("Consumer say Hello");
Première application
Retrouver des personnes avec un filtre.
En utilisant une classe générique pour la recherche :
public class Processor<T> { public List<T> find(Iterable<T> iterable, Predicate<T> predicate) { List<T> list = new ArrayList<>(); for (T t : iterable) if (predicate.test(t)) list.add(t); return list; } } Processor<Personne> personneProcessor = new Processor<>();
//avec une classe anonyme pour le critère System.out.println(personneProcessor.find(personnes, new Predicate<Personne>() { @Override public boolean test(Personne p) { return p.getNom().equals("Durand") && p.getAge() >= 18 && p.getAge() <= 25; } }));
avec une lambda expression
System.out.println(personneProcessor.find(personnes, p -> p.getNom().equals("Durand") && p.getAge() >= 10 && p.getAge() <= 15 ));
Stream
Un stream permet de représenter une séquence d’objets qui peut supporter l’exécution parallèle. La construction de stream peut être “lazzy”.
Un stream peut être créé au dessus d’une collection
List<Personne> personnes = new ArrayList<>(); personnes.add(new Personne("Pierre", "Durand", 20)); personnes.add(new Personne("Marie", "Durand", 14)); personnes.add(new Personne("Albert", "Martin", 12)); personnes.stream(); //Returns a sequential Stream with the collection as its source. personnes.parallelStream(); //Returns a possibly parallel Stream with the collection as its source.
Un stream peut être parcours avec un foreach qui permet d’appliquer une fonction sur chaque élément au fur et à mesure de leur production.
personnes.stream().forEach(System.out::println);
D’autre classe produisent des Stream comme les fichiers.
Noter le getResource
pour obtenir le chemin absolu.
String filename = this.getClass().class.getResource("/test.txt").getFile(); try (FileReader fileReader = new FileReader(filename); BufferedReader br = new BufferedReader(fileReader)) { br.lines().forEach(System.out::println); }
try (Stream stream = Files.lines(Paths.get(filename))) { stream.forEach(System.out::println); }
Il existe des versions plus performantes pour les primitifs IntStream
, DoubleStream
, et LongStream
.
Un stream peut aussi être filtré.
personnes.stream().filter(p -> p.getAge() > 18).forEach(System.out::println);
Et il permet d’utiliser le modèle map/reduce.
double ageMoyen = personnes.parallelStream().mapToInt(Personne::getAge).average().getAsDouble(); System.out.println(ageMoyen);
Javascript avec Nashorn
ScriptEngineManager engineManager = new ScriptEngineManager(); ScriptEngine engine = engineManager.getEngineByName("nashorn"); engine.eval("function pers(p,n) { return {nom:n, prenom:p} }"); engine.eval("print(JSON.stringify(pers('Pierre', 'Durand')))");
Optionnal
Objet qui peut contenir ou non une valeur null. Le but faciliter le traitement des null pointer exceptions.
—- dataentry page —- type : Howto technologie_tags : Java, Java8 theme_tags : POO