Participer au site avec un Tip
Rechercher
 

Améliorations / Corrections

Vous avez des améliorations (ou des corrections) à proposer pour ce document : je vous remerçie par avance de m'en faire part, cela m'aide à améliorer le site.

Emplacement :

Description des améliorations :

Le nouveau switch de Java SE 14

Les instructions conditionnelles Les instructions de boucles



Accès rapide :
La vidéo
Rappels sur l'instruction switch traditionnelle
La syntaxe moderne du switch
Un premier exemple basique
Utilisation du switch sous forme d'expression
Le mot clé yield
Travaux pratiques
Le sujet
La correction

la nouvelle forme de l'instruction switch qui va vous être présentée dans ce document est apparue avec Java SE 14. Si vous utilisez une version antérieure de Java, une erreur de compilation sera produite. Pour autant avec le Java SE 13, il est possible de tester cette fonctionnalité en activant le mode « preview » via l'option --enable-preview.

La vidéo

La Java SE 14 ajoute pleins de nouvelles possibilités et notamment des extensions de la syntaxe switch. C'est ce dernier point qui est présenté dans cette vidéo.


Le nouveau switch de Java SE 14

Rappels sur l'instruction switch traditionnelle

Depuis la première version de Java, l'instruction switch vous est proposée. Initialement, sa syntaxe était basée sur celle du langage C. Puis, Java SE 5.0 à permi d'utiliser cette instruction avec des chaînes de caractère.

Il faut néanmoins se souvenir que la forme traditionnelle de switch :

Revoici un exemple d'utilisation « traditionnelle » de l'instruction switch : il montre comment associer un traitement à plusieurs blocs case.

 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 
public class Sample {

    public static void main( String [] args ) {
                        
        int value = (int) (Math.random() * 11);

        switch( value ) {
            case 0:
            case 1:
            case 2:
            case 3:
            case 4:
                System.out.println( "Petit chiffre" );
                break;
            case 5:
            case 6:
            case 7:
            case 8:
            case 9:
                System.out.println( "Grand chiffre" );
                break;
            default:
                System.out.println( "Ce n'est plus un chiffre, mais un nombre" );
        }
        
    }

}
Rappels sur la syntaxe traditionnelle du switch

La syntaxe moderne du switch

Un premier exemple basique

Donc, Java SE 14 propose une syntaxe plus moderne. Cette syntaxe est plus simple et peut facilement être reconnue grâce à l'utilisation de l'opérateur ->. L'exemple suivant cherche à réaliser la même chose que l'exemple précédent, mais avec la nouvelle syntaxe : j'espère que vous apprécierez l'aspect plus « compact ».

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
public class Sample {

    public static void main( String [] args ) {
                        
        int value = (int) (Math.random() * 11);

        switch( value ) {
            case 0, 1, 2, 3, 4 -> System.out.println( "Petit chiffre" );
            case 5, 6, 7, 8, 9 -> System.out.println( "Grand chiffre" );
            default -> System.out.println( "Ce n'est plus un chiffre, mais un nombre" );
        }
        
    }

}
Rappels sur la syntaxe traditionnelle du switch

Une branche case peut donc maintenant accepter plusieurs valeurs. Ces valeurs doivent être séparée par des virgules.

Notez aussi qu'il n'est plus nécessaire d'utiliser le mot clé break. Avec la syntaxe ->, le passage au case suivant n'est plus possible en cas d'absence du mot clé. Vous ne risquerez donc plus de l'oublier !

Il faut comprendre que les codes machine produits sont les mêmes entre les deux approches : on est donc toujours limité sur les types de données utilisable par le switch étant donné que le compilateur doit jouer des optimisations. Le switch « nouvelle génération » ne peut donc toujours pas être utilisé avec des valeurs flottantes.

Si vous souhaitez voir l'optimisation produite, vous pouvez utiliser l'outil javap proposé par votre JDK (Java Development Kit). Il permet de désassembler un fichier .class : vous visualiserez donc du byte code pour le processeur Java (la JVM).

$> javap -c Sample
Compiled from "Sample.java"
public class Sample {
  public Sample();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: invokestatic  #7                  // Method java/lang/Math.random:()D
       3: ldc2_w        #13                 // double 11.0d
       6: dmul
       7: d2i
       8: istore_1
       9: iload_1
      10: tableswitch   { // 0 to 9
                     0: 64
                     1: 64
                     2: 64
                     3: 64
                     4: 64
                     5: 75
                     6: 75
                     7: 75
                     8: 75
                     9: 75
               default: 86
          }
      64: getstatic     #15                 // Field java/lang/System.out:Ljava/io/PrintStream;
      67: ldc           #21                 // String Petit chiffre
      69: invokevirtual #23                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      72: goto          94
      75: getstatic     #15                 // Field java/lang/System.out:Ljava/io/PrintStream;
      78: ldc           #29                 // String Grand chiffre
      80: invokevirtual #23                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      83: goto          94
      86: getstatic     #15                 // Field java/lang/System.out:Ljava/io/PrintStream;
      89: ldc           #31                 // String Ce n\'est plus un chiffre, mais un nombre
      91: invokevirtual #23                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      94: return
}$>
ainsi, on voit bien, avec l'instruction byte code tableswitch, le tableau de pointeurs pré-calculé pour chaque valeur testée par l'instruction switch. Contrairement à l'emploi d'une instruction if, on ne réalisera pas un grand nombre de comparaisons et le temps nécessaire pour localiser le code à exécuter est constant (quelle que soit la valeur considérée).

Utilisation du switch sous forme d'expression

Il est possible d'utiliser une instruction switch sous forme d'expression. Cela peut vous permettre, par exemple, d'initialiser une variable avec une valeur qui dépende de plusieurs conditions. Voici un exemple d'utilisation de cette nouvelle forme du switch.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
public class Sample {

    public static void main( String [] args ) {
                        
        int value = (int) (Math.random() * 11);

        String result = switch( value ) {
            case 0, 1, 2, 3, 4 -> "Petit chiffre";
            case 5, 6, 7, 8, 9 -> "Grand chiffre";
            default -> "Ce n'est plus un chiffre, mais un nombre";
        };

        System.out.println( result );
        
    }

}
Exemple d'utilisation d'un switch sous forme d'expression
dans l'exemple ci-dessus, chaque valeur proposée à la droite d'un opérateur -> doit être de type String, étant donné que la variable result est basée sur ce type.

Voici un autre exemple de code ou un switch est utilisé en plein milieu d'un appel de méthode.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
public class Sample {

    public static void main( String [] args ) {
                        
        int value = (int) (Math.random() * 11);

        System.out.println( switch( value ) {
            case 0, 1, 2, 3, 4 -> "Petit chiffre";
            case 5, 6, 7, 8, 9 -> "Grand chiffre";
            default -> "Ce n'est plus un chiffre, mais un nombre";
        } );
        
    }

}
Utilisation d'un switch dans un appel de méthode

Le mot clé yield

Ce mot clé sera utile si vous utilisez le switch sous forme d'expression. Dans cette situation, il peut arriver que vous ayez besoin de plusieurs lignes de code pour calculer la valeur finale du switch. Ces différentes lignes de code devront être placées entre une paire d'accolades et pour indiquer que le calcul est terminé, vous devrez utiliser le mot clé yield. Voici un exemple d'utilisation de ce mot clé.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
public class Sample {

    public static void main( String [] args ) {
                        
        int value = (int) (Math.random() * 11);

        String result = switch( value ) {
            case 0, 1, 2, 3, 4 -> {
                double sqrt = Math.sqrt( value );
                yield "Petit chiffre dont la racine carré vaut " + sqrt;
            }
            case 5, 6, 7, 8, 9 -> {
                double square = value * value;
                yield "Grand chiffre dont le carré vaut " + square;
            }
            default -> "Ce n'est plus un chiffre, mais un nombre";
        };

        System.out.println( result );
        
    }

}
Exemple d'utilisation du mot clé yield
comme vous le constatez avec la branche default, il est possible de mixer les différentes approches (avec ou sans yield).
bien entendu, les variables déclarées dans un bloc d'instructions associé à un case (ou au default) ne seront plus visible en dehors de ce bloc.

Travaux pratiques

Le sujet

Le but de ce TP est d'écrire un programme permettant d'appliquer une opération sur deux valeurs numériques. L'opérateur ainsi que les valeurs doivent être saisis à partir de la console en suivant le format suivant : java Demo operator value1 value2. Un minimum de quatre opérateurs doivent être fournis : add, sub, mul et div. Voici un petit exemple d'utilisation du programme à développer.

$> java Demo
Usage: java Demo operator value1 value2
$> java Demo add 10.2 3.4
13.6
$> java Demo sub 10.2 3.4
6.8
$> java Demo mul 5 3
15.0
$> java Demo div 10 5
2.0
$>

Voila, c'est maintenant à vous de me proposer une solution à ce problème, mais en utilisant la nouvelle forme du switch. Jouez le jeu et ne passez pas directement à la correction ;-)

oui, il s'agit bien du même TP que pour l'utilisation de la syntaxe traditionnelle du switch. Si vous avec déjà fait ce TP, vous pouvez faire un copier/coller et l'adapter à la nouvelle syntaxe.

La correction

Pour choisir l'opération à exécuter en fonction de l'opérateur renseigné, je vous conseille d'utiliser l'instruction switch afin d'avoir un programme plus lisible et efficace. Voici ma correction.

 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 
public class Demo {

    public static void main( String [] args ) {

        if ( args.length != 3 ) {
            System.out.println( "Usage: java Demo operator value1 value2" );
            System.exit( 0 );
        }

        String operatorName = args[0];
        double value1 = Double.parseDouble( args[1] );
        double value2 = Double.parseDouble( args[2] );

        String result = switch( operatorName ) {
            case "add" -> "" + ( value1 + value2 );
            case "sub" -> "" + ( value1 - value2 );
            case "mul" -> "" + ( value1 * value2 );
            case "div" -> "" + ( value1 / value2 );
            default -> "Undefined operator " + operatorName;
        };
        
        System.out.println( result );

    }

}
Un évaluateur d'expressions développé grâce au switch.

De plus, comme la méthode System.out.println propose une signature acceptant un object quelconque (typé Object), on peut donc lui passer n'importe quelle valeur (un entier, un flotant ou une chaîne de caractères). Il est carrément possible d'écrite ce type de code.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
public class Demo {

    public static void main( String [] args ) {

        if ( args.length != 3 ) {
            System.out.println( "Usage: java Demo operator value1 value2" );
            System.exit( 0 );
        }

        String operatorName = args[0];
        double value1 = Double.parseDouble( args[1] );
        double value2 = Double.parseDouble( args[2] );

        System.out.println( switch( operatorName ) {
            case "add" -> value1 + value2;
            case "sub" -> value1 - value2;
            case "mul" -> value1 * value2;
            case "div" -> value1 / value2;
            default -> "Undefined operator " + operatorName;
        } );
        
    }

}
Le switch et le polymorphisme
si le concept de polymorphisme ne vous parle pas encore, rien de grave : nous en parlerons dans un futur chapitre.


Les instructions conditionnelles Les instructions de boucles