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

JDK 7: Ο Διαχειριστής Διαμαντιών

Το Project Coin παρέχει πολλές "βελτιώσεις μικρών γλωσσών" ως υποσύνολο των νέων δυνατοτήτων JDK 7. Πρόσφατα έγραψα blog σχετικά με την ενεργοποίηση του Strings του Project Coin και σε αυτήν την ανάρτηση γράφω για το νέο Diamond Operator ().

Ο Διαχειριστής Διαμαντιών μειώνει μερικά από την ευγένεια της Java γύρω από τα γενικά, έχοντας τον τύπο του παραγόμενου να συνάγει τύπους παραμέτρων για κατασκευαστές γενικών κλάσεων. Η αρχική πρόταση για την προσθήκη του Διαχειριστή Diamond στη γλώσσα Java έγινε τον Φεβρουάριο του 2009 και περιλαμβάνει αυτό το απλό παράδειγμα:

Για παράδειγμα, εξετάστε την ακόλουθη δήλωση ανάθεσης:

Χάρτης anagrams = νέο HashMap();

Αυτό είναι αρκετά μακρύ, οπότε μπορεί να αντικατασταθεί με αυτό:

Χάρτης anagrams = νέο HashMap ();

Το παραπάνω παράδειγμα που παρέχεται στην πρόταση του Jeremy Manson (που ήταν ένα από τα πρώτα σε απάντηση σε μια πρόσκληση για ιδέες για Project Coin) είναι απλό, αλλά καταδεικνύει επαρκώς τον τρόπο με τον οποίο ο Διαχειριστής διαμαντιών εφαρμόζεται στο JDK 7. Η πρόταση του Manson παρέχει επίσης σημαντικό λόγο για τον οποίο αυτή η προσθήκη ήταν επιθυμητό:

Η απαίτηση ότι οι παράμετροι τύπου πρέπει να αντιγράφονται άσκοπα

Αυτό ενθαρρύνει ένα ατυχές

υπεραφθονία των στατικών μεθόδων εργοστασίου, απλώς και μόνο λόγω συμπερασμάτων τύπου

λειτουργεί με επίκληση μεθόδου.

Με άλλα λόγια, η προσθήκη JDK 7 Project Coin ενός Διαχειριστή Διαμαντιών φέρνει συμπεράσματα τύπου σε κατασκευαστές που ήταν διαθέσιμοι με μεθόδους. Με μεθόδους, το συμπέρασμα τύπου πραγματοποιείται σιωπηρά όταν κάποιος αφήνει την προδιαγραφή τύπου ρητής παραμέτρου. Με την απόδειξη, από την άλλη πλευρά, ο τελεστής διαμαντιών πρέπει να καθορίζεται ρητά για να "πει" στον μεταγλωττιστή να συμπεράνει τον τύπο.

Στην αρχική του πρόταση, ο Manson επισημαίνει ότι η σύνταξη χωρίς έναν ειδικό τελεστή διαμαντιών δεν θα μπορούσε να χρησιμοποιηθεί για να υπονοήσει σιωπηρά τύπους για στιγμιότυπα, επειδή "για σκοπούς συμβατότητας προς τα πίσω, ο νέος χάρτης () δείχνει έναν ακατέργαστο τύπο και επομένως δεν μπορεί να χρησιμοποιηθεί για τον τύπο συμπέρασμα." Η σελίδα Type Inference του Generics Μάθημα της εκμάθησης της γλώσσας Java του Java Tutorials περιλαμβάνει μια ενότητα που ονομάζεται "Type Inference and Instantiation of Generic Classes" που έχει ήδη ενημερωθεί για να αντικατοπτρίζει το Java SE 7. Αυτή η ενότητα περιγράφει επίσης γιατί το ειδικό Ο χειριστής πρέπει να έχει καθοριστεί για να ενημερώνει ρητά τον μεταγλωττιστή για να χρησιμοποιήσει συμπεράσματα τύπου σε περίπτωση:

Λάβετε υπόψη ότι για να επωφεληθείτε από την αυτόματη συμπερίληψη τύπου κατά τη γενική παρουσίαση κατηγορίας, πρέπει να καθορίσετε τον τελεστή διαμαντιών. Στο ακόλουθο παράδειγμα, ο μεταγλωττιστής δημιουργεί μια μη ελεγμένη προειδοποίηση μετατροπής επειδή ο κατασκευαστής HashMap () αναφέρεται στον ακατέργαστο τύπο HashMap, όχι στον χάρτη τύπος

Στο σημείο 24 ("Εξάλειψη των μη ελεγμένων προειδοποιήσεων") της δεύτερης έκδοσης της αποτελεσματικής Java, ο Josh Bloch τονίζει τολμηρός κείμενο, "Εξαλείψτε κάθε μη ελεγμένη προειδοποίηση που μπορείτε." Το Bloch δείχνει ένα παράδειγμα της μη ελεγχόμενης προειδοποίησης μετατροπής που εμφανίζεται όταν συντάσσει έναν κώδικα που χρησιμοποιεί έναν ακατέργαστο τύπο στη δεξιά πλευρά μιας δήλωσης. Η επόμενη λίστα κωδικών δείχνει κώδικα που θα οδηγήσει σε αυτήν την προειδοποίηση.

τελικός χάρτης StatesToCities = νέο HashMap (); // ωμά! 

Τα επόμενα δύο στιγμιότυπα οθόνης δείχνουν την απόκριση του μεταγλωττιστή στην παραπάνω γραμμή κώδικα. Στην πρώτη εικόνα εμφανίζεται το μήνυμα όταν δεν είναι ενεργοποιημένες οι προειδοποιήσεις -Xlint και η δεύτερη δείχνει την πιο ρητή προειδοποίηση που εμφανίζεται όταν -Xlint: μη επιλεγμένο παρέχεται ως επιχείρημα στο javac.

Αν Αποτελεσματική Java, Ο Bloch επισημαίνει ότι αυτή η συγκεκριμένη ανεξέλεγκτη προειδοποίηση είναι εύκολο να αντιμετωπιστεί παρέχοντας ρητά τον τύπο παραμέτρου στην παρουσίαση της γενικής κλάσης. Με το JDK 7, αυτό θα είναι ακόμα πιο εύκολο! Αντί να χρειάζεται να προσθέσετε το ρητό κείμενο με αυτά τα ονόματα τύπων, οι τύποι μπορούν να συναχθούν σε πολλές περιπτώσεις και η προδιαγραφή του τελεστή διαμαντιών λέει στον μεταγλωττιστή να κάνει αυτό το συμπέρασμα αντί να χρησιμοποιεί τον αρχικό τύπο.

Η επόμενη λίστα κώδικα Java παρέχει απλοϊκά παραδείγματα αυτών των εννοιών. Υπάρχουν μέθοδοι που αποδεικνύουν την εμφάνιση ενός πρωτογενούς συνόλου, την παρουσίαση ενός συνόλου με ρητή προδιαγραφή του τύπου παραμέτρου του και την παρουσίαση ενός συνόλου με τύπο παραμέτρου που συνάγεται λόγω της προδιαγραφής του τελεστή διαμαντιών ().

πακέτο dustin.example; εισαγωγή java.util.HashMap; εισαγωγή java.util.HashSet; εισαγωγή java.util.Map; εισαγωγή java.util.Set; εισαγωγή στατικού java.lang.System.out; / ** * Πολύ απλή επίδειξη του "Diamond Operator" του JDK 7 / Project Coin. * / δημόσια κατηγορία DiamondOperatorDemo {/ ** Χρήση τύπου "raw". * / ιδιωτικό στατικό σύνολο rawWithoutExplicitTyping () {final Set names = new HashSet (); addNames (ονόματα); ονόματα επιστροφής; } / ** Προσδιορίστε ρητά τον τύπο παραμέτρου instantiation της γενικής κλάσης. * / ιδιωτικό στατικό σύνολο expressTypingExplicitlySpecified () {final Set names = new HashSet (); addNames (ονόματα); ονόματα επιστροφής; } / ** * Συμπεράσματα τύπου παραμέτρου γενικής κατηγορίας με JDK 7 * "Diamond Operator". * / ιδιωτικό στατικό σύνολο expressTypingInferredWithDiamond () {final Set names = new HashSet (); addNames (ονόματα); ονόματα επιστροφής; } ιδιωτικό static void addNames (final Set namesToAddTo) {namesToAddTo.add ("Dustin"); namesToAddTo.add ("Rett"); namesToAddTo.add ("Όμηρος"); } / ** * Κύρια εκτελέσιμη λειτουργία. * / public static void main (final επιχειρήματα String []) {out.println (rawWithoutExplicitTyping ()); out.println (expressTypingExplicitlySpecified ()); out.println (expressTypingInferredWithDiamond ()); }} 

Όταν καταρτίζεται ο παραπάνω κωδικός, μόνο η "πρώτη" περίπτωση οδηγεί σε προειδοποίηση.

Σε αυτό το σημείο, μπορεί να είναι διορατικό να δούμε τι μας λέει ο javap για αυτές τις τρεις μεθόδους. Αυτό γίνεται σε αυτήν την περίπτωση με την εντολή ( η επιλογή για ρήξη δίνει όλες τις ζουμερές λεπτομέρειες και εμφανίζει αυτές τις ζουμερές λεπτομέρειες για το ιδιωτικός μέθοδοι):

javap -v -p -classpath κατηγορίες dustin.examples.DiamondOperatorDemo 

Επειδή αυτές οι μέθοδοι ήταν όλες σε μία τάξη, υπάρχει ένα μόνο ρεύμα εξόδου για ολόκληρη την τάξη. Ωστόσο, για να διευκολύνω τη σύγκριση τους, έχω κόψει και επικολλήσει την έξοδο σε μορφή που ευθυγραμμίζει την έξοδο javap για κάθε μέθοδο μεταξύ τους. Κάθε στήλη αντιπροσωπεύει το javap έξοδος για μία από τις μεθόδους. Έχω αλλάξει το χρώμα γραμματοσειράς της συγκεκριμένης μεθόδου σε μπλε για να το ξεχωρίσω και να επισημάνω την έξοδο αυτής της στήλης.

Εκτός από τα ονόματα των ίδιων των μεθόδων, δεν υπάρχει διαφορά στο javap παραγωγή. Αυτό συμβαίνει επειδή η διαγραφή τύπου Java generics σημαίνει ότι η διαφοροποίηση βάσει του τύπου δεν είναι διαθέσιμη κατά το χρόνο εκτέλεσης. Το Java Tutorial on Generics περιλαμβάνει μια σελίδα που ονομάζεται Type Erasure που εξηγεί αυτό:

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

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

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

συμπέρασμα

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

Η αρχική ανάρτηση διατίθεται στη διεύθυνση //marxsoftware.blogspot.com/

Αυτή η ιστορία, "JDK 7: The Diamond Operator" δημοσιεύθηκε αρχικά από την JavaWorld.