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

Java toString () Σκέψεις

Ακόμη και αρχικά οι προγραμματιστές Java γνωρίζουν τη χρησιμότητα της μεθόδου Object.toString () που είναι διαθέσιμη σε όλες τις εμφανίσεις τάξεων Java και μπορεί να παρακαμφθεί για να παρέχει χρήσιμες λεπτομέρειες σχετικά με οποιαδήποτε συγκεκριμένη παρουσία μιας κλάσης Java. Δυστυχώς, ακόμη και οι έμπειροι προγραμματιστές Java περιστασιακά δεν εκμεταλλεύονται πλήρως αυτήν την ισχυρή δυνατότητα Java για διάφορους λόγους. Σε αυτήν την ανάρτηση ιστολογίου, κοιτάζω την ταπεινή Java toString () και να περιγράψουμε εύκολα βήματα που μπορεί κανείς να κάνει για να βελτιώσει τον χρηματισμό toString ().

Εφαρμόστε ρητά (Παράκαμψη) στο String ()

Ίσως το πιο σημαντικό ζήτημα που σχετίζεται με την επίτευξη μέγιστης αξίας από toString () είναι να παρέχει υλοποιήσεις αυτών. Αν και η ρίζα όλων των ιεραρχιών κλάσης Java, Object, παρέχει μια εφαρμογή toString () που είναι διαθέσιμη σε όλες τις κλάσεις Java, η προεπιλεγμένη συμπεριφορά αυτής της μεθόδου είναι σχεδόν ποτέ χρήσιμη. Το Javadoc για Object.toString () εξηγεί τι παρέχεται από προεπιλογή για toString () όταν δεν παρέχεται προσαρμοσμένη έκδοση για μια κλάση:

Η μέθοδος toString για την κλάση Αντικειμένου επιστρέφει μια συμβολοσειρά που αποτελείται από το όνομα της κλάσης της οποίας το αντικείμενο είναι μια παρουσία, ο χαρακτήρας στο σύμβολο "@" και η μη υπογεγραμμένη δεκαεξαδική αναπαράσταση του κωδικού κατακερματισμού του αντικειμένου. Με άλλα λόγια, αυτή η μέθοδος επιστρέφει μια συμβολοσειρά ίση με την τιμή:getClass (). getName () + '@' + Integer.toHexString (hashCode ())

Είναι δύσκολο να βρούμε μια κατάσταση στην οποία είναι χρήσιμο το όνομα της τάξης και η δεκαεξαδική αναπαράσταση του κωδικού κατακερματισμού του αντικειμένου που διαχωρίζεται από το σύμβολο @. Σε όλες σχεδόν τις περιπτώσεις, είναι πολύ πιο χρήσιμο να παρέχετε μια προσαρμοσμένη, ρητή

toString ()

υλοποίηση σε μια τάξη για παράκαμψη αυτής της προεπιλεγμένης έκδοσης.

Το Javadoc για Object.toString () μας λέει επίσης τι toString () η εφαρμογή γενικά πρέπει να συνεπάγεται και κάνει επίσης την ίδια σύσταση που κάνω εδώ: παράκαμψη toString ():

Σε γενικές γραμμές, τοtoString Η μέθοδος επιστρέφει μια συμβολοσειρά που "αντιπροσωπεύει κείμενο" αυτό το αντικείμενο. Το αποτέλεσμα θα πρέπει να είναι μια συνοπτική αλλά ενημερωτική αναπαράσταση που είναι εύκολο να διαβάσει κάποιος. Συνιστάται όλες οι υποκατηγορίες να παρακάμψουν αυτήν τη μέθοδο.

Κάθε φορά που γράφω μια νέα τάξη, υπάρχουν αρκετές μέθοδοι που θεωρώ να προσθέσω ως μέρος της πράξης της δημιουργίας νέας τάξης. Αυτά περιλαμβάνουν

hashCode ()

και

ισούται με (αντικείμενο)

εάν ενδείκνυται. Ωστόσο, από την εμπειρία μου και κατά τη γνώμη μου, η εφαρμογή ρητή

toString ()

είναι πάντα κατάλληλο.

Εάν η "πρόταση" του Javadoc ότι "όλες οι υποκατηγορίες παρακάμπτουν αυτήν τη μέθοδο" δεν είναι αρκετή (τότε δεν υποθέτω ότι η πρότασή μου είναι είτε) για να δικαιολογήσει σε έναν προγραμματιστή Java τη σημασία και την αξία ενός ρητού toString () μέθοδος, τότε προτείνω να αναθεωρήσετε το αποτελεσματικό στοιχείο Java του Josh Bloch "Πάντα παράκαμψη στο String" για επιπλέον υπόβαθρο σχετικά με τη σημασία της εφαρμογής toString (). Κατά τη γνώμη μου, όλοι οι προγραμματιστές Java πρέπει να διαθέτουν ένα αντίγραφο του Αποτελεσματική Java, αλλά ευτυχώς το κεφάλαιο με αυτό το αντικείμενο toString () είναι διαθέσιμο για όσους δεν διαθέτουν αντίγραφο: Μέθοδοι κοινές για όλα τα αντικείμενα.

Διατήρηση / ενημέρωση στο String ()

Είναι απογοητευτικό να καλείτε ρητά ή σιωπηρά ένα αντικείμενο toString () σε μια δήλωση καταγραφής ή άλλο διαγνωστικό εργαλείο και να έχει το προεπιλεγμένο όνομα κλάσης και τον δεκαεξαδικό κωδικό κατακερματισμού του αντικειμένου αντί κάτι πιο χρήσιμο και ευανάγνωστο. Είναι σχεδόν εξίσου απογοητευτικό να έχουμε ένα ατελές toString () υλοποίηση που δεν περιλαμβάνει σημαντικά κομμάτια των τρεχόντων χαρακτηριστικών και της κατάστασης του αντικειμένου. Προσπαθώ να είμαι αρκετά πειθαρχημένος και να δημιουργώ και να ακολουθώ τη συνήθεια να εξετάζω πάντα το toString () εφαρμογή μαζί με την αναθεώρηση του ισούται με (αντικείμενο) και hashCode () υλοποιήσεις οποιασδήποτε κλάσης στην οποία εργάζομαι είναι νέα για μένα ή όποτε προσθέτω ή αλλάζω τα χαρακτηριστικά μιας τάξης.

Απλά τα γεγονότα (αλλά όλα / τα περισσότερα!)

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

Γνωρίστε το κοινό σας

Ένα από τα πιο συνηθισμένα λάθη που έχω δει για αρχάριους προγραμματιστές Java να κάνουν toString () ξεχνά τι και ποιος toString () προορίζεται συνήθως για. Γενικά, toString () είναι ένα εργαλείο διάγνωσης και εντοπισμού σφαλμάτων που διευκολύνει την καταγραφή λεπτομερειών σε μια συγκεκριμένη παρουσία σε μια συγκεκριμένη στιγμή για μεταγενέστερο εντοπισμό σφαλμάτων και διαγνωστικά. Συνήθως είναι λάθος να εμφανίζονται οι διεπαφές χρήστη από παραστάσεις συμβολοσειρών που δημιουργούνται από toString () ή να λαμβάνετε λογικές αποφάσεις με βάση ένα toString () εκπροσώπηση (στην πραγματικότητα, η λήψη λογικών αποφάσεων για οποιαδήποτε συμβολοσειρά είναι εύθραυστη!). Έχω δει καλοί προγραμματιστές να έχουν toString () επιστρέψτε τη μορφή XML για χρήση σε κάποια άλλη φιλική προς το XML πτυχή του κώδικα. Ένα άλλο σημαντικό λάθος είναι να αναγκάσει τους πελάτες να αναλύσουν το String που επέστρεψε toString () προκειμένου να έχουν πρόσβαση στα μέλη δεδομένων μέσω προγραμματισμού. Είναι πιθανώς καλύτερο να παρέχετε μια δημόσια μέθοδο λήψης / πρόσβασης από το να βασίζεστε στο toString () ποτέ δεν αλλάζει. Όλα αυτά είναι λάθη, επειδή αυτές οι προσεγγίσεις ξεχνούν την πρόθεση ενός toString () εκτέλεση. Αυτό είναι ιδιαίτερα ύπουλο εάν ο προγραμματιστής αφαιρέσει σημαντικά χαρακτηριστικά από το toString () μέθοδος (βλ. τελευταίο στοιχείο) για να φαίνεται καλύτερα σε μια διεπαφή χρήστη.

μου αρέσει toString () υλοποιήσεις για να έχουν όλες τις σχετικές λεπτομέρειες και να παρέχουν ελάχιστη μορφοποίηση για να κάνουν αυτές τις λεπτομέρειες πιο εύγευστες. Αυτή η μορφοποίηση μπορεί να περιλαμβάνει νέους χαρακτήρες γραμμής που έχουν επιλεγεί με σύνεση [System.getProperty ("line.seperator");] και καρτέλες, άνω και κάτω τελεία, ερωτηματικά κ.λπ. Δεν επενδύω τον ίδιο χρόνο με αυτό που θα έδινα σε έναν τελικό χρήστη του λογισμικού, αλλά προσπαθώ να κάνω τη μορφοποίηση αρκετά καλή ώστε να είναι περισσότερο αναγνώσιμος. Προσπαθώ να εφαρμόσω toString () μεθόδους που δεν είναι υπερβολικά περίπλοκες ή δαπανηρές για συντήρηση, αλλά που παρέχουν κάποια πολύ απλή μορφοποίηση. Προσπαθώ να αντιμετωπίσω τους μελλοντικούς συντηρητές του κωδικού μου όπως θα ήθελα να αντιμετωπίζονται από προγραμματιστές των οποίων ο κώδικας θα διατηρήσω κάποια μέρα.

Στο στοιχείο του στις toString () εφαρμογή, ο Bloch δηλώνει ότι ένας προγραμματιστής θα πρέπει να επιλέξει εάν θα έχει ή όχι toString () επιστρέψτε μια συγκεκριμένη μορφή. Εάν προορίζεται μια συγκεκριμένη μορφή, αυτό πρέπει να τεκμηριωθεί στα σχόλια του Javadoc και ο Bloch συνιστά επιπλέον να παρέχεται ένας στατικός αρχικοποιητής που μπορεί να επιστρέψει το αντικείμενο στα χαρακτηριστικά εμφάνισης του με βάση μια συμβολοσειρά που δημιουργείται από το toString (). Συμφωνώ με όλα αυτά, αλλά πιστεύω ότι αυτό είναι περισσότερο πρόβλημα από ό, τι οι περισσότεροι προγραμματιστές είναι πρόθυμοι να πάνε. Ο Bloch επισημαίνει επίσης ότι οποιεσδήποτε αλλαγές σε αυτήν τη μορφή σε μελλοντικές κυκλοφορίες θα προκαλέσουν πόνο και αγωνία για τους ανθρώπους ανάλογα με αυτό (γι 'αυτό δεν πιστεύω ότι είναι καλή ιδέα να εξαρτάται η λογική από μια toString () παραγωγή). Με σημαντική πειθαρχία να γράφει και να διατηρεί κατάλληλη τεκμηρίωση, με προκαθορισμένη μορφή για ένα toString () μπορεί να είναι εύλογο. Ωστόσο, μου φαίνεται σαν πρόβλημα και καλύτερα να δημιουργήσω μια νέα και ξεχωριστή μέθοδο για τέτοιες χρήσεις και να αφήσω το toString () χωρίς επιβάρυνση.

Χωρίς ανεπιθύμητες ενέργειες

Εξίσου σημαντικό με το toString () Η εφαρμογή είναι, είναι γενικά απαράδεκτο (και σίγουρα θεωρείται κακή μορφή) να έχουμε τη ρητή ή σιωπηρή κλήση toString () επηρεάζουν τη λογική ή οδηγούν σε εξαιρέσεις ή προβλήματα λογικής. Ο συγγραφέας ενός toString () Η μέθοδος θα πρέπει να είναι προσεκτική για να διασφαλιστεί ότι οι αναφορές ελέγχονται για μηδενική πριν από την πρόσβαση σε αυτές για να αποφευχθεί μια NullPointerException. Πολλές από τις τακτικές που περιέγραψα στο Post Effective Java NullPointerException Handling μπορούν να χρησιμοποιηθούν toString () εκτέλεση. Για παράδειγμα, το String.valueOf (Object) παρέχει έναν εύκολο μηχανισμό μηδενικής ασφάλειας σε χαρακτηριστικά αμφισβητήσιμης προέλευσης.

Είναι εξίσου σημαντικό για το toString () προγραμματιστής για να ελέγξει τα μεγέθη πίνακα και άλλα μεγέθη συλλογής πριν προσπαθήσει να αποκτήσει πρόσβαση σε στοιχεία εκτός αυτής της συλλογής. Συγκεκριμένα, είναι πολύ εύκολο να συναντήσετε ένα StringIndexOutOfBoundsException όταν προσπαθείτε να χειριστείτε τις τιμές String με το String.substring.

Επειδή ένα αντικείμενο είναι toString () Η εφαρμογή μπορεί εύκολα να γίνει χωρίς να το συνειδητοποιήσει ο προγραμματιστής, αυτή η συμβουλή για να βεβαιωθείτε ότι δεν ρίχνει εξαιρέσεις ή δεν εκτελεί λογική (ειδικά λογική που αλλάζει κατάσταση) είναι ιδιαίτερα σημαντική. Το τελευταίο πράγμα που θέλει κάποιος είναι να καταστήσει την πράξη καταγραφής της τρέχουσας κατάστασης μιας παρουσίας σε εξαίρεση ή αλλαγή κατάστασης και συμπεριφοράς. ΕΝΑ toString () Η υλοποίηση πρέπει ουσιαστικά να είναι μια λειτουργία μόνο για ανάγνωση στην οποία η κατάσταση αντικειμένου διαβάζεται για να δημιουργήσει μια συμβολοσειρά για επιστροφή. Εάν κάποια χαρακτηριστικά αλλάξουν στη διαδικασία, τα κακά πράγματα είναι πιθανό να συμβούν σε απρόβλεπτες ώρες.

Είναι η θέση μου ότι α toString () Η υλοποίηση θα πρέπει να περιλαμβάνει μόνο κατάσταση στην παραγόμενη συμβολοσειρά που είναι προσβάσιμη στον ίδιο χώρο διεργασίας τη στιγμή της δημιουργίας της. Για μένα, δεν είναι υπερασπίσιμο να έχεις toString () υλοποίηση πρόσβαση σε απομακρυσμένες υπηρεσίες για τη δημιουργία ενός String μιας παρουσίας. Ίσως λίγο λιγότερο προφανές είναι ότι μια παρουσία δεν πρέπει να συμπληρώνει χαρακτηριστικά δεδομένων επειδή toString () κλήθηκε. ο toString () Η εφαρμογή θα πρέπει να αναφέρεται μόνο για το πώς βρίσκονται τα πράγματα στην τρέχουσα περίπτωση και όχι για το πώς θα μπορούσαν να είναι ή θα είναι στο μέλλον, εάν προκύψουν ορισμένα διαφορετικά σενάρια ή εάν φορτώνονται τα πράγματα. Για να είναι αποτελεσματικό στον εντοπισμό σφαλμάτων και στα διαγνωστικά, το toString () πρέπει να δείξει πώς είναι οι συνθήκες και όχι πώς θα μπορούσαν να είναι.

Η απλή μορφοποίηση εκτιμάται ειλικρινά

Όπως περιγράφηκε παραπάνω, η συνετή χρήση διαχωριστικών γραμμών και καρτελών μπορεί να είναι χρήσιμη στο να κάνουν πιο μακροχρόνιες και περίπλοκες περιπτώσεις πιο εύγευστες όταν δημιουργούνται σε μορφή String. Υπάρχουν και άλλα «κόλπα» που μπορούν να κάνουν τα πράγματα πιο ωραία. Όχι μόνο String.valueOf (Αντικείμενο) παρέχετε μερικά μηδενικό προστασία, αλλά επίσης παρουσιάζει μηδενικό ως το String "null" (το οποίο είναι συχνά η προτιμώμενη αναπαράσταση του null σε μια συμβολοσειρά που δημιουργείται από το toString (). Arrays.toString (Object) είναι χρήσιμο για την εύκολη αναπαράσταση των συστοιχιών ως Strings (ανατρέξτε στην ανάρτησή μου Stringifying Java Arrays για περισσότερες λεπτομέρειες).

Συμπερίληψη ονόματος κλάσης στην παράσταση toString

Όπως περιγράφεται παραπάνω, η προεπιλεγμένη εφαρμογή του toString () παρέχει το όνομα της τάξης ως μέρος της αναπαράστασης της παρουσίας. Όταν το παρακάμπτουμε ρητά, πιθανώς χάνουμε αυτό το όνομα τάξης. Αυτό δεν είναι μεγάλη υπόθεση, συνήθως εάν καταγράφετε μια συμβολοσειρά μιας παρουσίας, επειδή το πλαίσιο καταγραφής θα περιλαμβάνει το όνομα της κλάσης. Ωστόσο, προτιμώ να είμαι στην ασφαλή πλευρά και να έχω πάντα το όνομα της τάξης διαθέσιμο. Δεν με ενδιαφέρει να διατηρήσω την δεκαεξαδική αναπαράσταση κωδικού κατακερματισμού από την προεπιλογή toString (), αλλά το όνομα της τάξης μπορεί να είναι χρήσιμο. Ένα καλό παράδειγμα αυτού είναι το Throwable.toString (). Προτιμώ να χρησιμοποιήσω αυτήν τη μέθοδο αντί για getMessage ή getLocalizedMessage επειδή το πρώτο (toString ()) περιλαμβάνει το Ρίξιμοτο όνομα της τάξης, ενώ οι δύο τελευταίες μέθοδοι δεν το κάνουν.

toString () Εναλλακτικές λύσεις

Αυτήν τη στιγμή δεν το έχουμε αυτό (τουλάχιστον όχι μια τυπική προσέγγιση), αλλά έχει γίνει λόγος για μια κλάση Αντικειμένων στην Java που θα προχωρούσε πολύ προς την ασφαλή και χρήσιμη προετοιμασία των συμβολών String διαφόρων αντικειμένων, δομών δεδομένων και συλλογών. Δεν έχω ακούσει καμία πρόσφατη πρόοδο στο JDK7 σε αυτό το μάθημα. Μια τυπική κλάση στο JDK που παρείχε συμβολοσειρά αναπαράσταση αντικειμένων ακόμη και όταν οι ορισμοί της κλάσης των αντικειμένων δεν παρείχαν ρητή toString () θα ήταν χρήσιμο.

Το Apache Commons ToStringBuilder μπορεί να είναι η πιο δημοφιλής λύση για τη δημιουργία ασφαλών εφαρμογών toString () με ορισμένα βασικά στοιχεία ελέγχου μορφοποίησης. Έχω κάνει blog στο ToStringBuilder στο παρελθόν και υπάρχουν πολλοί άλλοι διαδικτυακοί πόροι σχετικά με τη χρήση του ToStringBuilder.

Η τεχνική συμβουλή τεχνολογίας Java της Glen McCluskey "Γράφοντας μεθόδους toString" παρέχει πρόσθετες λεπτομέρειες σχετικά με τον τρόπο σύνταξης μιας καλής μεθόδου toString (). Σε ένα από τα σχόλια του αναγνώστη, ο Giovanni Pelosi δηλώνει την προτίμησή του να αναθέτει την παραγωγή μιας συμβολοσειράς αναπαράστασης μιας παρουσίας εντός των ιεραρχιών κληρονομιάς από toString () σε μια κατηγορία αντιπροσώπων που έχει δημιουργηθεί για το σκοπό αυτό.

συμπέρασμα

Νομίζω ότι οι περισσότεροι προγραμματιστές Java αναγνωρίζουν την αξία του καλού toString () υλοποιήσεις. Δυστυχώς, αυτές οι υλοποιήσεις δεν είναι πάντα τόσο καλές ή χρήσιμες όσο θα μπορούσαν. Σε αυτήν την ανάρτηση προσπάθησα να περιγράψω ορισμένες σκέψεις για βελτίωση toString () υλοποιήσεις. Αν και toString () Η μέθοδος δεν θα (ή τουλάχιστον δεν πρέπει) να επηρεάζει τη λογική όπως ισούται με (αντικείμενο) ή hashCode () μέθοδος μπορεί, μπορεί να βελτιώσει τον εντοπισμό σφαλμάτων και τη διαγνωστική απόδοση. Λιγότερο χρόνο που αφιερώνεται για να καταλάβει ποια είναι η κατάσταση του αντικειμένου σημαίνει περισσότερο χρόνο για την επίλυση του προβλήματος, τη μετάβαση σε πιο ενδιαφέρουσες προκλήσεις και την ικανοποίηση περισσότερων αναγκών του πελάτη.

Αυτή η ιστορία, "Java toString () σκέψεις" δημοσιεύθηκε αρχικά από την JavaWorld.

$config[zx-auto] not found$config[zx-overlay] not found