13
Évolutions du langage Java Évolutions dans Java SE 5.0 Génériques - Permet un type ou une méthode de fonctionner sur des objets de différents types, tout en offrant la sécurité de type à la compilation. Ajoute la sécurité de type de la librairie des Collections Java et élimine la corvée de la gestion du cast Amélioration de boucle - Cette nouvelle structure du langage, élimine la corvée et la propension aux erreurs des itérateurs et des variables d'index lors de l'itération sur les collections et les tableaux. Autoboxing / unboxing Elimine la corvée de conversion manuelle entre les types primitifs (comme int) et les types d'encapsulation correspondants (examinés Integer). Énumérations typesafe Permet de créer des types énumérés orientés objet avec des méthodes et des champs arbitraires. VarArgs Possibilité de passer à des méthodes une liste d'arguments de longueur variable. Statique Import Permet d'éviter la qualification des membres statiques avec des noms de classe. Annotations (métadonnées) Cette fonctionnalité du langage permet des traitements à la compilation ou au runtime du code source (des outils permettent de générer du code à partir des annotations). Cela permet de faire de la programmation "déclarative" où le programmeur dit ce qui doit être fait par des annotations et les outils émettent le code pour le faire. Il élimine donc la nécessité pour le maintien de « fichiers secondaires» qui doivent être tenus à jour avec les changements dans les fichiers sources. Au contraire, l'information peut être maintenue dans le fichier source. http://docs.oracle.com/javase/8/docs/technotes/guides/language/enhancements.html#javase8 Évolutions dans Java SE 6 Aucun changement du langue n’a été introduit dans Java SE 6 Évolutions dans Java SE 7

Améliorations dans Java depuis la version 5

Embed Size (px)

Citation preview

Page 1: Améliorations dans Java depuis la version 5

Évolutions du langage Java

Évolutions dans Java SE 5.0

Génériques - Permet un type ou une méthode de fonctionner sur des objets de différents types, tout

en offrant la sécurité de type à la compilation. Ajoute la sécurité de type de la librairie des Collections

Java et élimine la corvée de la gestion du cast

Amélioration de boucle - Cette nouvelle structure du langage, élimine la corvée et la propension

aux erreurs des itérateurs et des variables d'index lors de l'itération sur les collections et les tableaux.

Autoboxing / unboxing – Elimine la corvée de conversion manuelle entre les types primitifs

(comme int) et les types d'encapsulation correspondants (examinés Integer).

Énumérations typesafe – Permet de créer des types énumérés orientés objet avec des méthodes et

des champs arbitraires.

VarArgs – Possibilité de passer à des méthodes une liste d'arguments de longueur variable.

Statique Import – Permet d'éviter la qualification des membres statiques avec des noms de classe.

Annotations (métadonnées) – Cette fonctionnalité du langage permet des traitements à la

compilation ou au runtime du code source (des outils permettent de générer du code à partir des

annotations). Cela permet de faire de la programmation "déclarative" où le programmeur dit ce qui

doit être fait par des annotations et les outils émettent le code pour le faire. Il élimine donc la nécessité

pour le maintien de « fichiers secondaires» qui doivent être tenus à jour avec les changements dans les

fichiers sources. Au contraire, l'information peut être maintenue dans le fichier source.

http://docs.oracle.com/javase/8/docs/technotes/guides/language/enhancements.html#javase8

Évolutions dans Java SE 6

Aucun changement du langue n’a été introduit dans Java SE 6

Évolutions dans Java SE 7

Page 2: Améliorations dans Java depuis la version 5

Binary Literals - Avec Java 7 les types primitifs byte , short, int et long peuvent être déclarés en

utilisant la notation binaire base 2. Pour cela il faut utiliser les préfixes 0b ou 0B.

byte aByte = (byte)0b00100001;

short aShort = (short)0b1010000101000101; // A 16-bit 'short' value:

int anInt1 = 0b10100001010001011010000101000101; / / Some 32-bit 'int' values:

// A 64-bit 'long' value. Note the "L" suffix:

long aLong = 0b1010000101000101101000010100010110100001010001011010000101000101L;

Underscores in Numeric Literals – Le caractère underscore (_) peut apparaître à tout endroit

d’un nombre. Cela peut être utile pour la lisibilité des nombres à manipuler en groupant les séries de

chiffres.

long creditCardNumber = 1234_5678_9012_3456L;

long socialSecurityNumber = 999_99_9999L;

float pi = 3.14_15F; long hexBytes = 0xFF_EC_DE_5E;

long hexWords = 0xCAFE_BABE;

long maxLong = 0x7fff_ffff_ffff_ffffL;

byte nybbles = 0b0010_0101;

long bytes = 0b11010010_01101001_10010100_10010010;

float pi1 = 3_.1415F; //KO cannot put underscores adjacent to a decimal point

float pi2 = 3._1415F; //KO cannot put underscores adjacent to a decimal point

int x3 = 52_; //KO - cannot put underscores at the end of a literal

int x4 = 5____2;//OK - (decimal literal) int x5 = 0_x52; //KO - cannot put underscores in the 0x radix prefix

int x6 = 0x_52; //KO - cannot put underscores at the beginning of a number

int x7 = 0x5_2; //OK - (hexadecimal literal)

int x8 = 0x52_; //KO - cannot put underscores at the end of a number

int x9 = 0_52; //OK - (octal literal) int x10 = 05_2; //OK - (octal literal)

int x11 = 052_; //KO - cannot put underscores at the end of a number

Strings in switch Statements – Utilisation possible des String dans les comparaisons des switch

String typeOfDay;

switch (dayOfWeekArg) {

case "Monday":

typeOfDay = "Start of work week";

break;

case "Tuesday":

default:

}

La comparaison est case sensitive et s’effectue avec la méthode String.equals().

Type Inference for Generic Instance Creation – Déduction de type)

Page 3: Améliorations dans Java depuis la version 5

Avec Java 7 on peut supprimer les types paramétrés quand on fait appel au constructeur des classes

génériques tant que le compilateur peut les déduire. Le pair ‘<>’ est appelé losange.

Exemple :

Avant java 7 :

Map<String, List<String>> myMap = new HashMap<String, List<String>>();

Maintenant :

Map<String, List<String>> myMap = new HashMap<>();

Map<String, List<String>> myMap = new HashMap(); // unchecked conversion warning

class MyClass<X> { <T> MyClass(T t) {

// ...

}

}

Avant Java 7 : new MyClass<Integer>(""); // OK

Avec Java 7 : MyClass<Integer> myObject = new MyClass<>("");

Le compilateur déduit le type générique de la classe et le paramètre générique du constructeur.

================================================

Improved Compiler Warnings and Errors When Using Non-Reifiable Formal Parameters

with Varargs Methods – The Java SE 7 complier generates a warning at the declaration site of a

varargs method or constructor with a non-reifiable varargs formal parameter. Java SE 7 introduces the

compiler option -Xlint:varargs and the annotations @SafeVarargs and

@SuppressWarnings({"unchecked", "varargs"}) to suppress these warnings.

================================================

The try-with-resources Statement – Le try-with-resources est une déclaration qui declare un ou

plusieurs ressources qui doit être fermer/libérer une fois quand on ne s’en sert plus.

Le try-with-resources s’assure que chaque ressource est libérée à la fin du try-with-resources. Tout

objet qui implemente les interfaces java.lang.AutoCloseable ou java.io.Closeable peut alors être

considérée comme une ressource.

Page 4: Améliorations dans Java depuis la version 5

REMARQUE :

Les classes java.io.InputStream, OutputStream, Reader, Writer, java.sql.Connection, Statement,

and ResultSet ont évoluées pour implémenter l’interface AutoCloseable et peuvent être utilisées dans

une déclaration try-with-resources.

Exemple d'utilisation :

String readFirstLineFromFile(String path) throws IOException {

try (BufferedReader br = new BufferedReader(new FileReader(path))) {

return br.readLine();

}

}

On peut utiliser une ou plusieurs ressources dans un déclaration try-with-resource.

public static void writeToFileZipFileContents(String zipFileName, String outputFileName) throws

java.io.IOException {

java.nio.charset.Charset charset = java.nio.charset.StandardCharsets.US_ASCII;

java.nio.file.Path outputFilePath = java.nio.file.Paths.get(outputFileName);

// Open zip file and create output file with try-with-resources statement

try (

java.util.zip.ZipFile zf = new java.util.zip.ZipFile(zipFileName);

java.io.BufferedWriter writer = java.nio.file.Files.newBufferedWriter(outputFilePath, charset)

) {

// Enumerate each entry

for (java.util.Enumeration entries = zf.entries(); entries.hasMoreElements();) {

// Get the entry name and write it to the output file

String newLine = System.getProperty("line.separator");

String zipEntryName = ((java.util.zip.ZipEntry)entries.nextElement()).getName() + newLine;

writer.write(zipEntryName, 0, zipEntryName.length());

}

}

}

NB :

Dans cet exemple deux exceptions peuvent etre levées dans l'instruction try-with-resource (lors des

appels zf.close() et writer.close()).

Si une exception est levée dans le bloc d'instructions et en même temps par la déclaration try-with-

resource alors ces dernières sont tues et seule la première est renvoyée. Pour intercepter ces exceptions

là il faut appeler Throwable.getSuppressed.

Page 5: Améliorations dans Java depuis la version 5

Catching Multiple Exception Types and Rethrowing Exceptions with Improved Type Checking

– Avec Java 7 on peut intercepter plusieurs types d'exceptions dans un seul bloc catch.

En outre le compilateur effectue une meilleure analyse des exceptions retransmises par les instructions

throw e; permettant de mieux spécifier les types d'exceptions dans les clauses throws des déclarations

de méthode.

Avant Java 7 :

catch (IOException ex) {

logger.log(ex);

throw ex;

} catch (SQLException ex) {

logger.log(ex);

throw ex;

}

Avec java 7 :

catch (IOException|SQLException ex) {

logger.log(ex);

throw ex;

}

Rethrowing Exceptions with More Inclusive Type Checking

Soit le code suivant :

Avant Java 7 :

public void rethrowException(String exceptionName)

throws Exception {

try {

if (exceptionName.equals("First")) {

throw new FirstException();

} else {

throw new SecondException();

}

} catch (Exception e) {

throw e;

}

}

Avec Java 7 :

public void rethrowException(String exceptionName) throws FirstException, SecondException { try { // ... } catch (Exception e ) { throw e ; } }

Le compilateur vérifie que que l'exception de l'instruction throw e provient du bloc try et que seules

les exceptions FirstException, SecondException y sont levées.

Page 6: Améliorations dans Java depuis la version 5

Évolutions dans Java SE 8

1. Lambda Expressions – Permet d’encapsuler une unique unité de travail, une

fonctionnalité ou un comportement et de le passer à un nouveau contexte d’exécution. On peut

utiliser les lambda expressions sur chaque élément d’une collection, à la fin de l’exécution d’un

process ou bien en cas d’erreur d’un process. On peut distinguer trois types de lambdas

expressions:

Method References

Ce sont des lambdas expressions compact, facile à lire ou comprendre car ce sont des méthodes

qui possèdent un nom et donc signature.

Exemple Arrays.sort(rosterAsArray, Person::comparePersonneByAge );

Le tableau ci-dessous résume les différents types de lambdas expressions utilisant des références de

méthodes:

Référence d'une méthode statique

ContainingClass::staticMethod

Arrays.sort(rosterAsArray, Person::compareByAge);

Référence depuis un objet d’un type particulier

containingObject::instanceMethodName

ComparisonProvider compareProvider = new

ComparisonProvider();

Arrays.sort(rosterAsArray,

compareProvider::compareByName);

Référence depuis un type particulier

ContainingType::methodName

String [] stringArray = {"Barbara", "James", "Mary", "John",

"Patricia", "Robert", "Michael", "Linda"};

Arrays.sort(stringArray, String::compareToIgnoreCase);

Référence à un constructeur

ClassName::new

--------------------------

Utilisation avec une lambda

Page 7: Améliorations dans Java depuis la version 5

Soit l’exemple ci-dessous :

public static <T, SOURCE extends

Collection<T>, DEST extends Collection<T>>

DEST transferElements(

SOURCE sourceCollection,

Supplier<DEST> collectionFactory) {

DEST result = collectionFactory.get();

for (T t : sourceCollection) {

result.add(t);

}

return result;

}

-------------------------------

1 Set<Person> rosterSetLambda =

transferElements(roster, () -> { return new HashSet<>();

});

Avec une référence contructeur (celui de HashSet)

2 Set<Person> rosterSet = transferElements(roster,

HashSet::new);

Le compilateur déduit le type paramètré comme un type

Person à partir du type paramétré dans

Toujours avec une référence de constructeur.

3 Set<Person> rosterSet = transferElements(roster,

HashSet<Person>::new);

Default Methods Permettent l’ajout de nouvelles fonctionnalités aux interfaces des

librairies d’un API et d’assurer la compatibilité avec le code existant pour les anciennes

versions de ces interfaces. Ces méthodes d’interfaces ont une implémentation et un le mot clef

default devant leur signature. En addition on peut ajouter des méthodes statiques dans ces

interfaces.

Définition

En java une interface est un type de référence, semblable à une classe, pouvant contenir uniquement

des constantes, des signatures de méthode, des méthodes statiques, et des types internes. Les

implémentations de méthode existent uniquement pour les méthodes default et les méthodes

statiques. Les interfaces ne peuvent pas être instanciées, ils peuvent seulement être implémentés

(implements) ou étendus (extends) par d’autres interfaces.

Extending Interfaces That Contain Default Methods

Lors de l’extension d’une interface contenant une default method on peut soit :

Ne pas mentionner la méthode default et hériter de celui de la super-interface.

Redéclarer la méthode par défaut, ce qui la rend abstraite (sans default devant la signature).

Ou redéfinir la default method pour réécrire celle de la super-interface. Toute classe qui

l’implémente cette interface utilisera cette default method au lieu de celle de la super-

interface.

Static Methods

Avec Java 8 on peut définir des méthodes statiques dans une interface. La déclaration est identique à

celle d’une classe.

Page 8: Améliorations dans Java depuis la version 5

Définition

Une méthode statique est une méthode qui est associée à la classe dans laquelle elle est définie plutôt

qu’à un quelconque objet.

Integrating Default Methods into Existing Libraries

Les default method méthodes permettent d’ajouter de nouvelles fonctionnalités à des interfaces

existantes sans nuire à la compatibilité binaire du code existant se basant sur les versions antérieures

de ces interfaces.

Les default method permettent d’ajouter des méthodes qui acceptent des lambdas expressions comme

paramètre. Cette section montre un exemple d’utilisation de l’intégration des default method et de

méthode statique dans une interface (Exemple de l’API Comparator).

New and Enhanced APIs That Take Advantage of Lambda Expressions and Streams in

Java SE 8

En Java SE 8 de nouvelles classes et APIs qui exploitent les lambdas expressions et les Streams (que

l’on verra plus bas) ont été ajoutées. Des classes existantes ont été modifiés et mis à jour pour utiliser

ces nouvelles évolutions.

La p lus part de ces classes se situent dans les packages suivants :

java.util: Contient les interfaces et classes permettant de manipuler les colletions

(Java Collections Framework ) et les Stream.

java.util.function: Nouveau package Contient les interfaces fonctionnelles servant en général de types cibles

(target types) de type cible en général pour les lambdas expressions et

les références de méthode (method references).

java.util.stream: Nouveau package Contient la majorité des interfaces et classes permettant de manipuler les

Stream et les opérations d’agrégation sur les collections (aggregate

operations).

Ci-dessous les classes et leurs packages qui ont été modifiés pour intégrer les évolutions sur les Strem

et lambdas expressions.

Page 9: Améliorations dans Java depuis la version 5

Package Nouvelles Classes Classes Modifiées

java.io UncheckedIOException BufferedReader

java.lang

AutoCloseable

ThreadLocal

String

Iterable

CharSequence

Boolean

Integer

Long

Float

Double

java.nio.file Files

java.util

PrimitiveIterator

Spliterator

DoubleSummaryStatistics

IntSummaryStatistics

LongSummaryStatistics

Optional

OptionalDouble

OptionalInt

OptionalLong

Spliterators

SplittableRandom

StringJoiner

Arrays

BitSet

Collection

Comparator

Iterator

List

Map

Map.Entry

LinkedHashMap

Random

TreeMap

java.util.concurrent ThreadLocalRandom

java.util.jar JarFile

java.util.zip ZipFile

java.util.logging Logger

java.util.regex Pattern

2. Improved Type Inference – Déduction de type évoluée à la compilation

Le compilateur peut déduire les différents types cibles des paramètres des méthodes génériques. Le

type cible d’une expression est le type des données auxquelles le compilateur s’attend à recevoir.

Page 10: Améliorations dans Java depuis la version 5

Par exemple en Java 7 lors d’une assignation Map<String, String> aMap = new HashMap<>() ;

En Java 8 on peut utiliser la déduction de types des expressions dans des contextes plus variés

Lambdas Expressions ou Invocation de Méthode pour déduire les types des paramètres.

Par exemple le code suivante ne passera pas en Java 7 et antérieur.

List<String> stringList = new ArrayList<>();

stringList.add("A");

stringList.addAll(Arrays.asList());

L’erreur suivante est levée :

The method addAll(Collection<? extends String>) in the type List<String> is not applicable for the

arguments (List<Object>)

Pour résoudre l’erreur il faudra indiquer explicitement le type requis :

stringList.addAll(Arrays.<String>asList());

La méthode addAll(...) prend en paramètre un type Collection< ? extends String> et Arrays.asList()

retourne une liste List<T> .

En Java 8 le compilateur déduit que le type T attendu est de type String grâce au de la méthode

addAll(Collection< ? extends String>)

3. Annotations on Java Types – Annotation de Type

En java Java 7 on peut appliquer les annotations uniquement sur les déclarations de variable, méthode,

et classes.

Java 8 a introduit une évolution sur les annotations appelées Type Annotation. Ces annotations

peuvent être utilisées pour différents type d’usage. On peut utiliser les annotations partout où un

type peut être utilisé, lors de la création d’instances (new), lors d’un cast, dans les clauses throws ou

implements etc.… Ces annotations sont appelées Type Annotation.

Création d’une instance de classe :

new @Interned MyObject(); Type cast:

myString = (@NonNull String) str;

implements clause: class UnmodifiableList<T> implements

@Readonly List<@Readonly T> { ... } Throws exception déclaration:

void monitorTemperature() throws @Critical TemperatureException { ... }

Page 11: Améliorations dans Java depuis la version 5

Si une déclaration possède plusieurs annotations de même type, on parle d’annotation répétitive

apparue avec Java 8 (Repeating Annotation)

Exemple :

@Author(name = "Jane Doe")

@Author(name = "John Smith")

class MyClass { ... }

La définition d’une annotation reste inchangée :

@interface MyAnnotation {

String name () ;

Int va lue () default 0 ; String [] names() ;

… }

Les Annotations Prédéfinies :

Outre les annotations bien connues : @Deprecated (Java 5), @Override (Java 5),

@SuppressWarnings (Java 5) indique au compilateur de ne pas générer de warnings,

@SafeVarargs (Java 7) assume que le code dans la méthode/constructeur n’effectue pas des

opérations dangereuses sur ses paramètres de type tableau (varargs). Les warning sur ces paramètres

là sont toujours activés et ne peuvent être unchecked.

@FunctionalInterface (Java 8) indique que le type déclaré est supposé être un functional interface,

Les Annotations qui s’appliquent à d’autres annotations (META-ANNOTATION).

@Inherited (Java 5) – s’applique uniquement aux classes. Indique que l’annotation utilisée sur une

superclasse est héritée dans les sous-classes.

public class MySubClass extends MySuperClass {...}

MySubClass hérite de l’annotation @MyAnnotation

MySubClass.class.isAnnotationPresent(EntityAnnotation.cla

ss) retourne true !

java.lang.annotation.Inherit

ed

@Inherited

public @interface

MyAnnotation {

}

@MyAnnotation

public class MySuperClass {

... }

@Retention – Spécifie comment une annotation est utilisée:

Page 12: Améliorations dans Java depuis la version 5

RetentionPolicy.SOURCE – L’annotation est utilisée uniquement au niveau du code source et est ignoré par le compilateur.

RetentionPolicy.CLASS – L’annotation est utilisée uniquement par le compilateur à la compilation, mais elle est ignorée par la JVM.

RetentionPolicy.RUNTIME – L’annotation est utilisée uniquement par la JVM et peut donc être utilisée à l’exécution.

@Target (Java 5) – Permet de restreindre une annotation sur les types Java auxquels cette annotation

doit s’appliquer.

ElementType.ANNOTATION_TYPE peut être appliquée à une autre annotation.

ElementType.CONSTRUCTOR peut être appliquée à un constructeur.

ElementType.FIELD peut être appliquée à un attribut ou propriété.

ElementType.LOCAL_VARIABLE peut être appliquée à une locale variable.

ElementType.METHOD peut être appliquée à une méthode.

ElementType.PACKAGE peut être appliquée à une déclaration de package.

ElementType.PARAMETER peut être appliquée aux paramètres d’une méthode.

ElementType.TYPE peut être appliquée à tout élément d’une classe.

@Documented (Java 5) – Est utilisé pour indiquer à la javadoc que mes propres annotations doivent

être visibles sur les classes annotées avec.

@MyAnnotation

public class MySuperClass { ... }

java.lang.annotation.Documented

@Documented

public @interface MyAnnotation {

}

L’annotation @MyAnnotation est maintenant visible dans la javadoc de la classe MySuperClass.

@Repeatable (Java 8) – Indique qu’une annotation peut se répéter plusieurs fois sur une déclaration ou

un type.

4. Repeating Annotations (@see) –

Parfois il peut s’avérer utile de porter la même annotation plus d’une fois :

@Schedule(dayOfMonth="last")

Page 13: Améliorations dans Java depuis la version 5

@Schedule(dayOfWeek="Fri", hour="23")

public void doPeriodicCleanup() { ... }

Pour créer une annotation répétitive il faut la marquer avec la nouvelle méta-annotation

@Repeatable apparue avec Java 8.

import java.lang.annotation.Repeatable;

@Repeatable(Schedules.class)

public @interface Schedule {

String dayOfMonth() default "first";

String dayOfWeek() default "Mon";

int hour () default 12;

}

La valeur, entre parenthèses, de l’annotation @Repeatable correspond à une annotation conteneur qui

contiendra la liste des annotations répétitives.

Cette annotation conteur doit posséder un attribut value dont le type est un tableau d’éléments de type

l’annotation Repeatable qu’on est en train de créer.

public @interface Schedules {

Schedule [] value ();

}

5. Method Parameter Reflection –