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
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 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.
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
:
byte
, short
, int
, long
),
des char
ou des chaînes de caractères,
switch
est optimisée par rapport à la syntaxe if / else
(voir le chapitre précédent) et c'est pour cela
qu'on a une limitation sur les types de données utilisables par le switch
,
switch
traditionnel n'est pas une expression et ne calcule donc pas de valeur),
break
pour mettre fin à un bloc case
, sans quoi l'exécution se poursuit au
bloc suivant.
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" ); } } } |
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" ); } } } |
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 }$>
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).
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 ); } } |
->
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"; } ); } } |
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 ); } } |
default
, il est possible de mixer les différentes approches (avec ou sans yield
).
case
(ou au default
) ne seront plus visible
en dehors de ce bloc.
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 ;-)
switch
.
Si vous avec déjà fait ce TP, vous pouvez faire un copier/coller et l'adapter à la nouvelle syntaxe.
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 ); } } |
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; } ); } } |
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 :