Oracle sort la Preview de Java SE 8 pour ARM, avec JavaFX
Les développeurs peuvent créer des applications pour Raspberry Pi

Le , par Hinault Romaric

0PARTAGES

2  0 
Mise à jour du 20/12/2012

Près de deux mois après la sortie de la préversion de Java SE 8, lors de la conférence JavaOne, Oracle publie une déclinaison de la plateforme de développement pour ARM.

La préversion de Java SE 8 pour ARM va permettre de développer des applications Java pour les systèmes embarqués et autres dispositifs reposant sur l’architecture ARM à l’instar du Raspberry Pi. Elle embarque une version de JavaFX (sur Linux), le framework de développement d’Applications Internet Riches.

Pour rappel, Java SE 8 introduira comme nouveautés : les expressions lambda, le moteur JavaScript Nashorn, les annotations, la nouvelle API « date and time » et bien plus.

La sortie de la version finale de la plateforme est prévue pour septembre 2013.




Télécharger Java SE 8 pour ARM

Source : Oracle

Et vous ?

Qu'en pensez-vous ?

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

Avatar de Gugelhupf
Modérateur https://www.developpez.com
Le 20/12/2012 à 19:00
J'ai remarqué que les lambdas de Java 8 ressemblaient à celui de C++11.

Sympa d'inclure un Joda Time dans le standard.
Par contre j'aurai bien aimé qu'il y est les dates au format relatif.
Quelque chose du genre :
Code : Sélectionner tout
1
2
// Premier Mercredi du moins prochain
DateTime d = new DateTime("first Wednesday of next month");
Pourrait-t-on avoir des informations plus précises sur les différentes nouveautés cités ?
Avatar de adiGuba
Expert éminent sénior https://www.developpez.com
Le 21/12/2012 à 10:00
Citation Envoyé par bouye Voir le message
Ouaip c'est un peu pour ça que je trouve le truc moins efficace que les closures où il fallait juste transmettre le nom d'une fonction qui correspondait au type attendu. Ici, il faut utiliser une interface avec une seule méthode, c'est pas pratique pour tous les mouse et keyboard listener de AWT/Swing/JavaFX.
Le problème avec cette solution, c'est qu'elle ne s'applique pas bien à toutes les interfaces, et que cela pourrait engendrer des erreurs "bizarres".

En effet : que faire avec les méthodes non implémentées ?
leur attribuer un corps "vide" ?
remonter une exception (UnsupportedOperationException) ?

Si cela laisse le corps vide, ca marche bien avec les listeners, mais cela peut aboutir à des cas incohérent pour d'autre type d'interface. Image une méthode "add(E)" qui ne fasse rien. Tu penses stocker ton objet mais il n'en est rien !

Si cela remonte une exception, cela permet de détecter immédiatement le problème, mais cela empêche l'utilisation dans des listeners...

De même : que faire lorsqu'elles retournent une valeurs ?
retourner une valeur "nulle" (null, false, 0, 0.0 selon le cas)
retourner une exception ?

Bref dans tous ces cas là il est préférable d'adapter l'API avec une interface "mono-méthode"...

a++
Avatar de adiGuba
Expert éminent sénior https://www.developpez.com
Le 21/12/2012 à 11:35
Au passage je viens de découvrir une petit modif anodine mais bien sympathique dans l'API Logger.

En général on effectue un log de la manière suivante :
Code : Sélectionner tout
	LOG.log(Level.INFO, "Message " + args);
Toutefois ce code à un défaut, c'est que le message est généré AVANT l'appel de la méthode log(), et qu'il sera donc construit en mémoire même lorsque les logs de ce niveau sont désactivé.

Pour pallier à cela on utiliser généralement un if pour vérifier le niveau :
Code : Sélectionner tout
1
2
3
	if (LOG.isLoggable(Level.INFO)) {
		LOG.log(Level.INFO, "Message " + args);
	}


Dans la preview du JDK8 on peut désormais utiliser un Supplier<String> pour générer le message.
Supplier<T> est juste défini comme cela :
Code : Sélectionner tout
1
2
3
public interface Supplier<T> {
    public T get();
}

L'intérêt c'est qu'on peut donc utiliser une expression lambda pour la génération du message :
Code : Sélectionner tout
	LOG.log(Level.INFO, () -> "Message " + args );
Du coup il est inutile de vérifier le niveau avant l'appel, puisque le message ne sera généré que lors de l'appel de la méthode get() du Supplier, et uniquement lorsque le niveau de log correspondant est activé...

a++
Avatar de bouye
Rédacteur/Modérateur https://www.developpez.com
Le 22/12/2012 à 14:42
Heu, j'ai toujours du mal avec leur notation à savoir à quel moment sont faits les allocations des closures/classes anonymes. Encore plus quand c'est sensé produire du bytecode compatible avec la version antérieure. Tu es bien sur de ce que tu avances ?
Avatar de adiGuba
Expert éminent sénior https://www.developpez.com
Le 22/12/2012 à 16:08
Citation Envoyé par bouye Voir le message
Heu, j'ai toujours du mal avec leur notation à savoir à quel moment sont faits les allocations des closures/classes anonymes. Encore plus quand c'est sensé produire du bytecode compatible avec la version antérieure. Tu es bien sur de ce que tu avances ?
Oui j'ai testé cela dans l'early-access JDK8+lambda : http://jdk8.java.net/lambda/

Sinon cela ne produit pas du bytecode compatible dans le sens où il faudra à tout prix une JVM 1.8 pour faire tourner le code.

En fait le compilateur va générer une méthode statique qui contiendra le code de la lambda, et va inclure un appel dynamique vers cette méthode via l'invokedynamic et les MethodHandle.

Grosso modo le code suivant :
Code : Sélectionner tout
1
2
3
public void method(String args) {
	LOG.log(Level.INFO, () -> "Message " + args );
}

Va générer quelque chose de la sorte :
Code : Sélectionner tout
1
2
3
4
5
6
7
public void method(String args) {
	LOG.log(Level.INFO, invokedynamic bootstrap[lambda$1]);
}

static String lambda$1(String args) {
	return "Message " + args;
}

Bien sûr l'instruction "invokedynamic bootstrap[lambda$1]" n'est pas du Java, mais une représentation d'un appel dynamique permettant de créer le lambda.

Lors de cet appel dynamique, la JVM va retourner un type "lambda proxy" qui "simulera" l'interface fonctionnelle (Supplier<T> dans cet exemple).
Et apparemment la JVM pourra effectuer là dessus des optimisations très importante en allant carrément jusqu'à remplacer l'appel directement dans le code à l'intérieur de la méthode appelée.

J'avoue ne pas tout comprendre bien précisément, mais cela a vraiment l'air très prometteur...

Malheureusement, il y a un "MAIS" ! Apparemment ils sont à la bourre sur l'implémentation de ce proxy lors de l'appel dynamique. Ainsi dans un premier temps l'appel dynamique va se contenter de créer une classe anonyme...

La version optimisé avec le proxy viendra plus tard...

Et si j'ai bien compris tout ceci concerne avant tous la JVM, donc il n'y aura pas besoin de recompiler...

a++
Avatar de bouye
Rédacteur/Modérateur https://www.developpez.com
Le 24/12/2012 à 6:52
Merci de la précision
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++
Avatar de la.lune
Membre chevronné https://www.developpez.com
Le 28/12/2012 à 8:23
adiGuba
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++
Avatar de adiGuba
Expert éminent sénior https://www.developpez.com
Le 30/12/2012 à 19:04
Citation Envoyé par la.lune Voir le message
Là on vient d'apprendre l'ajout du mot clé "default"
C'est le principe des "default's methods" qui permet de définir une implémentation par défaut dans une interface. Les classes qui l'implémente n'auront pas l'obligation d'implémenter la méthode.

Cette notion a eu plusieurs noms, et j'en ai pas mal parlé sur mon blog :


Citation Envoyé par la.lune Voir le message
mais peut-on avoir une méthode par défaut et static aussi?
Cela n'a pas de sens.
Les méthodes static d'une interface ne sont pas hérité ni rien. Elle doivent impérativement être appelé via la syntaxe NomDeLinterface.method().

a++
Contacter le responsable de la rubrique Accueil

Partenaire : Hébergement Web