Προγραμματισμός

Ξεκινήστε με αναφορές μεθόδων στην Java

Μαζί με τα lambdas, το Java SE 8 έφερε αναφορές μεθόδων στη γλώσσα Java. Αυτό το σεμινάριο προσφέρει μια σύντομη επισκόπηση των αναφορών μεθόδων στην Java και, στη συνέχεια, θα ξεκινήσετε να τις χρησιμοποιείτε με παραδείγματα κώδικα Java. Μέχρι το τέλος του σεμιναρίου θα ξέρετε πώς να χρησιμοποιείτε αναφορές μεθόδων για να αναφέρετε τις στατικές μεθόδους μιας τάξης, τις δεσμευμένες και μη δεσμευμένες μη στατικές μεθόδους και τους κατασκευαστές, καθώς και πώς να τις χρησιμοποιήσετε για να αναφέρετε σε μεθόδους παρουσίας σε superclass και στην τρέχουσα τάξη τύποι. Θα καταλάβετε επίσης γιατί πολλοί προγραμματιστές Java υιοθέτησαν εκφράσεις λάμδα και αναφορές μεθόδων ως μια καθαρότερη, απλούστερη εναλλακτική λύση αντί των ανώνυμων τάξεων.

Σημειώστε ότι τα παραδείγματα κώδικα σε αυτό το σεμινάριο είναι συμβατά με το JDK 12.

λήψη Λήψη του κώδικα Λήψη του πηγαίου κώδικα για παράδειγμα εφαρμογές σε αυτό το σεμινάριο. Δημιουργήθηκε από τον Jeff Friesen για το JavaWorld.

Αναφορές μεθόδου: Ένα αστάρι

Το προηγούμενο πρόγραμμα εκμάθησης Java 101 εισήγαγε εκφράσεις λάμδα, οι οποίες χρησιμοποιούνται για τον καθορισμό ανώνυμων μεθόδων που μπορούν στη συνέχεια να αντιμετωπίζονται ως περιπτώσεις λειτουργικής διεπαφής. Μερικές φορές, μια έκφραση λάμδα δεν κάνει τίποτα περισσότερο από την κλήση μιας υπάρχουσας μεθόδου. Για παράδειγμα, το ακόλουθο τμήμα κώδικα χρησιμοποιεί μια λάμδα για επίκληση System.out'μικρό άκυρη εκτύπωση μέθοδος στο μοναδικό επιχείρημα της λάμδα--μικρόΟ τύπος δεν είναι ακόμη γνωστός:

(α) -> System.out.println (s)

Το λάμδα παρουσιάζει (μικρό) ως επίσημη λίστα παραμέτρων και ένα σώμα κώδικα του οποίου System.out.println (s) εκτυπώσεις έκφρασης μικρότιμή για την τυπική ροή εξόδου. Δεν έχει συγκεκριμένο τύπο διεπαφής. Αντ 'αυτού, ο μεταγλωττιστής εισάγει από το περιβάλλον πλαίσιο το λειτουργικό περιβάλλον που θα δημιουργηθεί. Για παράδειγμα, εξετάστε το ακόλουθο τμήμα κώδικα:

Καταναλωτής καταναλωτής = (ες) -> System.out.println (s);

Ο μεταγλωττιστής αναλύει την προηγούμενη δήλωση και καθορίζει ότι το java.util.function.Cumer προκαθορισμένες λειτουργικές διεπαφές άκυρη αποδοχή (T t) Η μέθοδος ταιριάζει με τη λίστα τυπικών παραμέτρων της λάμδα ((μικρό)). Το καθορίζει επίσης αυτό αποδέχομαι()'μικρό κενός αγώνες τύπου επιστροφής εκτύπωση ()'μικρό κενός τύπος επιστροφής. Το λάμδα είναι έτσι όριο προς την Καταναλωτής.

Πιο συγκεκριμένα, το λάμδα δεσμεύεται Καταναλωτής. Ο μεταγλωττιστής δημιουργεί κώδικα έτσι ώστε μια επίκληση του Καταναλωτής'μικρό άκυρη αποδοχή (String s) Η μέθοδος οδηγεί στο όρισμα συμβολοσειράς που μεταβιβάστηκε μικρό μεταβιβάζεται σε System.out'μικρό void println (συμβολοσειρά) μέθοδος. Αυτή η επίκληση εμφανίζεται παρακάτω:

consumer.accept ("Γεια"); // Περάστε το "Hello" στο σώμα του λάμδα. Εκτύπωση Γεια σε τυπική έξοδο.

Για να αποθηκεύσετε πατήματα πλήκτρων, μπορείτε να αντικαταστήσετε το λάμδα με ένα αναφορά μεθόδου, που είναι μια συμπαγής αναφορά σε μια υπάρχουσα μέθοδο. Για παράδειγμα, το ακόλουθο τμήμα κώδικα αντικαθιστά (String s) -> System.out.println (s) με System.out :: println, όπου :: σημαίνει ότι System.out'μικρό void println (συμβολοσειρά) αναφέρεται η μέθοδος:

Καταναλωτής καταναλωτής2 = System.out :: println; // Η αναφορά μεθόδου είναι μικρότερη. umer2.accept ("Γεια"); // Περάστε το "Hello" στο σώμα του λάμδα. Εκτύπωση Γεια σε τυπική έξοδο.

Δεν είναι απαραίτητο να καθορίσετε μια επίσημη λίστα παραμέτρων για την προηγούμενη αναφορά μεθόδου, επειδή ο μεταγλωττιστής μπορεί να συμπεράνει αυτήν τη λίστα με βάση Καταναλωτής Αυτός ο παράμετρος τύπου java.lang.String αντικαθιστά το όρισμα πραγματικού τύπου Τ σε άκυρη αποδοχή (T t), και είναι επίσης ο τύπος της μεμονωμένης παραμέτρου στο σώμα του λάμδα System.out.println () μέθοδος κλήσης.

Η μέθοδος αναφέρεται σε βάθος

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

Μπορείτε να χρησιμοποιήσετε αναφορές μεθόδων για να αναφέρετε τις στατικές μεθόδους μιας τάξης, τις δεσμευμένες και μη δεσμευμένες μη στατικές μεθόδους και τους κατασκευαστές. Μπορείτε επίσης να χρησιμοποιήσετε αναφορές μεθόδων για να αναφερθείτε σε μεθόδους παρουσίας σε τύπους superclass και τρέχοντες κλάσεις. Θα σας παρουσιάσω σε καθεμία από αυτές τις κατηγορίες αναφοράς μεθόδου και θα δείξω πώς χρησιμοποιούνται σε μια μικρή επίδειξη.

Μάθετε περισσότερα σχετικά με τις αναφορές μεθόδων

Αφού διαβάσετε αυτήν την ενότητα, ανατρέξτε στις Αναφορές μεθόδου στην Java 8 (Toby Weston, Φεβρουάριος 2014) για περισσότερες πληροφορίες σχετικά με τις αναφορές μεθόδων σε δεσμευμένα και μη δεσμευμένα μη στατικά περιβάλλοντα μεθόδου.

Αναφορές σε στατικές μεθόδους

ΕΝΑ αναφορά στατικής μεθόδου αναφέρεται σε μια στατική μέθοδο σε μια συγκεκριμένη κατηγορία. Η σύνταξή του είναι όνομα τάξης::staticMethodName, όπου όνομα τάξης προσδιορίζει την τάξη και staticMethodName προσδιορίζει τη στατική μέθοδο. Ένα παράδειγμα είναι Integer :: bitCount. Η λίστα 1 δείχνει μια στατική μέθοδο αναφοράς.

Λίστα 1. MRDemo.java (έκδοση 1)

εισαγωγή java.util.Arrays; εισαγωγή java.util.function.Consumer; δημόσια τάξη MRDemo {public static void main (String [] args) {int [] array = {10, 2, 19, 5, 17}; Καταναλωτής καταναλωτής = συστοιχίες :: ταξινόμηση; consumer.accept (πίνακας); για (int i = 0; i <array.length; i ++) System.out.println (πίνακας [i]); System.out.println (); int [] array2 = {19, 5, 14, 3, 21, 4}; Καταναλωτής καταναλωτής2 = (a) -> Arrays.sort (a); consumer2.accept (πίνακας2); για (int i = 0; i <array2.length; i ++) System.out.println (array2 [i]); }}

Λίστα 1 κύριος() Η μέθοδος ταξινομεί ένα ζευγάρι ακέραιων συστοιχιών μέσω του java.util.Arays της τάξης είδος στατικού κενού (int [] a) μέθοδο, η οποία εμφανίζεται σε στατική μέθοδο αναφοράς και ισοδύναμα περιβάλλοντα έκφρασης λάμδα. Μετά την ταξινόμηση ενός πίνακα, a Για Ο βρόχος εκτυπώνει τα περιεχόμενα του ταξινομημένου πίνακα στη βασική ροή εξόδου.

Προτού μπορέσουμε να χρησιμοποιήσουμε μια μέθοδο αναφοράς ή μια λάμδα, πρέπει να συνδέεται με μια λειτουργική διεπαφή. Χρησιμοποιώ το προκαθορισμένο Καταναλωτής λειτουργική διεπαφή, η οποία πληροί τις απαιτήσεις μεθόδου αναφοράς / λάμδα. Η λειτουργία ταξινόμησης αρχίζει περνώντας τον πίνακα προς ταξινόμηση Καταναλωτής'μικρό αποδέχομαι() μέθοδος.

Μεταγλώττιση καταχώρισης 1 (javac MRDemo.java) και εκτελέστε την εφαρμογή (java MRDemo). Θα παρατηρήσετε την ακόλουθη έξοδο:

2 5 10 17 19 3 4 5 14 19 21

Αναφορές σε δεσμευμένες μη στατικές μεθόδους

ΕΝΑ δεσμευμένη μη στατική αναφορά μεθόδου αναφέρεται σε μια μη στατική μέθοδο που συνδέεται με ένα δέκτης αντικείμενο. Η σύνταξή του είναι αντικείμενοName::instanceMethodName, όπου αντικείμενοName αναγνωρίζει τον δέκτη και instanceMethodName προσδιορίζει τη μέθοδο εμφάνισης. Ένα παράδειγμα είναι s :: περικοπή. Η λίστα 2 δείχνει μια δεσμευμένη μη στατική αναφορά μεθόδου.

Λίστα 2. MRDemo.java (έκδοση 2)

εισαγωγή java.util.function.Supplier; δημόσια τάξη MRDemo {public static void main (String [] args) {String s = "Η γρήγορη καφέ αλεπού πήδηξε πάνω από τον τεμπέλης σκύλο"; εκτύπωση (s :: μήκος); εκτύπωση (() -> s.length ()); εκτύπωση (νέος προμηθευτής () {@Override public Integer get () {return s.length (); // close over s}}); } δημόσια στατική κενή εκτύπωση (προμηθευτής προμηθευτή) {System.out.println (supplier.get ()); }}

Λίστα 2's κύριος() Η μέθοδος εκχωρεί μια συμβολοσειρά σε Σειρά μεταβλητός μικρό και στη συνέχεια επικαλείται το Τυπώνω() μέθοδος κλάσης με λειτουργικότητα για να αποκτήσετε το μήκος αυτής της συμβολοσειράς ως επιχείρημα αυτής της μεθόδου. Τυπώνω() καλείται στην αναφορά μεθόδου (s :: μήκος -- μήκος() είναι βέβαιο ότι θα μικρό), ισοδύναμο λάμδα και ισοδύναμα ανώνυμα περιβάλλοντα κλάσης.

Έχω ορίσει Τυπώνω() για να χρησιμοποιήσετε το java.util.function.Supplier προκαθορισμένη λειτουργική διεπαφή, της οποίας παίρνω() Η μέθοδος επιστρέφει έναν προμηθευτή αποτελεσμάτων. Σε αυτήν την περίπτωση, το Προμηθευτής το παράδειγμα πέρασε στο Τυπώνω() εφαρμόζει το παίρνω() μέθοδος για επιστροφή s. μήκος (); Τυπώνω() εξάγει αυτό το μήκος.

s :: μήκος εισάγει ένα κλείσιμο που κλείνει μικρό. Μπορείτε να το δείτε πιο καθαρά στο παράδειγμα λάμδα. Επειδή το λάμδα δεν έχει επιχειρήματα, η τιμή του μικρό διατίθεται μόνο από το πεδίο εφαρμογής. Επομένως, το σώμα λάμδα είναι ένα κλείσιμο που κλείνει μικρό. Το ανώνυμο παράδειγμα κλάσης το καθιστά ακόμη πιο σαφές.

Μεταγλωττίστε την καταχώριση 2 και εκτελέστε την εφαρμογή. Θα παρατηρήσετε την ακόλουθη έξοδο:

44 44 44

Αναφορές σε μη δεσμευμένες μη στατικές μεθόδους

Ενα μη δεσμευμένη μη στατική αναφορά μεθόδου αναφέρεται σε μια μη στατική μέθοδο που δεν συνδέεται με ένα αντικείμενο δέκτη. Η σύνταξή του είναι όνομα τάξης::instanceMethodName, όπου όνομα τάξης προσδιορίζει την κλάση που δηλώνει τη μέθοδο εμφάνισης και instanceMethodName προσδιορίζει τη μέθοδο εμφάνισης. Ένα παράδειγμα είναι String :: toLowerCase.

String :: toLowerCase είναι μια μη δεσμευμένη μη στατική μέθοδος αναφοράς που προσδιορίζει το μη στατικό String toLowerCase () μέθοδος του Σειρά τάξη. Ωστόσο, επειδή μια μη στατική μέθοδος εξακολουθεί να απαιτεί αντικείμενο δέκτη (σε αυτό το παράδειγμα a Σειρά αντικείμενο, το οποίο χρησιμοποιείται για την επίκληση toLowerCase () μέσω της μεθόδου αναφοράς), το αντικείμενο δέκτη δημιουργείται από την εικονική μηχανή. toLowerCase () θα κληθεί σε αυτό το αντικείμενο. String :: toLowerCase καθορίζει μια μέθοδο που παίρνει ένα Σειρά όρισμα, που είναι το αντικείμενο του δέκτη, και επιστρέφει a Σειρά αποτέλεσμα. Συμβολοσειρά :: toLowerCase () είναι ισοδύναμο με το λάμδα (String s) -> {return s.toLowerCase (); }.

Η λίστα 3 δείχνει αυτήν την απεριόριστη μη στατική μέθοδο αναφοράς.

Λίστα 3. MRDemo.java (έκδοση 3)

εισαγωγή java.util.function.Function; δημόσια τάξη MRDemo {public static void main (String [] args) {print (String :: toLowerCase, "STRING TO LOWERCASE"); εκτύπωση (s -> s.toLowerCase (), "STRING TO LOWERCASE"); print (new Function () {@Override public String apply (String s) // λαμβάνει όρισμα στην παράμετρο s. {// δεν χρειάζεται να κλείσει το s return s.toLowerCase ();}}, "STRING TO LOWERCASE" ); } δημόσια στατική κενή εκτύπωση (Function function, String s) {System.out.println (function.apply (s)); }}

Λίστα 3's κύριος() μέθοδος επικαλείται το Τυπώνω() μέθοδος κλάσης με λειτουργικότητα για τη μετατροπή μιας συμβολοσειράς σε πεζά και τη συμβολοσειρά που θα μετατραπεί ως ορίσματα της μεθόδου. Τυπώνω() καλείται στην αναφορά μεθόδου (String :: toLowerCase, όπου toLowerCase () δεν είναι δεσμευμένο σε αντικείμενο που καθορίζεται από το χρήστη) και ισοδύναμα λάμδα και ανώνυμα περιβάλλοντα κλάσης.

Έχω ορίσει Τυπώνω() για να χρησιμοποιήσετε το java.util.function.Function προκαθορισμένη λειτουργική διεπαφή, η οποία αντιπροσωπεύει μια συνάρτηση που δέχεται ένα όρισμα και παράγει ένα αποτέλεσμα. Σε αυτήν την περίπτωση, το Λειτουργία το παράδειγμα πέρασε στο Τυπώνω() εφαρμόζει το R ισχύουν (T t) μέθοδος για επιστροφή s.toLowerCase (); Τυπώνω() εξάγει αυτήν τη συμβολοσειρά.

παρόλο που το Σειρά μέρος του String :: toLowerCase το κάνει να μοιάζει με μια τάξη που αναφέρεται, αναφέρεται μόνο μια παρουσία αυτής της τάξης. Το ανώνυμο παράδειγμα κλάσης το καθιστά πιο προφανές. Σημειώστε ότι στο ανώνυμο παράδειγμα κλάσης το lambda λαμβάνει ένα επιχείρημα. δεν κλείνει παράμετρο μικρό (δηλαδή, δεν είναι κλείσιμο).

Μεταγλωττίστε την καταχώριση 3 και εκτελέστε την εφαρμογή. Θα παρατηρήσετε την ακόλουθη έξοδο:

συμβολοσειρά σε πεζά συμβολοσειρά σε πεζά συμβολοσειρά σε πεζά

Αναφορές σε κατασκευαστές

Μπορείτε να χρησιμοποιήσετε μια αναφορά μεθόδου για να αναφέρετε έναν κατασκευαστή χωρίς να υποδείξετε την ονομαζόμενη κλάση. Αυτό το είδος αναφοράς μεθόδου είναι γνωστό ως αναφορά κατασκευαστή. Η σύνταξή του είναι όνομα τάξης::νέος. όνομα τάξης πρέπει να υποστηρίζει τη δημιουργία αντικειμένων. δεν μπορεί να ονομάσει μια αφηρημένη κλάση ή διεπαφή. Λέξη-κλειδί νέος ονομάζει τον κατασκευαστή που αναφέρεται. Ορίστε μερικά παραδείγματα:

  • Χαρακτήρας :: νέο: ισοδύναμο με το λάμδα (Χαρακτήρας ch) -> νέος χαρακτήρας (ch)
  • Long :: νέο: ισοδύναμο με το λάμδα (μεγάλη τιμή) -> νέο Long (τιμή) ή (String s) -> νέα Long (s)
  • ArrayList :: νέο: ισοδύναμο με το λάμδα () -> νέο ArrayList ()
  • float [] :: νέο: ισοδύναμο με το λάμδα (int μέγεθος) -> νέο float [μέγεθος]

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

Για να δημιουργήσετε μια αναφορά κατασκευαστή, καθορίστε νέος χωρίς κατασκευαστή. Όταν μια τάξη όπως java.lang.Long δηλώνει πολλούς κατασκευαστές, ο μεταγλωττιστής συγκρίνει τον τύπο της λειτουργικής διεπαφής με όλους τους κατασκευαστές και επιλέγει τον καλύτερο αγώνα. Η λίστα 4 δείχνει μια αναφορά κατασκευαστή.

Λίστα 4. MRDemo.java (έκδοση 4)

εισαγωγή java.util.function.Supplier; δημόσια τάξη MRDemo {public static void main (String [] args) {Προμηθευτής προμηθευτή = MRDemo :: new; System.out.println (προμηθευτής.get ()); }}

Λίστα 4's MRDemo :: νέο η αναφορά του κατασκευαστή είναι ισοδύναμη με το λάμδα () -> νέο MRDemo (). Εκφραση προμηθευτής.get () εκτελεί αυτό το λάμδα, το οποίο επικαλείται MRDemoο προεπιλεγμένος κατασκευαστής χωρίς ορίσματα και επιστρέφει το MRDemo αντικείμενο, στο οποίο μεταβιβάζεται System.out.println (). Αυτή η μέθοδος μετατρέπει το αντικείμενο σε μια συμβολοσειρά, την οποία εκτυπώνει.

Ας υποθέσουμε ότι έχετε μια τάξη με έναν κατασκευαστή χωρίς ορίσματα και έναν κατασκευαστή που παίρνει ένα όρισμα και θέλετε να καλέσετε τον κατασκευαστή που παίρνει ένα όρισμα Μπορείτε να ολοκληρώσετε αυτήν την εργασία επιλέγοντας μια διαφορετική λειτουργική διεπαφή, όπως η προκαθορισμένη Λειτουργία διεπαφή που εμφανίζεται στην καταχώριση 5.

Λίστα 5. MRDemo.java (έκδοση 5)

εισαγωγή java.util.function.Function; δημόσια κλάση MRDemo {ιδιωτικό όνομα συμβολοσειράς; MRDemo () {name = ""; } MRDemo (όνομα συμβολοσειράς) {this.name = name; System.out.printf ("MRDemo (όνομα συμβολοσειράς) που ονομάζεται με% s% n", όνομα); } δημόσιος στατικός κενός κενός (String [] args) {Function function = MRDemo :: new; System.out.println (function.apply ("κάποιο όνομα")); }}

Λειτουργία συνάρτησης = MRDemo :: new; προκαλεί τον μεταγλωττιστή να αναζητήσει έναν κατασκευαστή που παίρνει ένα Σειρά επιχείρημα, επειδή Λειτουργία'μικρό ισχύουν() μέθοδος απαιτεί ένα (σε αυτό το πλαίσιο) Σειρά διαφωνία. Εκτελεί function.apply ("κάποιο όνομα") αποτελέσματα σε "κάποιο όνομα" μεταβιβάζεται σε MRDemo (Όνομα συμβολοσειράς).