5.5 Οι εκφράσεις Lambda (Lambda expressions) στην Java

Οι εκφράσεις Lambda (Lambda expressions) εισήχθησαν στην Java 8.

Οι εκφράσεις Lambda στην Java αναφέρονται σε μια συντομευμένη σύνταξη που επιτρέπει τον ορισμό και τη χρήση ανώνυμων συναρτήσεων (anonymous functions) ή ενεργειών (actions). Οι εκφράσεις Lambda είναι ιδιαίτερα χρήσιμες για την απλοποίηση της συντακτικής δομής του κώδικα και την υλοποίηση λειτουργικότητας που αντιστοιχεί σε μία μόνο μέθοδο.

Οι εκφράσεις Lambda είναι αποτέλεσμα της εισαγωγής της λειτουργικότητας προγραμματισμού λειτουργικού υψηλού επιπέδου (functional programming) στην Java, επιτρέποντας την αντιμετώπιση συναρτήσεων ως αντικειμένων. Με τη χρήση εκφράσεων Lambda, μπορούμε να ορίσουμε συναρτήσεις ως παραμέτρους ή να τις αποθηκεύσουμε σε μεταβλητές, προσφέροντας μεγαλύτερη ευελιξία στον τρόπο που γράφουμε κώδικα.

Μια εκφραση Lambda συνήθως αποτελείται από μια λίστα παραμέτρων, το σύμβολο “->” και το σώμα της συνάρτησης. Το σώμα μπορεί να περιέχει μια μόνο εντολή ή ένα μπλοκ εντολών. Οι εκφράσεις Lambda παρέχουν μια συνοπτική και εκφραστική τρόπο για την υλοποίηση απλών λειτουργιών, όπως ανώνυμες εντολές, συγκρίσεις και επεξεργασία συλλογών δεδομένων.

Η σύνταξη μιας εκφρασης Lambda είναι η εξής:

(parameter1, parameter2, ...) -> { code block }

Οι παράμετροι είναι οι παράμετροι που δέχεται η εκφραση και η λίστα τους περικλείεται σε παρενθέσεις. Ο τελεστής “->” χρησιμοποιείται για να δηλώσει ότι ακολουθεί μια εκφραση Lambda και το σώμα της εκφρασης είναι το μπλοκ κώδικα που εκτελείται.

Παρακάτω παρουσιάζουμε ένα παράδειγμα με μια εκφραση Lambda:

// Ορισμός ενός interface με μια μέθοδο operation
interface MathOperation {
   int operation(int a, int b);
}

public class Main {
   public static void main(String args[]) {
      // Δημιουργία μιας μεταβλητής addition τύπου MathOperation με χρήση lambda
      MathOperation addition = (int a, int b) -> a + b;

      // Εκτέλεση της μεθόδου operation της μεταβλητής addition με ορίσματα 10 και 20
      int result = addition.operation(10, 20);

      // Εκτύπωση του αποτελέσματος
      System.out.println("10 + 20 = " + result);
   }
}

Ο παραπάνω κώδικας δημιουργεί ένα λειτουργικό αντικείμενο στη γλώσσα προγραμματισμού Java χρησιμοποιώντας τη λειτουργία lambda.

Καταρχάς, ορίζεται το interface MathOperation με μια μέθοδο operation που παίρνει δύο ακέραιες παραμέτρους και επιστρέφει έναν ακέραιο.

Στη συνέχεια, στην κλάση Main, δημιουργείται μια μεταβλητή addition τύπου MathOperation χρησιμοποιώντας μια λειτουργία lambda (int a, int b) -> a + b. Αυτή η λειτουργία απλά πραγματοποιεί την πρόσθεση των δύο παραμέτρων a και b.

Στη συνέχεια, καλείται η μέθοδος operation του αντικειμένου addition με ορίσματα 10 και 20 και αποθηκεύεται το αποτέλεσμα στη μεταβλητή result.

Τέλος, εκτυπώνεται το αποτέλεσμα “10 + 20 = {result}” στην οθόνη.

Το αποτέλεσμα που θα εμφανιστεί στην οθόνη είναι:

10 + 20 = 30

Αυτό συμβαίνει επειδή η λειτουργία addition πραγματοποιεί την πρόσθεση των δύο ακεραίων παραμέτρων 10 και 20, και το αποτέλεσμα είναι 30. Αυτή η τιμή εκτυπώνεται με το κατάλληλο μήνυμα στην οθόνη.

[adinserter block=”2″]

Παρακάτω παρουσιάζουμε μια πιο συνοπτική μορφή του παραπάνω παραδείγματος με τη χρήση της διεπαφής FunctionalInterface:

@FunctionalInterface
interface MathOperation {
   int operation(int a, int b);
}

public class Main {
   public static void main(String args[]) {
      // Ορισμός της λειτουργίας πρόσθεσης ως εκφρασης Lambda
      MathOperation addition = (a, b) -> a + b;

      // Χρήση της εκφρασης Lambda για την εκτέλεση της πράξης πρόσθεσης
      int result = addition.operation(10, 20);
      System.out.println("10 + 20 = " + result);
   }
}

Ο παραπάνω κώδικας περιέχει τα εξής:

  1. Δηλώνει ένα λειτουργικό περιβάλλον (functional interface) με το όνομα “MathOperation”. Αυτή η δήλωση λειτουργεί ως ορισμός για μια λειτουργία που μπορεί να δέχεται δύο ακέραιες παραμέτρους και να επιστρέφει έναν ακέραιο.
  2. Η κλάση “Main” περιέχει τη μέθοδο “main”, η οποία είναι η εκκίνηση του προγράμματος.
  3. Στο εσωτερικό της μεθόδου “main”, ορίζεται μια μεταβλητή με το όνομα “addition”, η οποία αντιστοιχεί σε μια εκφραση Lambda που αναπαριστά την πράξη πρόσθεσης.
  4. Μετά τον ορισμό της εκφρασης Lambda, γίνεται η χρήση της για την εκτέλεση μιας πράξης πρόσθεσης. Το αποτέλεσμα της πρόσθεσης 10 + 20 αποθηκεύεται στη μεταβλητή “result”.
  5. Τέλος, το αποτέλεσμα εμφανίζεται στην οθόνη με τη χρήση της μεθόδου println().

Συνολικά, ο κώδικας εκτελεί μια πράξη πρόσθεσης (10 + 20) με τη χρήση μιας εκφρασης Lambda και εμφανίζει το αποτέλεσμα (30) στην οθόνη.

Μπορούμε να χρησιμοποιήσουμε επίσης εκφράσεις Lambda για να υλοποιήσουμε ανώνυμες κλάσεις, όπως η ακόλουθη παράδειγμα όπου υλοποιούμε μια ανώνυμη κλάση που υλοποιεί τη διεπαφή ActionListener:

import java.awt.*;
import java.awt.event.*;

public class Main {
   public static void main(String args[]) {
      // Δημιουργία ενός Frame με τίτλο "Lambda Expressions Example"
      Frame frame = new Frame("Lambda Expressions Example");

      // Δημιουργία ενός κουμπιού με το κείμενο "Click Me"
      Button button = new Button("Click Me");
      frame.add(button);

      // Προσθήκη ακροατή γεγονότος στο κουμπί με χρήση λάμδα έκφρασης
      button.addActionListener(e -> {
         System.out.println("Button Clicked!");
      });

      // Ορισμός μεγέθους του παραθύρου (300x200)
      frame.setSize(300, 200);
      // Ορισμός διάταξης ροής για το παράθυρο
      frame.setLayout(new FlowLayout());
      // Ορατότητα του παραθύρου
      frame.setVisible(true);
   }
}

Ο παραπάνω κώδικας δημιουργεί ένα παράθυρο εφαρμογής στην Java με ένα κουμπί. Όταν το κουμπί πατηθεί, εκτελείται μια ενέργεια που εμφανίζει το μήνυμα “Button Clicked!” στην κονσόλα.

Αναλυτικότερα, ο κώδικας κάνει τα εξής βήματα:

  1. Εισάγει τις απαραίτητες κλάσεις java.awt.* και java.awt.event.* για την δημιουργία του γραφικού παραθύρου και την χειρισμό των γεγονότων.
  2. Δημιουργεί ένα νέο παράθυρο με τίτλο “Lambda Expressions Example” χρησιμοποιώντας την κλάση Frame.
  3. Δημιουργεί ένα κουμπί με το κείμενο “Click Me” χρησιμοποιώντας την κλάση Button και το προσθέτει στο παράθυρο.
  4. Προσθέτει έναν ακροατή γεγονότος στο κουμπί με χρήση μιας λάμδα έκφρασης. Όταν το κουμπί πατηθεί, εκτελείται ο κώδικας εντολών εντός της λάμδα έκφρασης, που σε αυτήν την περίπτωση εμφανίζει το μήνυμα “Button Clicked!” στην κονσόλα.
  5. Ορίζει το μέγεθος του παραθύρου σε 300×200 pixels, με τη χρήση της μεθόδου setSize().
  6. Ορίζει τη διάταξη ροής (FlowLayout) για το παράθυρο με τη χρήση της μεθόδου setLayout().
  7. Καθιστά το παράθυρο ορατό με τη χρήση της μεθόδου setVisible(true).

Όλα αυτά τα βήματα οδηγούν στην δημιουργία ενός γραφικού παραθύρου στην οθόνη, με ένα κουμπί που εκτελεί μια ενέργεια όταν πατηθεί.

Παράδειγμα:

import java.util.ArrayList;

public class Main {
   public static void main(String args[]) {
      // Δημιουργία ενός ArrayList με στοιχεία τύπου String
      ArrayList<String> cars = new ArrayList<String>();

      // Προσθήκη στοιχείων στο ArrayList
      cars.add("Volvo");
      cars.add("BMW");
      cars.add("Ford");
      cars.add("Mazda");

      // Εκτέλεση ενέργειας για κάθε στοιχείο της λίστας
      cars.forEach((car) -> {
         System.out.println(car); // Εκτύπωση του στοιχείου
      });
   }
}

Ο παραπάνω κώδικας πραγματοποιεί τις εξής ενέργειες:

  1. Δημιουργείται ένα ArrayList με όνομα “cars” που περιέχει στοιχεία τύπου String.
  2. Προστίθενται τέσσερα στοιχεία στο ArrayList, ανάλογα με το αυτοκίνητο που παρουσιάζει κάθε στοιχείο.
  3. Χρησιμοποιώντας τη μέθοδο forEach() της κλάσης ArrayList, εκτελείται μια ενέργεια για κάθε στοιχείο της λίστας.
  4. Κάθε αυτοκίνητο εκτυπώνεται στην οθόνη με τη χρήση της μεθόδου println() της κλάσης System.out.

Ο κώδικας εκτυπώνει τα αυτοκίνητα που περιέχονται στο ArrayList “cars” με μια γραμμή εκτύπωσης για κάθε αυτοκίνητο.

[adinserter block=”3″]

Οι εκφράσεις Lambda μπορούν επίσης να αποθηκευτούν σε μεταβλητές, όπως φαίνεται στο παρακάτω παράδειγμα:

import java.util.function.*;

public class Main {
   public static void main(String args[]) {
      // Χρήση της εκφρασης Lambda για τη δημιουργία ενός Supplier
      // που επιστρέφει τη συμβολοσειρά "Hello World!"
      Supplier<String> hello = () -> "Hello World!";
      
      // Εκτύπωση της τιμής που επιστρέφεται από το Supplier
      System.out.println(hello.get());
   }
}

Ο παραπάνω κώδικας χρησιμοποιεί τη λειτουργία των λειτουργικών διαστάσεων (functional interfaces) και ειδικότερα μια εκφραση Lambda για να δημιουργήσει έναν Supplier (Προμηθευτής). Ο Supplier είναι ένας λειτουργικός τύπος που δεν δέχεται κανένα όρισμα και επιστρέφει μια τιμή.

Συγκεκριμένα, ο κώδικας δημιουργεί έναν Supplier με χρήση της εκφρασης Lambda. Η εκφραση Lambda () -> "Hello World!" δηλώνει ότι ο Supplier δεν δέχεται κανένα όρισμα και επιστρέφει τη συμβολοσειρά “Hello World!”.

Στη συνέχεια, με τη χρήση της μεθόδου get() στον Supplier (hello.get()), ανακτάται η τιμή που επιστρέφεται από τον Supplier και εκτυπώνεται στην οθόνη. Έτσι, στην παραπάνω περίπτωση, θα εκτυπωθεί η συμβολοσειρά “Hello World!”.

Ο κώδικας δείχνει την απλή χρήση των λειτουργικών διαστάσεων και των εκφράσεων Lambda στην Java για τη δημιουργία και χρήση ενός Supplier.

Οι λαμδα εκφράσεις στη Java μπορούν να αποθηκευτούν σε μεταβλητές, υπό την προϋπόθεση ότι ο τύπος της μεταβλητής είναι μια διεπαφή (interface) που περιέχει μόνο μία μέθοδο. Η λαμδα εκφραση πρέπει να έχει τον ίδιο αριθμό παραμέτρων και τον ίδιο τύπο επιστροφής με αυτή τη μέθοδο που ορίζεται στη διεπαφή. Στην Java, υπάρχουν πολλές ενσωματωμένες διεπαφές που πληρούν αυτές τις προϋποθέσεις, όπως η διεπαφή Consumer που βρίσκεται στο πακέτο java.util. Αυτή η διεπαφή χρησιμοποιείται συχνά για την επεξεργασία λιστών ή συλλογών δεδομένων, καθώς δέχεται ένα αντικείμενο και εκτελεί μια ενέργεια πάνω του.

Ένα παράδειγμα χρήσης της διεπαφής Consumer της Java για την αποθήκευση μιας λαμδα εκφρασης σε μια μεταβλητή:

import java.util.function.Consumer;

public class Main {
    public static void main(String[] args) {
        // Δημιουργία μιας μεταβλητής myLambda τύπου Consumer<String>
        // Η μεταβλητή αυτή χρησιμοποιείται για να αποθηκεύσουμε μια lambda έκφραση
        Consumer<String> myLambda = (String s) -> System.out.println(s);

        // Κλήση της μεθόδου accept() του αντικειμένου myLambda και παράδοση ενός String ως όρισμα
        // Η λειτουργία της λάμβδα έκφρασης είναι να εκτελέσει τον κώδικα μέσα στις αγκύλες
        // Εδώ εκτυπώνει το String που περνάμε ως όρισμα
        myLambda.accept("Hello Lambda Expression!");
    }
}

Ο παραπάνω κώδικας υλοποιεί μια απλή χρήση των λαμβαδικών εκφράσεων (lambda expressions) στην Java.

Αρχικά, γίνεται η εισαγωγή της κλάσης Consumer από το πακέτο java.util.function, η οποία είναι μια λειτουργική διεπαφή (functional interface) που δέχεται ένα όρισμα και δεν επιστρέφει κάποιο αποτέλεσμα.

Στην main μέθοδο της κλάσης Main, δημιουργείται μια μεταβλητή myLambda τύπου Consumer<String>, η οποία αποθηκεύει μια λαμβαδική έκφραση (lambda expression) που εκτελεί την εντολή System.out.println(s), όπου s είναι το όρισμα της λάμβδα έκφρασης.

Στη συνέχεια, γίνεται κλήση της μεθόδου accept() του αντικειμένου myLambda και περνιέται η συμβολοσειρά "Hello Lambda Expression!" ως όρισμα. Η λάμβδα έκφραση εκτελείται και το μήνυμα εκτυπώνεται στην κονσόλα.

Για να χρησιμοποιήσουμε μια λαμβδα εκφραση σε μια μέθοδο, η μέθοδος πρέπει να δέχεται ένα όρισμα τύπου διεπαφής που περιέχει μόνο μία μέθοδο. Αν καλέσουμε την μέθοδο αυτής της διεπαφής, θα εκτελεστεί η λαμβδα εκφραση που έχουμε ορίσει:

Παράδειγμα
Δημιουργία μιας μεθόδου που δέχεται μια λαμδα εκφραση ως παράμετρο:

import java.util.function.Function;

public class Main {
  public static void main(String[] args) {
    int increment = 2;
    
    // Δημιουργία μιας λειτουργίας (Function) που προσθέτει το increment σε έναν αριθμό
    Function<Integer, Integer> incrementBy = (number) -> number + increment;
    
    // Εφαρμογή της λειτουργίας doMath με τον αριθμό 5 και την λειτουργία incrementBy
    int result = doMath(5, incrementBy);
    
    // Εκτύπωση του αποτελέσματος
    System.out.println(result);
  }

  // Ορισμός της μεθόδου doMath που παίρνει έναν αριθμό και μια λειτουργία
  public static int doMath(int number, Function<Integer, Integer> mathFunction) {
    // Εφαρμογή της λειτουργίας στον αριθμό και επιστροφή του αποτελέσματος
    return mathFunction.apply(number);
  }
}

Ο παραπάνω κώδικας κάνει τα εξής:

  1. Ορίζει μια μεταβλητή increment με τιμή 2.
  2. Δημιουργεί μια λειτουργία (Function) με όνομα incrementBy που προσθέτει την τιμή του increment σε έναν αριθμό.
  3. Καλεί τη μέθοδο doMath και της περνάει τον αριθμό 5 και την λειτουργία incrementBy.
  4. Η μέθοδος doMath παίρνει έναν αριθμό και μια λειτουργία ως ορίσματα.
  5. Εφαρμόζει τη λειτουργία πάνω στον αριθμό και επιστρέφει το αποτέλεσμα.
  6. Το αποτέλεσμα από την doMath αποθηκεύεται στη μεταβλητή result.
  7. Εκτυπώνει το result, δηλαδή το αποτέλεσμα της λειτουργίας incrementBy εφαρμοσμένης στον αριθμό 5, που αναμένεται να είναι 7.

Ο κώδικας χρησιμοποιεί τη λειτουργία (function) Function της Java, η οποία μπορεί να περάσει ως όρισμα και να επιστρέψει ένα αποτέλεσμα. Στην προκειμένη περίπτωση, η λειτουργία incrementBy προσθέτει την τιμή του increment σε έναν αριθμό.

16 Ιουνίου, 2023
top
error: Content is protected !!
Μετάβαση σε γραμμή εργαλείων