IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

JavaOne 2012 : Oracle dévoile ses plans pour Java
Les préversions du JDK 8 et JavaFX Scene Builder 1.1 disponibles

Le , par Hinault Romaric

195PARTAGES

7  0 
JavaOne 2012, la plus grande conférence annuelle autour de la plateforme Java se déroule actuellement à San Francisco.

Oracle a profité de l’occasion pour dévoiler sa feuille de route pour Java et renouveler son engagement à faire évoluer le langage afin de rassurer les utilisateurs sceptiques face aux récentes découvertes de failles dans la plateforme.

Pendant ces prochains mois, Oracle travaillera essentiellement sur Java SE 8. Au menu : l’éditeur prévoit l’intégration des expressions lambda, du moteur JavaScript Nashorn (déjà disponible dans la préversion de NetBeans 7.3), les annotations, la nouvelle API « date and time » et bien plus.

Oracle a également officialisé le projet Sumatra, qui vise à mettre fin à l’utilisation des bibliothèques externes pour l’accélération GPU des applications Java ainsi qu’au processus de conversion entre Java et OpenCL (librairie multiplateforme qui permet d'utiliser les processeurs graphiques pour réaliser des calculs lourds). Le projet Sumatra sera disponible avec Java SE 8.




La préversion du JDK 8 peut déjà être testée sur le site java.net. La sortie de la version finale est prévue pour septembre 2013. On va regretter cependant le report à Java 9 du projet Jigsaw, qui devait ajouter au langage un système de module.

Java EE 7 (l’édition pour entreprise) est annoncé pour avril 2013 et apportera comme nouveautés : une API WebSocket, l’API JCACHE pour une mise en cache temporaire des objets Java, un modèle de programmation pour applications Batch et une API pour la manipulation des données au format JSON. Avec cette version de Java EE, Oracle proposera Glassfish 4.0 comme plateforme de référence.

En ce qui concerne sa plateforme de développement d’Applications Internet Riches JavaFX, Oracle envisage de passer de JavaFX 2.0 (la version actuelle) à JavaFX 8 lorsque sortira le JDK 8. Cette version de JavaFX disposera par défaut au niveau de l’interface utilisateur d’une boite à outils pour Java SE 8 Embedded. Une nouvelle API sera proposée pour la création d’interfaces utilisateur avec un meilleur support des balises HTML5, WebView et JavaFX Scene Builder 2.0.

JavaFX Scene Builder, l’outil de mise en page visuelle pour la plateforme JavaFX, qui permet aux utilisateurs de créer des interfaces utilisateur en glissant et en positionnant les composants à partir d'une palette dans une scène est actuellement disponible en version 1.1 développeur avec un support pour Linux 32 et 64 bits.

Toutes ces annonces montrent l’engagement d’Oracle à vouloir faire évoluer l’écosystème Java.

Télécharger la préversion de JDK8

Télécharger la préversion de JavaFX Scene Builder 1.1

La couverture de JavaOne par Bouye

Source : JavaOne 2012

Et vous ?

Que pensez-vous de ces annonces d'Oracle ?

Une erreur dans cette actualité ? Signalez-nous-la !

Avatar de adiGuba
Expert éminent sénior https://www.developpez.com
Le 27/12/2012 à 12:01
Juste pour info, l'early-access Lambda est assez complète : http://jdk8.java.net/lambda/

Il y a de quoi bien s'amuser même si l'inference des types n'est pas finalisé (du coup il faut parfois caster explicitement, ce qui alourdit la syntaxe).

Quelques exemples vites fait :

1 - On peut effectuer des itérations internes sur les éléments Iterable :
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
        Iterable<String> iterable = ...

       // Ceci :
       for (String s : iterable) {
            System.out.println(s);
        }
       // Peut-être remplacé par cela :
        iterable.forEach((String s) -> {
            System.out.println(s);
        });
Par defaut cela revient à la même chose (c'est à dire à utiliser un Iterator), mais chaque implémentation peut définir sa propre implémentation de forEach() plus optimisé (c'est le cas par exemple d'ArrayList qui effectuera directement le parcours sur son tableau interne).

Au passage ce code peut être encore plus compacte, de diverses manières :
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
        // Expression Lambda complète, dont l'expression peut prendre plusieurs lignes :
        iterable.forEach((String s) -> {
            System.out.println(s);
        });
        // Lorsque le code de l'expression se résume à une ligne,
        // on peut se passer des crochet et du point-virgule final { ... ;}
        iterable.forEach((String s) -> System.out.println(s));
        // Le type du (ou des) paramètre est déduit du contexte
        // il est donc possible de s'en passer :
        iterable.forEach((s) -> System.out.println(s));
        // Lorsqu'on n'a qu'un seul et unique paramètre,
        // on peut se passer des parenthèses :
        iterable.forEach(s -> System.out.println(s));
Mieux encore, lorsqu'on se contente d’appeler une méthode, et que sa signature correspond à l'interface fonctionnelle, on peut remplacer l'expression Lambda par un pointeur de méthode (notez bien les doubles deux-points :: )
Code : Sélectionner tout
        iterable.forEach(System.out::println);

Cette méthode forEach() est encore plus intéressante sur les Map :
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
        Map<String, Object> map = ...

        // Avec un Iterator on se ballade plein de chose inutile :
        for (Map.Entry<String,Object> e : map.entrySet()) {
            String k = e.getKey();
            Object v = e.getValue();
            System.out.println(k + " = " + v);
        }

        // Alors qu'on peut aller droit à l'essentiel avec les expr. lambda :
        map.forEach((k,v) -> {
            System.out.println(k + " = " + v);
        });


L'API de Collections profite des "Default Method" pour se doter de quelques méthodes utiles, exemple :
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
        List<String> list = ...
        
        // Passer tous les éléments de la liste en majuscule :
        list.replaceAll(String::toUpperCase);
        // Supprimer tous les éléments de moins de 4 caractères :
        list.removeAll(s -> s.length() < 4);
        // Trier les éléments selon l'ordre naturel (compareTo()) :
        list.sort(Comparators.naturalOrder());
        // Trier les éléments selon leurs tailles :
        list.sort(Comparators.comparing(String::length));
Note : cette dernière ligne ne fonctionne pas encore à cause de l'inférence des types qui n'est pas finalisé, et pour le moment il faut spécifier explicitement le paramétrage Generics, ce qui ne sera plus le cas dans la version finale :
Code : Sélectionner tout
list.sort(Comparators.<String,Integer>comparing(String::length));


Mais le plus gros ajout vient des streams : lorsqu'on utilise un stream, on peut filtrer ou modifier les valeurs de la source de données, sans modifier cette source.

Quelques exemples (loin d'être exhaustif) :
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
        Collection<String> coll = ...

        // On prend tous les éléments de 6 caractères,
        // en ignorant les doublons,
        // que l'on va trier par taille,
        // puis convertir en majuscule,
        // pour finalement afficher les valeurs :
        coll.stream()
                .filter(s -> s.length() < 6)
                .uniqueElements()
                .sorted(Comparators.<String, Integer>comparing(String::length))
                .map(String::toUpperCase)
                .forEach(System.out::println);

        // Même chose que ci-dessus, mais en stockant le résultat dans une ArrayList :
        List<String> result = coll.stream()
                .filter(s -> s.length() < 6)
                .uniqueElements()
                .sorted(Comparators.<String, Integer>comparing(String::length))
                .map(String::toUpperCase)
                .into(new ArrayList<String>());

        // Afficher seulement 5 éléments, après le 10ième
        // (cela permet de mettre en place un système de pagination)
        coll.stream()
                .slice(10, 5)
                .forEach(System.out::println);

        // Recherche de la valeur minimum, selon l'ordre naturel :
        String min = coll.stream()
                .min(Comparators.naturalOrder())
                .get();

La grosse force des "stream" étant de pouvoir paralléliser les traitements.
En effet il suffit d'utiliser la méthode parallelStream() à la place de stream() pour que le traitement soit effectuer en parallèle (si cela est possible bien entendu).

a++
4  0 
Avatar de adiGuba
Expert éminent sénior https://www.developpez.com
Le 31/12/2012 à 16:08
Citation Envoyé par Gugelhupf Voir le message
abiGuba, quels seront les différences entre ces interfaces et une classe abstraite ?
Les interfaces ne peuvent pas contenir d'état car elles ne peuvent pas contenir d'attribut d'instance.

Citation Envoyé par Gugelhupf Voir le message
Est-ce que c'est semblable aux Traits et Mixins ?
Oui cela s'en approche beaucoup.

Citation Envoyé par Gugelhupf Voir le message
Comment résoudre le problème d'héritage multiple si une classe implémente 2 interfaces qui contiennent une méthode defaut avec le même nom mais un contenu différent ?
S'il n'y a aucun lien entre les deux interfaces, cela provoquera une erreur de compilation. Il faudra alors l'implémenter.
On peut bien sûr se contenter de réutiliser une implémentation d'une interface via une syntaxe spécifique, par exemple :
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
interface A {
    public default void method() {
        System.out.println("A::method");
    }
}

interface B {
    public default void method() {
        System.out.println("B::method");
    }
}

class C implements A, B {
	public void method() {
		A.super.method();
	}
}

Par contre les règles sont plus souples, car si la méthode est implémenter dans une classe parente, cela prendra toujours la priorité sur les méthodes par défaut, qui comme leur nom l'indique, ne seront utilisé QUE dans le cas où la classe ne possèdent pas d'implémentation.

Là où cela est très intéressant, c'est que la résolution de la méthode est géré par la JVM au runtime. C'est à dire que cela permet d'ajouter une méthode à une interface sans avoir à recompiler toutes les classes qui l'implémentent...

Citation Envoyé par Gugelhupf Voir le message
Ça parait logique de ce point de vue, mais alors pourquoi la compilation est autorisée en C++ ? ...
Les règles d'héritage du C++ et de Java sont très différente.
En Java toutes les méthodes sont implicitement virtuelles et donc hérités par défaut, alors que c'est exactement l'inverse en C++.
Du coup les problèmes que l'on peut rencontrer via l'héritage multiple sont moins visible...

a++
3  0 
Avatar de adiGuba
Expert éminent sénior https://www.developpez.com
Le 30/12/2012 à 13:04
Je viens de découvrir autre chose concernant les interfaces.

Pour rappel il y a les "default methods" qui permettront d'intégrer du code dans les interfaces :
Code : Sélectionner tout
1
2
3
4
5
6
7
public interface Demo {
    public void method1();

    public default void method2() {
         System.out.println("method2");
    }
}
Les classes qui implémentent cette interface pourront se contenter d'implémenter la méthode method1().
La méthode method2() est optionnelle et utilisera le code par défaut si elle n'est pas implémenté par la classe.

Mais ce n'est pas tout, on pourra utiliser des méthodes private, destiné à être utiliser dans les "default methods" afin de pouvoir mutualiser le code.
Par exemple :
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public interface Demo {
    public void method1();

    public default void method2() {
	this.print("method2");
    }

    public default void method3() {
	this.print("method3");
    }

    private void print(String text) {
         System.out.println(text);
    }
}


Enfin les interfaces pourront contenir des méthodes static :
Code : Sélectionner tout
1
2
3
4
5
public interface Demo {
    public static void method() {
	/* ... */
    }
}

Attention toutefois car à l'heure actuelle ceci n'est implémenté que dans le compilateur. En clair cela va compiler normalement, mais cela risque de générer des erreurs à l'exécution...

Sources :
Enhancement: Add support for static interface methods
Enhancement: Add experimental support for private (instance) interface methods

a++
2  0 
Avatar de adiGuba
Expert éminent sénior https://www.developpez.com
Le 20/01/2013 à 16:16
Citation Envoyé par Gugelhupf Voir le message
1. J'aurais aimé savoir s'il y avait une différence entre le fait de préciser le type d'un argument ou non :
Il n'y a aucune différence. S'il n'est pas précisé le type est déduite selon le contexte par le compilateur...

Citation Envoyé par Gugelhupf Voir le message
2. Aussi, si on utilise un lambda dans une classe, pourra-t-on automatiquement avoir accès au this dans le lambda (sans avoir à le faire passer par un paramètre) ?
Oui, tout simplement en utilisant this :
Code : Sélectionner tout
Runnable r = () -> this.method();
Citation Envoyé par Gugelhupf Voir le message
3. Qu'en est-t-il du Java pour les fermetures (utilisation de variable extérieur au bloc lambda) ?
C'est tout à fait possible :
Code : Sélectionner tout
1
2
3
4
5
6
// On retourne x + y
IntBinatyOperator op1 = (x, y) -> x + y;

// On retourne x + y + z (z variable extérieur au bloc lambda)
int z = 10;
IntBinatyOperator op1 = (x, y) -> x + y + z;
La seule restriction c'est que la variable doit être implicitement final.
C'est à dire que la variable doit être définie et ne doit pas être modifié dans la lambda ou en dehors...

a++
2  0 
Avatar de adiGuba
Expert éminent sénior https://www.developpez.com
Le 01/01/2013 à 21:51
@la.lune
Réponse courte : oui ton code fonctionne

Réponse longue :

Une interface fonctionnelle c'est juste une interface qui ne contient qu'une seule et unique méthode abstraite (sans compter les "default's methods" donc), comme par exemple Runnable.

Les lambdas et les références de méthode ne peuvent être convertis qu'en une interface fonctionnelle, à condition que leurs signatures correspondent.

Par exemple dans ce cas là la méthode Iterable::forEach() est définie comme ceci :
Code : Sélectionner tout
1
2
3
4
5
    public default void forEach(Block<? super T> block) {
        for (T t : this) {
            block.accept(t);
        }
    }
Et Block fait partie du package java.util.function, qui inclut un ensemble d'interface fonctionnelle basique...
Grosso-modo elle est définie comme ceci :
Code : Sélectionner tout
1
2
3
4
5
public interface Block<T> {

    public void accept(T t); 

}
Et c'est la signature de cette méthode qu'il faudra donc respecter avec la lambda (ou la référence de méthode).

Si tu références une méthode static, alors la signature de cette méthode devra correspondre à la signature de l'interface. C'est le cas dans ton exemple donc cela marchera bien

Après tu as encore le cas particulier des méthodes d'instances, où tu as deux possibilités :
  • Si tu références une méthode d'instance via son type, et la signature est alors modifié en rajoutant le type en tant que premier paramètre, ce qui permettra de passer l'instance lors de l'appel.
  • Si tu la référence via une instance d'un objet, la signature n'est pas modifié et l'appel se fera sur l'instance indiqué.


Exemple Object::toString pourra être associer avec une interface fonctionnelle tel quel celle-ci :
Code : Sélectionner tout
1
2
3
public interface Exemple {
    public String method(Object o);
}

A l'inverse pour une instance d'objet "o", o::toString sera associable avec une interface fonctionnelle comme ceci :
Code : Sélectionner tout
1
2
3
public interface Exemple {
    public String method();
}


Je ne sais pas si tout est bien clair...

a++
1  0 
Avatar de adiGuba
Expert éminent sénior https://www.developpez.com
Le 02/01/2013 à 9:59
Citation Envoyé par la.lune Voir le message
Aussi, je suis je suis un peu perdu quand tu parles de correspondance entre signature de méthode et signature d'interface, ou bien tu veux parler de correspondance entre signature de méthode et signature de la méthode de l'interface fonctionnelle.
Oui je voulais bien parler de la signature de la méthode de l'interface fonctionnelle.

Une lambda (ou une référence de méthode) ne peut être associé qu'à une interface fonctionnelle, et il faut que la signature correspondent à celle de la méthode :

Par exemple :
Code : Sélectionner tout
ActionListener listener = (ActionEvent e) -> System.out.println("ActionEvent = " + e);
L'expression lambda a la signature suivante : "void(ActionEvent)", ce qui correspond à la signature de la méthode de l'interface fonctionnelle ActionListener qui défini la méthode suivante :
Code : Sélectionner tout
public void actionPerformed(ActionEvent e);
Au passage le "Type Inférence" rentre en jeu, ce qui nous permet de ne pas spécifier le type du paramètre dans la lambda :
Code : Sélectionner tout
ActionListener listener = (e) -> System.out.println("ActionEvent = " + e);


Et c'est la même chose pour les références de méthode. Si on a une méthode définie comme ceci :
Code : Sélectionner tout
1
2
3
public static void onEvent(ActionEvent e) {
    ...
}
On peut l'associer à un ActionListener puisque la signature de la méthode concorde bien à la signature void(ActionEvent) :
Code : Sélectionner tout
ActionListener listener = MaClasse::onEvent;


S'il s'agit d'une méthode d'instance :
Code : Sélectionner tout
1
2
3
4
5
6
public class MaClasse {

    public void doSomething(ActionEvent e) {
         ...
    }
}
On ne peut pas l'associer comme cela puisque l'instance se rajoute à la signature, qui devient void(MaClasse,ActionEvent).
Code : Sélectionner tout
ActionListener listener = MaClasse::doSomething; // ERREUR
Pour que la signature corresponde, il faut lui associer une instance, par exemple :
Code : Sélectionner tout
1
2
MaClasse cls = new MaClasse();
ActionListener listener = cls::doSomething; // OK
Dans ce cas là l'instance ("cls" dans l'exemple) sera utilisée pour l'appel de la méthode, qui conserve du coup sa signature originale...

Et pour les méthodes c'est la même chose. Les méthodes qui utiliseront les lambdas n'ont rien de spécial, si ce n'est qu'elles utilisent une interface fonctionnelle. Mais même si cette notion est "nouvelle", cela ne l'est pas vraiment car l'API standard est déjà pleine d'interface fonctionnelle...

Du coup on pourra utiliser les lambdas/références de méthode avec des APIs existante, du moment qu'elles utilisent une interface fonctionnelle :
Code : Sélectionner tout
1
2
3
    MaClasse cls = new MaClasse();
    JButton b = new JButton();
    b.addActionListener(cls::doSomething);

C'est le "Type inference" qui se chargera de vérifier le tout, c'est à dire :
  • Récupérer le type du paramètre de addActionListener() (qui est justement un ActionListener).
  • Vérifier qu'il s'agit bien d'une interface fonctionnelle (ce qui est le cas puisqu'elle ne comporte qu'une seule méthode)
  • Vérifier que la signature de la lambda/référence de méthode concorde bien avec la signature de la méthode de l'interface fonctionnelle.


Et en cas de surcharge, le compilo ira chercher la version de la méthode qui correspond.

A noter également l'existence de référence de constructeur (en utilisant ::new), par exemple :
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
	// Création d'un ThreadFactory via une classe anonyme :
	Executors.newCachedThreadPool(new ThreadFactory() {
		@Override
		public Thread newThread(Runnable r) {
			return new Thread(r);
		}
	});

	// Création d'un ThreadFactory via une référence de constructeur :
	Executors.newCachedThreadPool(Thread::new);
	// Ceci utilisera le constructeur Thread(Runnable),
	// qui correspond à la signature de la méthode de ThreadFactory

a++
1  0 
Avatar de adiGuba
Expert éminent sénior https://www.developpez.com
Le 02/01/2013 à 12:10
Autre petite subtilité que j'ai découverte aujourd'hui : de nombreuses interfaces fonctionnelles (déjà existante ou non) sont enrichies de "default's method" permettant diverses choses.

Par exemple pour trier une liste d'User par nom, on pourra utiliser le code suivant :
Code : Sélectionner tout
1
2
3
    List<User> list = ....

    list.sort( Comparators.comparing(User::getFirstName) );
Avec Comparators.comparing() qui nous retourne un Comparator<User> basé sur le getter getFirstName().

Or l'interface Comparator est doté de nouvelle méthode permettant de créer des dérivés.

Par exemple on peut inverser l'ordre de tri très simplement :
Code : Sélectionner tout
1
2
3
    list.sort( Comparators.comparing(User::getFirstName)
            .reverseOrder() );
Ou alors on peut enchainer plusieurs comparaisons qui seront traiter dans l'ordre.
Par exemple pour tirer par nom, prénom puis date de naissance on pourra faire ceci :
Code : Sélectionner tout
1
2
3
    list.sort( Comparators.comparing(User::getFirstName)
            .thenComparing(User::getLastName)
            .thenComparing(User::getBirthday) );


a++
1  0 
Avatar de adiGuba
Expert éminent sénior https://www.developpez.com
Le 03/01/2013 à 10:39
Citation Envoyé par la.lune Voir le message
De plus j'ai une autre question sur la parallélisation dont tu as mentionné sur les multiples instruction dont on applique à une collection,
Juste une remarque : les opérations s'appliquent sur le flux (stream), mais n'affecte pas la collection en elle-même

Citation Envoyé par la.lune Voir le message
alors quand tu dis 'si cela est possible', je me pose la question possible dans le sens où certaines instructions dépendent des précédentes ou dans le sens de la capacité de l'ordinateur de paralléliser, et là aussi il y a deux option soit de la parallélisation juste en différents thread qui serait optimisée avec les architectures multi-core ou bien de la vrai parallélisation.
C'est juste que cela dépend des instructions que tu utilises, et de ce que tu veux faire.

Par exemple si tu veux stocker le résultat dans une collection, il faut que cette dernière soit thread-safe, car si ce n'est pas le cas cela engendrera des erreurs. Du coup même si tu choisis un stream parallel ce type d'opération sera en séquentiel par défaut (en fait c'est l'implémentation de la collection qui peut modifier cela).

Citation Envoyé par la.lune Voir le message
Ma dernière question c'est que tu parles d'interfaces de types qui ne sont pas encore finalisés dans une de tes réponses, alors peux-tu nous donner plus de détailles sur l'objet de ces interfaces et leur domaines d'applications.
En fait c'est juste un nouveau package java.util.function qui les interfaces fonctionnelles les plus courante.

Quelques exemples :

Block<T> qui permet d'exécuter un bout de code en prenant un objet en paramètre (c'est ce qui est utiliser par forEach() par exemple) :
Code : Sélectionner tout
1
2
3
public interface Block<T> {
	public void accept(T t);
}
Function<T, R> qui prend un paramètre T et retourne une valeur R.
Code : Sélectionner tout
1
2
3
public interface Function<T, R> {
	public R apply(T t);
}
Predicate<T> qui permet de tester un élément.
Code : Sélectionner tout
1
2
3
public interface Predicate<T> {
    public boolean test(T t);
}
Supplier<T> qui permet de fournir une valeur.
Code : Sélectionner tout
1
2
3
public interface Supplier<T> {
    public T get();
}
etc...

On y retrouve aussi des versions optimisés pour les types primitifs, ou des versions "Bi" prenant deux paramètres (et utilisé par les Map pour les clef/valeur).

Il n'y a rien d'exceptionnel là dedans, c'est juste pour fournir une base commune qui sera utilisable par tout le monde plutôt que de réécrire tout plein d'interface similaire dans chaque API

a++
1  0 
Avatar de adiGuba
Expert éminent sénior https://www.developpez.com
Le 10/01/2013 à 10:16
Il y a un nouveau build du JDK8/Lambda : http://jdk8.java.net/lambda/

Je n'ai pas vraiment eu le temps de le parcourir, mais l'interface Map s'est enrichie de plusieurs méthodes par défaut, en plus du forEach() dont j'avais déjà parlé !
Rien d'extraordinaire en soit, mais quand même des méthodes bien utile :
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
	/*
	 * Supprime un couple clef/valeur,
	 * seulement si le couple existe.
	 */
	map.remove("KEY", "VALUE");

	/*
	 * Remplace la valeur associé à la clef,
	 * seulement si cette clef existe déjà.
	 */
	map.replace("KEY", "NEWVALUE");

	/*
	 * Remplace la valeur d'un couple clef/valeur
	 * seulement si le couple existe.
	 */
	map.replace("KEY", "VALUE", "NEWVALUE");

	/*
	 * Remplace toutes les valeurs de la Map,
	 * par le résultat de l'expression.
	 * Exemple : mettre toutes les valeurs en Majuscule :
	 */
	map.replaceAll((k,v) -> v.toUpperCase());

	/*
	 * Ajoute un couple clef/valeur,
	 * seulement si la clef n'est pas déjà présente.
	 */
	map.putIfAbsent("KEY", "VALUE");

	/*
	 * Permet de récupérer ET de modifier
	 * la valeur d'une clef dans la Map.
	 */
	String value = map.compute("KEY", (k,v) -> v.toUpperCase());

	/*
	 * Permet de modifier la valeur d'une clef,
	 * seulement si le couple clef/valeur existe.
	 */
	String value = map.computeIfPresent("KEY", (k,v)->"new value");

	/*
	 * Permet de définir la valeur d'une clef,
	 * lorsque le couple clef/valeur est absent.
	 * Sinon on récupère la valeur existante.
	 */
	String value = map.computeIfAbsent("KEY", (k)->"empty");

A noter que ce "computeIfAbsent()" nous permettra d'implémenter une MultiMap en un rien de temps :
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
class MultiMap<K,V> extends HashMap<K,Collection<V>> {

	private Collection<V> creator(K key) {
		return new ArrayList<>();
	}

	public void add(K key, V value) {
		this.computeIfAbsent(key, this::creator).add(value);
	}
}
L'appel add(K,V) permettra d'ajouter l'élément "value" dans la collection, en la créant si neccessaire.

a++
1  0 
Avatar de la.lune
Membre chevronné https://www.developpez.com
Le 03/10/2012 à 15:56
L'importance dans JavaFX8 c'est le support 3D en vrai et le support aussi de l'embarqué. Et vu que presque les syntaxe vont évolué vers Java 8 avec les expressions tous se nouveautés, de plus JavaFX sera une partie intégrant du jdk pas besoin d'installer un jre en plus du jre de java, voilà pourquoi ça va passer à la place de la version 3 à la version 8 pour aller avec java 8
0  0