"Java n'est toujours pas mort - et les gens commencent à comprendre cela."
Ce tutoriel utilisera un code annoté simple pour décrire de nouvelles fonctionnalités, et vous ne verrez pas le texte à blockbuster.
1. La méthode par défaut de l'interface
Java 8 nous permet d'ajouter une implémentation de la méthode non abstrante à l'interface, utilisez simplement le mot-clé par défaut.
La copie de code est la suivante:
formule d'interface {
double calculer (int a);
Double Sqrt par défaut (int a) {
return math.sqrt (a);
}
}
En plus d'avoir une méthode calculée, l'interface de formule définit également la méthode SQRT.
La copie de code est la suivante:
Formule formule = nouvelle formule () {
@Outrepasser
Double calcul public (int a) {
retour sqrt (a * 100);
}
};
formule.Calculate (100);
formule.sqrt (16);
La formule de l'article est implémentée comme une instance d'une classe anonyme. Dans la section suivante, nous verrons une approche plus simple pour implémenter une interface à méthode unique.
Remarque du traducteur: il n'y a que des héritages uniques dans Java. Dans d'autres langues, la méthode pour avoir une classe a un autre code réutilisable en même temps est appelé mixin. Ce nouveau Java 8 Special est plus proche du trait de Scala du point de vue de la mise en œuvre du compilateur. Il existe également un concept appelé méthode d'extension dans C #, qui permet à l'étendue des types existants, ce qui est sémantiquement différent de celui-ci dans Java 8.
2. Lambda Expressions
Tout d'abord, jetons un coup d'œil à la façon dont les cordes sont organisées dans l'ancienne version de Java:
La copie de code est la suivante:
List <string> names = arrays.aslist ("Peter", "Anna", "Mike", "Xenia");
Collection.Sort (noms, nouveau comparateur <string> () {
@Outrepasser
public int compare (String A, String b) {
retour B.............. ce.
}
});
Passez simplement un objet de liste et un comparateur aux collectes de méthodes statiques.Sort pour l'organiser dans l'ordre spécifié. Il est généralement fait pour créer un objet de comparateur anonyme et le passer à la méthode de tri.
Dans Java 8, vous n'avez pas besoin d'utiliser cette méthode traditionnelle d'objets anonymes.
La copie de code est la suivante:
CollectionS.Sort (noms, (String A, String b) -> {
retour B.............. ce.
});
Voir, le code devient plus segmenté et lisible, mais il peut en fait être écrit plus court:
La copie de code est la suivante:
CollectionS.Sort (noms, (chaîne A, chaîne B) -> b.............. ce.Pareto (A));
Pour le corps de fonction avec une seule ligne de code, vous pouvez supprimer les accolades {} et retourner les mots clés, mais vous pouvez l'écrire plus court:
La copie de code est la suivante:
Collection.Sort (noms, (a, b) -> b................ ce............... ce................ ce............... ce............... ce................
Le compilateur Java peut déduire automatiquement les types de paramètres, vous n'avez donc plus à réécrire le type. Ensuite, voyons ce que les expressions de Lambda les plus pratiques peuvent faire:
3. Interface fonctionnelle
Comment les expressions Lambda sont-elles représentées dans le système de type Java? Chaque expression de lambda correspond à un type, généralement un type d'interface. "Interface fonctionnelle" fait référence à une interface qui ne contient qu'une méthode abstraite, et chaque expression de lambda de ce type sera appariée à cette méthode abstraite. Parce que la méthode par défaut n'est pas une méthode abstraite, vous pouvez également ajouter des méthodes par défaut à votre interface fonctionnelle.
Nous pouvons traiter les expressions Lambda comme n'importe quel type d'interface qui ne contient qu'une seule méthode abstraite pour vous assurer que votre interface doit répondre à cette exigence. Annotation, le compilateur constatera que l'interface que vous avez marquée est annotée par cette annotation.
Les exemples sont les suivants:
La copie de code est la suivante:
@FunctionalInterface
Convertisseur d'interface <f, t> {
T converti (f de);
}
Convertisseur <chaîne, entier> convertisseur = (de) -> Integer.Valueof (de);
Entier converti = converter.convert ("123");
System.out.println (converti);
Il convient de noter que si @functionalInterface n'est pas spécifié, le code ci-dessus est également correct.
Les notes du traducteur cartographie les expressions Lambda à une interface à méthode unique. Fonction.
4. Méthode et référence du constructeur
Le code dans la section précédente peut également être représenté par des références de méthode statique:
La copie de code est la suivante:
Convertisseur <string, entier> convertisseur = entier :: valeurof;
Entier converti = converter.convert ("123");
System.out.println (converti);
Java 8 vous permet d'utiliser le mot-clé :: pour passer une référence de méthode ou de constructeur.
La copie de code est la suivante:
convertisseur = quelque chose :: startSwith;
String converted = converter.convert ("java");
System.out.println (converti);
Voyons comment les constructeurs sont référencés à l'aide du mot-clé :: d'abord, nous définissons une classe simple avec plusieurs constructeurs:
La copie de code est la suivante:
classe de classe {
String FirstName;
String LastName;
Personne() {}
Personne (String FirstName, String LastName) {
this.firstName = FirstName;
this.lastName = lastName;
}
}
Ensuite, nous spécifions une interface d'usine d'objets pour créer des objets de personne:
La copie de code est la suivante:
interface personfactory <p étend la personne> {
P create (String FirstName, String LastName);
}
Ici, nous utilisons des références de constructeur pour les associer au lieu de mettre en œuvre une usine complète:
La copie de code est la suivante:
Personfactory <ponge> Personfactory = Person :: Nouveau;
Personne personne = personfactory.create ("Peter", "Parker");
Nous devons seulement utiliser Person :: Nouveau pour obtenir une référence au constructeur de classe de personne.
5. Lambda Scope
La façon d'accéder aux lunettes extérieures dans les expressions de lambda est similaire à celle des anciennes versions d'objets anonymes. Vous pouvez accéder directement aux variables locales externes marquées finales, ou champs et variables statiques de l'instance.
6. Accéder aux variables locales
Nous pouvons accéder aux variables locales externes directement dans les expressions de lambda:
La copie de code est la suivante:
int num final = 1;
Converter <nteger, string> stringConverter =
(de) -> string.valueof (de + num);
StringConverter.Convert (2);
Mais contrairement aux objets anonymes, le nombre variable ici peut être déclaré final sans le déclarer définitif, et le code est également correct:
La copie de code est la suivante:
int num = 1;
Converter <nteger, string> stringConverter =
(de) -> string.valueof (de + num);
StringConverter.Convert (2);
Cependant, Num ici ne doit pas être modifié par le code suivant (c'est-à-dire, implicitement a une sémantique finale), par exemple, ce qui suit ne peut pas être compilé:
La copie de code est la suivante:
int num = 1;
Converter <nteger, string> stringConverter =
(de) -> string.valueof (de + num);
num = 3;
Essayer de modifier Num dans les expressions de lambda n'est pas non plus autorisé.
7. Accès aux champs d'objet et variables statiques
Contrairement aux variables locales, les champs et les variables statiques dans la Lambda peuvent être lus et écrits. Ce comportement est cohérent avec les objets anonymes:
Copiez le code comme suit: class Lambda4 {
statique int exterStaticnum;
int outernum;
void testScopes () {
Converter <Integer, string> stringConverter1 = (de) -> {
outernum = 23;
return string.valueof (de);
};
Converter <nteger, string> stringConverter2 = (de) -> {
OUTERSTATICNUM = 72;
return string.valueof (de);
};
}
}
8. La méthode par défaut pour accéder à l'interface
N'oubliez pas l'exemple de formule dans la première section.
La méthode par défaut ne peut pas être consultée dans l'expression de Lambda, et le code suivant ne sera pas compilé:
La copie de code est la suivante:
Formule formule = (a) -> sqrt (a * 100);
Interfaces fonctionnelles intégrées
L'API JDK 1.8 contient de nombreuses interfaces fonctionnelles intégrées, telles que les interfaces comparateur ou exécutables couramment utilisées dans l'ancien Java, et ces interfaces ont ajouté l'annotation @FunctionalInterface à utiliser sur les lambdas.
L'API Java 8 fournit également de nouvelles interfaces fonctionnelles pour rendre le travail plus pratique.
Interface de prédicat
L'interface de prédicat n'a qu'un seul paramètre, qui renvoie le type booléen. Cette interface contient un certain nombre de méthodes par défaut pour combiner le prédicat dans d'autres logiques complexes (telles que: contre, ou non):
La copie de code est la suivante:
Predicat <string> predicat = (s) -> s.length ()> 0;
prédire.test ("foo");
prédire.negate (). Test ("foo");
Predicat <boolean> nonnull = objets :: non null;
Predicat <boolean> isNull = objets :: isNull;
Predicat <string> isEmpty = String :: Isempty;
Predicat <string> isNotempty = iseempty.negate ();
Interface de fonction
L'interface de fonction a un paramètre et renvoie un résultat, et est livré avec certaines méthodes par défaut (compose, et là) qui peuvent être combinées avec d'autres fonctions:
La copie de code est la suivante:
Function <String, Integer> toInteger = Integer :: ValueOf;
Function <string, string> backtoString = toInteger.andThen (String :: ValueOf);
BacktoString.Apply ("123");
Interface du fournisseur
L'interface du fournisseur renvoie une valeur de tout type.
La copie de code est la suivante:
Fournisseur <ponse> PersonSupplier = Person :: Nouveau;
PersonSupplier.get ();
Interface de consommation
L'interface de consommation représente l'opération effectuée sur un seul paramètre.
La copie de code est la suivante:
Consumer <Songe> Greeter = (P) -> System.out.println ("Hello", + P.FirstName);
greeter.accept (nouvelle personne ("Luke", "Skywalker"));
Interface du comparateur
Comparator est une interface classique dans Old Java, et Java 8 a ajouté une variété de méthodes par défaut:
La copie de code est la suivante:
Comparator <ponge> Comparator = (P1, P2) -> p1.firstname.compareto (p2.firstName);
Personne P1 = nouvelle personne ("John", "Doe");
Personne P2 = nouvelle personne ("Alice", "Wonderland");
comparateur.compare (P1, P2);
Comparator.Reversed (). Comparez (P1, P2);
Interface facultative
Facultatif n'est pas une fonction mais une interface.
Facultatif est défini comme un simple conteneur dont la valeur peut être nulle ou non. Avant Java 8, une fonction doit généralement renvoyer un objet non vide, mais parfois il peut retourner null.
La copie de code est la suivante:
Facultatif <string> Facultatif = facultatif.of ("bam");
Facultatif.ispresent ();
facultatif.get (); // "bam"
Facultatif.orelse ("Fallback");
facultatif.ifpresent ((s) -> System.out.println (s.Charat (0)));
Interface de flux
java.util.stream représente une séquence d'opérations qui peut être appliquée à un ensemble d'éléments en même temps. Les opérations de flux sont divisées en deux types: opérations intermédiaires ou opérations finales. La création de Stream nécessite de spécifier une source de données, comme une sous-classe de java.util.collection, de liste ou de définition, qui n'est pas prise en charge par MAP. Les opérations de flux peuvent être exécutées en série ou en parallèle.
Tout d'abord, voyons comment Stream est utilisé.
La copie de code est la suivante:
List <string> stringCollection = new ArrayList <> ();
stringCollection.add ("ddd2");
StringCollection.add ("AAA2");
StringCollection.add ("BBB1");
StringCollection.add ("AAA1");
StringCollection.add ("BBB3");
StringCollection.add ("CCC");
StringCollection.add ("BBB2");
stringCollection.add ("ddd1");
Java 8 étend la classe de collection et peut créer un flux via Collection.Stream () ou Collection.ParallelStream (). Les sections suivantes expliquent en détail les opérations de flux couramment utilisées:
Filtre
Le filtrage est filtré via une interface de prédicat et seuls les éléments qui répondent aux critères sont conservés. ForEach nécessite une fonction pour exécuter des éléments filtrés en séquence. Foreach est une opération finale, nous ne pouvons donc pas effectuer d'autres opérations de flux après Foreach.
La copie de code est la suivante:
StringCollection
.flux()
.filter ((s) -> s.startswith ("a")))
.ForEach (System.out :: println);
// "aaa2", "aaa1"
Trier
Le tri est une opération intermédiaire et le flux retourné après le tri est renvoyé. Si vous ne spécifiez pas de comparateur personnalisé, le tri par défaut sera utilisé.
La copie de code est la suivante:
StringCollection
.flux()
.Sorted ()
.filter ((s) -> s.startswith ("a")))
.ForEach (System.out :: println);
// "aaa1", "aaa2"
Il convient de noter que le tri ne crée qu'un flux organisé et n'affectera pas la source de données d'origine.
La copie de code est la suivante:
System.out.println (StringCollection);
// DDD2, AAA2, BBB1, AAA1, BBB3, CCC, BBB2, DDD1
Cartographie des cartes
La carte de fonctionnement intermédiaire convertit les éléments en objets supplémentaires en séquence en fonction de l'interface de fonction spécifiée. Vous pouvez également utiliser la carte pour convertir les objets en autres types.
La copie de code est la suivante:
StringCollection
.flux()
.map (String :: ToupperCase)
.
.ForEach (System.out :: println);
// "ddd2", "ddd1", "ccc", "bbb3", "bbb2", "aaa2", "aaa1"
Correspondre
Stream fournit une variété d'opérations d'appariement, permettant à la détection de savoir si un prédicat spécifié correspond à l'ensemble du flux. Toutes les opérations de correspondance sont des opérations finales et renvoient une valeur de type booléen.
La copie de code est la suivante:
booléen anystartswitha =
StringCollection
.flux()
.AnyMatch ((S) -> S.startswith ("a"));
System.out.println (anyStartswitha);
booléen allstartswitha =
StringCollection
.flux()
.AllMatch ((s) -> s.startswith ("a"));
System.out.println (Allstartswitha);
booléen non startswithz =
StringCollection
.flux()
.NonEmatch ((s) -> s.startswith ("z"));
System.out.println (nonstartswithz);
Compter
Le comptage est une opération finale, qui renvoie le nombre d'éléments dans le flux, et le type de valeur de retour est long.
La copie de code est la suivante:
Long startSwithb =
StringCollection
.flux()
.filter ((s) -> s.startswith ("b"))
.compter();
System.out.println (startSwithb);
Réduire les réglementations
Il s'agit d'une opération finale, permettant à plusieurs éléments du flux d'être définis comme un élément via la fonction spécifiée, et le résultat de l'admissibilité est représenté par l'interface facultative:
La copie de code est la suivante:
FACTIONNEL <String> réduit =
StringCollection
.flux()
.Sorted ()
.reduce ((S1, S2) -> S1 + "#" + S2);
réduit.ifpresent (System.out :: println);
// "aaa1 # aaa2 # bb1 # bb2 # bb3 # ccc # ddd1 # ddd2"
Ruisseaux parallèles
Comme mentionné précédemment, le flux a deux types: série et parallèle.
L'exemple suivant montre comment améliorer les performances grâce au flux parallèle:
Nous créons d'abord une grande table sans éléments en double:
La copie de code est la suivante:
int max = 1000000;
List <string> valeurs = new ArrayList <> (max);
pour (int i = 0; i <max; i ++) {
UUid uuid = uUid.randomuuid ();
valeurs.add (uuid.toString ());
}
Ensuite, nous calculons combien de temps il faut pour trier ce flux.
Sort en série:
La copie de code est la suivante:
long t0 = System.NanoTime ();
Long count = valeurs.stream (). tri (). count ();
System.out.println (count);
long t1 = System.NanoTime ();
long millis = timeunit.nanoseconds.tomiillis (t1 - t0);
System.out.println (String.Format ("SEQUELTIEL SORT TAKE:% D MS", Millis));
// Temps de série: 899 ms
Tri parallèle:
La copie de code est la suivante:
long t0 = System.NanoTime ();
Long Count = Values.ParallelStream (). Trid (). Count ();
System.out.println (count);
long t1 = System.NanoTime ();
long millis = timeunit.nanoseconds.tomiillis (t1 - t0);
System.out.println (String.Format ("Sort parallèle a pris:% D MS", Millis));
// Le tri parallèle prend du temps: 472 ms
Les deux codes ci-dessus sont presque les mêmes, mais la version parallèle est aussi rapide que 50%.
Carte
Comme mentionné précédemment, le type de carte ne prend pas en charge le flux, mais MAP fournit des méthodes nouvelles et utiles pour gérer certaines tâches quotidiennes.
La copie de code est la suivante:
Map <nteger, string> map = new HashMap <> ();
pour (int i = 0; i <10; i ++) {
map.putifabsent (i, "val" + i);
}
map.ForEach ((id, val) -> System.out.println (val));
Le code ci-dessus est facile à comprendre.
L'exemple suivant montre d'autres fonctions utiles sur la carte:
La copie de code est la suivante:
map.CombuteIfPresent (3, (num, val) -> val + num);
map.get (3);
map.CombuteIfPresent (9, (num, val) -> null);
map.ContainsKey (9);
map.computeIfAbsent (23, num -> "val" + num);
map.ContainsKey (23);
map.computeIfAbsent (3, num -> "bam");
map.get (3);
Ensuite, montrez comment supprimer un élément de la carte qui correspond à toutes les clés:
La copie de code est la suivante:
Map.Remove (3, "Val3");
map.get (3);
Map.Remove (3, "Val33");
map.get (3);
Une autre méthode utile:
La copie de code est la suivante:
map.getOrdefault (42, "non trouvé");
Il est également facile de fusionner les éléments de la carte:
La copie de code est la suivante:
map.merge (9, "Val9", (valeur, newValue) -> value.concat (newValue));
map.get (9);
map.merge (9, "Concat", (valeur, newValue) -> value.concat (newValue));
map.get (9);
Ce que la fusion fait est d'insérer si le nom de la clé n'existe pas, sinon fusionnez la valeur correspondant à la clé d'origine et réinsérez-la dans la carte.
9. API de date
Java 8 contient un nouvel ensemble d'API de temps et de date dans le cadre du package java.time. La nouvelle API de date est similaire à la bibliothèque open source JODA-TIME, mais pas exactement la même chose.
Horloge
La classe d'horloge fournit une méthode pour accéder à la date et à l'heure actuelles. Un point spécifique peut également être représenté par la classe instantanée, qui peut également être utilisée pour créer d'anciens objets java.util.date.
La copie de code est la suivante:
Clock Clock = Clock.SystemDefaultZone ();
long millis = horloge.milis ();
Instantané instantané = horloge.instant ();
Date LegacyDate = Date.from (instantané);
Fuseau horaire des fuseaux horaires
Dans la nouvelle API, le fuseau horaire est représenté par ZoneId. Le fuseau horaire peut être facilement obtenu en utilisant la méthode statique de. Le fuseau horaire définit le décalage horaire par rapport au temps UTS, ce qui est extrêmement important lors de la conversion entre l'objet instantané du temps et l'objet Date local.
La copie de code est la suivante:
System.out.println (ZoneId.GetAvailableZoneid ());
// imprime tous les identifiants de fuseau horaire disponibles
ZoneId Zone1 = ZoneId.of ("Europe / Berlin");
ZoneId Zone2 = ZoneId.of ("Brésil / Est");
System.out.println (zone1.getRules ());
System.out.println (zone2.getRules ());
// Zonerules [CurrentStandardOffset = + 01: 00]
// Zonerules [CurrentStandardOffset = -03: 00]
Heure locale locale
Localtime définit un temps sans informations de fuseau horaire, tels que 22 h ou 17:30:15. L'exemple suivant crée deux fois locaux en utilisant le fuseau horaire créé par le code précédent. Le temps est ensuite comparé et le décalage horaire entre les deux fois est calculé en heures et en minutes:
La copie de code est la suivante:
LocalTime Now1 = LocalTime.now (Zone1);
LocalTime Now2 = LocalTime.now (Zone2);
System.out.println (maintenant1.isbefore (maintenant 2));
longs heuresbetween = chronounit.hours.between (now1, now2);
longs minutesbetween = chronounit.Minutes.between (now1, now2);
System.out.println (HoursBetween);
System.out.println (MinuchBetween);
LocalTime fournit une variété de méthodes d'usine pour simplifier la création d'objets, y compris les chaînes de temps d'analyse.
La copie de code est la suivante:
Localtime tardif = localtime.of (23, 59, 59);
System.out.println (tardif); // 23:59:59
DateTimeFormatter GermanFormatter =
DateTimeFormatter
.oflocalizedtime (formatstyle.short)
.Withlocale (Locale.German);
LocalTime Leettime = localtime.parse ("13:37", allemandformatter);
System.out.println (LeetTime);
Date locale locale
LocalDate représente une date exacte, comme 2014-03-11. La valeur de cet objet est immuable et est fondamentalement la même que celle de l'heure locale. L'exemple suivant montre comment ajouter / lune / an à un objet de date. Notez également que ces objets sont immuables et l'opération renvoie une nouvelle instance.
La copie de code est la suivante:
LocalDate aujourd'hui = localDate.now ();
LocalDate demain = Today.Plus (1, chronounit.days);
LocalDate hier = demain.minusdays (2);
LocalDate indépendancey = localDate.of (2014, mois. juillet, 4);
Dayofweek dayofweek = indépendance.getDayofweek ();
System.out.println (DayOfweek);
L'analyse d'un type localdate à partir d'une chaîne est aussi simple que l'analyse locale:
La copie de code est la suivante:
DateTimeFormatter GermanFormatter =
DateTimeFormatter
.oflocalizedDate (formatstyle.medium)
.Withlocale (Locale.German);
LocalDate Noël = localDate.Parse ("24.12.2014", allemandformatter);
System.out.println (Noël); // 2014-12-24
LocalDateTime Local Datetime
LocalDateTime représente à la fois l'heure et la date, ce qui équivaut à la fusion du contenu des deux premières sections en un seul objet. LocalDateTime, comme Localtime et LocalDate, sont tous deux immuables. LocalDateTime fournit quelques méthodes pour accéder à des champs spécifiques.
La copie de code est la suivante:
LocalDatetime Sylvester = localDateTime.of (2014, mois.de décembre, 31, 23, 59, 59);
Dayofweek dayofweek = sylvester.getDayofweek ();
System.out.println (DayOfweek);
Mois mois = sylvester.getMonth ();
System.out.println (mois);
long minuteofday = sylvester.getLong (chronofield.minute_of_day);
System.out.println (MinuteOfday);
Il suffit de joindre les informations de fuseau horaire et peut être convertie en un objet instantané de point de point.
La copie de code est la suivante:
Instantané instantané = sylvester
.atZone (ZoneId.SystemDefault ())
.toistant ();
Date LegacyDate = date.from (instant);
System.out.println (LegacyDate);
Le formatage localdatetime est le même que le formatage et la date. En plus d'utiliser des formats prédéfinis, nous pouvons également définir le format:
La copie de code est la suivante:
DateTimeFormatter Formatter =
DateTimeFormatter
.Ofpattern ("mmm dd, yyyy - hh: mm");
LocalDateTime analysé = localDateTime.Parse ("nov 03, 2014 - 07:13", format);
String String = Formatter.Format (Pared);
System.out.println (String); // nov 03, 2014 - 07:13
Contrairement à java.text.numberformat, la nouvelle version de DateTimeFormatter est immuable, il est donc filé.
Informations détaillées sur le format de l'heure et de la date: http://download.java.net/jdk8/docs/api/java/time/format/datetimeformatter.html
10. Notes d'annotation
Plusieurs annotations sont prises en charge dans Java 8. Voyons d'abord un exemple pour comprendre ce que cela signifie.
Tout d'abord, définissez une annotation des indices emballés pour placer un ensemble spécifique d'annotations d'indices:
La copie de code est la suivante:
@Interface Insigne {
Indice [] value ();
}
@Repeatable (indices.class)
@interface
String value ();
}
Java 8 nous permet d'utiliser des annotations du même type plusieurs fois, il suffit d'étiqueter l'annotation @Repeatable.
Exemple 1: Utilisez la classe de wrapper comme conteneur pour stocker plusieurs annotations (ancienne méthode)
La copie de code est la suivante:
@Hints ({@ hint ("hint1"), @Hint ("hint2")})
classe de classe {}
Exemple 2: Utilisation de plusieurs annotations (nouvelle méthode)
La copie de code est la suivante:
@Hint ("hint1")
@Hint ("hint2")
classe de classe {}
Dans le deuxième exemple, le compilateur Java définira implicitement l'annotation @Hints pour vous.
La copie de code est la suivante:
Indice indice = personne.class.getAnnotation (hint.class);
System.out.println (indice);
Indices Hints1 = Person.class.getAnnotation (indices.class);
System.out.println (Hints1.Value (). Longueur);
Indice [] hints2 = personne.class.getAnnotationsByType (hint.class);
System.out.println (Hints2.Length);
Même si nous ne définissons pas l'annotation @Hints sur la classe de personne, nous pouvons toujours obtenir une annotation @Hints via GetAnnotation (indice.class).
De plus, des annotations Java 8 ont été ajoutées à deux nouvelles cibles:
La copie de code est la suivante:
@Target ({elementType.type_parameter, elementType.type_use})
@interface myannotation {}
Il s'agit des nouvelles fonctionnalités de Java 8, et il y a certainement plus de fonctionnalités qui attendent d'être découvertes. Il y a beaucoup de choses utiles dans JDK 1.8, telles que Arrays.Parallelsort, Stampedlock et CompecuableFuture.