Skip to the content.

1.5 Εντολές Αποφάσεων

© Γιάννης Κωστάρας


<- Δ ->

Η Java διαθέτει δυο εντολές αποφάσεων ή ελέγχου ροής: if και switch.

Εντολή if

Σύνταξη:

if (συνθήκη) {
   εντολές
} else if (συνθήκη) {
   εντολές
} ... 
} else {
   εντολές
}

Η συνθήκη είναι μια λογική μεταβλητή (boolean) ή μια έκφραση που επιστρέφει λογική τιμή.

Π.χ.

if (grade > 17) {
  System.out.println("Άριστα");
} else if (grade > 15) { 
  System.out.println("Πολύ καλά");
} else if (grade > 13) {
  System.out.println("Καλά");
} else if (grade >= 10) {
  System.out.println("Μέτρια");
} else {
  System.out.println("Απορριπτέος");
}

Μπορούμε να εμφωλιάσουμε εντολές if:

if ("ν".equals(answer)) {
   if (i >= 0) {
	k += 1;
   } else {
	k -= 1
   }
}

Στο πιο πάνω παράδειγμα βλέπουμε μια εντολή if η οποία περιέχει άλλη μια εντολή if.

Τριαδικός τελεστής

Η εντολή απόφασης

if (συνθήκη) {
   εντολές
} else {
   εντολές
}

μπορεί να γραφεί και ως:

μεταβλητή = (συνθήκη) ? εντολές αν true : εντολές αν false

Ο τελεστής ? ονομάζεται τριαδικός τελεστής.

Π.χ.

String result = (num > 0) ? "θετικός" : "αρνητικός";

Εντολή switch

Σύνταξη:

switch(μεταβλητή) {
  case τιμή: 
    εντολές
    break;
  case τιμή: 
    εντολές
    break;
  ...
  default:
   εντολές
}

Η μεταβλητή μπορεί να είναι είτε αριθμητικού τύπου (char, byte, short, int, Character, Byte, Short, Integer), είτε συμβολοσειρά (String), είτε τύπου enum. enum είναι ένας ειδικός τύπος δεδομένων που επιτρέπει να ορίζουμε ένα καθορισμένο αριθμό σταθερών τιμών. Character, Byte, Short, Integer είναι οι αντίστοιχες κλάσεις των πρωτογενών τύπων char, byte, short, int. Θα μιλήσουμε για τις κλάσεις την επόμενη εβδομάδα. Επίσης και η var είναι αποδεκτή.

Ας δούμε ένα παράδειγμα όπου ο έλεγχος γίνεται με enum:

enum Choice {
  RED_PILL, BLUE_PILL
}
Choice choice = ...;  // Choice.RED_PILL ή Choice.BLUE_PILL
switch (choice) {
  case BLUE_PILL:
     System.out.println("Συνέχισε να κοιμάσαι...");
     break;  
  case RED_PILL:
     System.out.println("Καλωσήρθες στο Matrix!");
     break;
}

Προσέξτε, ότι είναι λάθος:

case Choice.BLUE_PILL:

|  Error:
|  an enum switch case label must be the unqualified name of an enumeration constant

Παράδειγμα ελέγχου με αλφαριθμητικό:

final String dayOfWeek = "Saturday";
String result = ""; 
switch (dayOfWeek) {
  case "Sunday":                 
    result = "Κυριακή"; 
    break; 
  case "Monday": 
    result = "Δευτέρα"; 
    break; 
  case "Tuesday": 
    result = "Τρίτη"; 
    break; 
  case "Wednesday": 
    result = "Τετάρτη"; 
    break; 
  case "Thursday": 
    result = "Πέμπτη"; 
    break; 
  case "Friday": 
    result = "Παρασκευή"; 
    break; 
  case "Saturday": 
    result = "Σάββατο"; 
    break; 
  default: 
    result = "Error: " + dayOfWeek + 
             " is not a day of the week"; 
    break; 
} 
System.out.println(result);

Έξοδος:

> Σάββατο

Ακόμα ένα παράδειγμα:

Scanner scan = new Scanner(System.in);
String choice = scan.next();
switch (choice) {
  case "one":
	System.out.println(1);
       break;
  case "two":
	System.out.println(2);
       break;  
  default:
	System.out.println(-1);
}

Η Scanner μας επιτρέπει να διαβάζουμε την μονάδα εισόδου (δηλ. το πληκτρολόγιο). Στο πιο πάνω παράδειγμα διαβάζει μια συμβολοσειρά από την είσοδο, την αποθηκεύει στη μεταβλητή choice και αν είναι "one" ή "two" εμφανίζει στην είσοδο 1 ή 2 αλλοιώς -1.

Το πιο πάνω παράδειγμα της εντολής if μπορεί να γραφτεί κι ως εξής (fall through):

switch (grade) {
  case 20:
  case 19:
  case 18:
	System.out.println("Άριστα");
       break;
  case 17:
  case 16:
	System.out.println("Πολύ καλά");
       break;
  ...  
  default:
	System.out.println("Απορριπτέος");
}

Η default αν και συνηθίζεται να γράφεται πάντα στο τέλος, αυτό δεν περιορίζεται από τη γλώσσα, έτσι μπορείτε να την ορίσετε σε οποιαδήποτε θέση μέσα στη switch.

Νέα switch

Στην έκδοση 12 της γλώσσας εισήχθηκε μια νέα σύνταξη για τη switch η οποία ήταν στη φάση της προεπισκόπισης (preview) μέχρι και την έκδοση 14 (οπότε και έγινε κανονικό χαρακτηριστικό της γλώσσας) ώστε οι προγραμματιστές να μπορούν να παρέχουν ανατροφοδότηση (feedback) από τη χρήση της και πιθανές βελτιώσεις σε μελλοντικές εκδόσεις της γλώσσας. Για να μπορέσετε να τη χρησιμοποιήσετε θα πρέπει να περάσετε την παράμετρο --enable-preview στο jshell της έκδοσης 12 και 13 όπως φαίνεται ακολούθως (δεν απαιτείται πλέον στην έκδοση 14 ή νεώτερη):

$> jshell --enable-preview
|  Welcome to JShell -- Version 12
|  For an introduction type: /help intro

jshell> 

Η εντολή switch, όπως την περιγράψαμε προηγουμένως, έχει αρκετά μειονεκτήματα. Π.χ. αν ξεχάσουμε μια εντολή break τότε η εκτέλεση του προγράμματος συνεχίζεται και στο επόμενο μπλοκ εντολής όπως είδαμε στο προηγούμενο παράδειγμα με τις βαθμολογίες. Αυτό μπορεί να γίνει εσκεμμένα, αλλά είναι πολύ εύκολο να γίνει και από λάθος το οποίο δε μπορεί να βρει ο μεταγλωττιστής (δηλ. είναι λογικό λάθος).

Η νέα σύνταξη έχει ως εξής:

switch(μεταβλητή) {
  case τιμή -> εντολές;
  case τιμή -> εντολές;
  ...
  default -> εντολές;
}

Ας ξαναγράψουμε ένα από τα προηγούμενα παραδείγματα με τη νέα σύνταξη:

jshell> String dayOfWeek = "Saturday";
dayOfWeek ==> "Saturday"

jshell> String result = "";
result ==> ""
 
jshell> switch (dayOfWeek) {
  case "Sunday" -> result = "Κυριακή"; 
  case "Monday" -> result = "Δευτέρα"; 
  case "Tuesday" -> result = "Τρίτη"; 
  case "Wednesday" -> result = "Τετάρτη"; 
  case "Thursday" -> result = "Πέμπτη"; 
  case "Friday" -> result = "Παρασκευή"; 
  case "Saturday" -> result = "Σάββατο"; 
  default -> result = "Error: " + dayOfWeek + 
             " is not a day of the week"; 
} 
$3 ==> "Σάββατο"

jshell> System.out.println(result);
Σάββατο

Βλέπετε πως δεν απαιτείται η break. Η περίπτωση fall through μπορεί να γραφτεί ως εξής:

jshell> int grade = 17;
grade ==> 17

jshell> switch (grade) {
  case 20, 19, 18 -> System.out.println("Άριστα");
  case 17, 16 -> System.out.println("Πολύ καλά");
  case 15, 14 -> System.out.println("Καλά");
  case 10, 13 -> System.out.println("Μέτρια");
  default -> System.out.println("Απορριπτέος");
}
Πολύ καλά

Η switch δεν είναι πλέον απλά μια εντολή, αλλά έχει μετατραπεί σε έκφραση, δηλ. μπορείτε να επιστρέψετε κάποια τιμή:

jshell> String result = switch (dayOfWeek) {
  case "Sunday" -> result = "Κυριακή"; 
  case "Monday" -> result = "Δευτέρα"; 
  case "Tuesday" -> result = "Τρίτη"; 
  case "Wednesday" -> result = "Τετάρτη"; 
  case "Thursday" -> result = "Πέμπτη"; 
  case "Friday" -> result = "Παρασκευή"; 
  case "Saturday" -> result = "Σάββατο"; 
  default -> result = "Error: " + dayOfWeek + 
             " is not a day of the week"; 
} 
result ==> "Σάββατο"

Τέλος, μπορούμε να γράψουμε και μπλοκ εντολών μετά το ->, όπως φαίνεται στο παρακάτω παράδειγμα, χρησιμοποιώντας την yield για να επιστρέψουμε την τιμή:

int score = switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> 6;
    case TUESDAY                -> 7;
    default -> {
      String s = day.toString();
      int result = s.length();
      yield result;
    }
};

Ασκήσεις

  1. Να γράψετε πρόγραμμα που βρίσκει τις λύσεις της δευτεροβάθμιας εξίσωσης. Ο χρήστης δίνει 3 αριθμούς α,β,γ που είναι οι παράμετροι της δευτεροβάθμιας εξίσωσης αx² + βx+ γ = 0. Το πρόγραμμα τυπώνει τις λύσεις της εξίσωσης.
  2. Γράψτε ένα πρόγραμμα που θα διαβάζει 3 αριθμούς και θα επιστρέφει τον μεγαλύτερο από τους 3.
  3. Υπολογίστε αν ένα έτος είναι δίσεκτο. Ένα έτος είναι δίσκεκτο αν διαιρείται με το 4 αλλά όχι με το 100 ή διαιρείται με το 400.
  4. Δοθείσας μιας ημερομηνίας, να υπολογίσετε την ημέρα από την αρχή του έτους. Π.χ. αν δώσει ο χρήστης 14/2/2020 το πρόγραμμα θα εκτυπώνει: Η 14/2/2020 είναι η 45η ημέρα του 2020. Μένουν άλλες 321 ημέρες μέχρι το τέλος του έτους. (Μην ξεχάσετε τα δίσεκτα έτη.)
  5. Να γραφτεί ένα πρόγραμμα που να επιστρέφει τα ρέστα μετά την αγορά ενός αντικειμένου. Μια τυπική εκτύπωση του προγράμματος είναι η παρακάτω:
    Κόστος αγοράς αντικειμένου:  82.53€
    Πλήρωσα                   : 100.00€
    Ρέστα:
      0 x 500€
      0 x 200€
      0 x 100€
      0 x 50€
      0 x 20€
      1 x 10€
      1 x 5€
      1 x 2€
      0 x 1€
      0 x 0.50€
      2 x 0.20€
      0 x 0.10€
      1 x 0.05€
      1 x 0.02€
      0 x 0.01€
    

    ή η παρακάτω (στην κρίση του μαθητή τι θέλει να υλοποιήσει):

      1 x 10€
      1 x 5€
      1 x 2€
      2 x 0.20€
      1 x 0.05€
      1 x 0.02€  
    

Πηγές

  1. Urma R.-G. & Warburton R. (2019), “New switch Expressions in Java 12”, Java Magazine, May/June 2019.
  2. Urma R.-G. & Warburton R. (2019), “Inside Java 13’s switch Expressions and Reimplemented Socket API”, Java Magazine, October 2019.

<- Δ ->