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

Πώς να χρησιμοποιήσετε ισχυρισμούς στην Java

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

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

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

Τι είναι οι ισχυρισμοί Java;

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

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

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

Πώς να γράψετε έναν ισχυρισμό στην Java

Οι ισχυρισμοί υλοποιούνται μέσω του διεκδικώ δήλωση και java.lang.AssertionError τάξη. Αυτή η δήλωση ξεκινά με τη λέξη-κλειδί διεκδικώ και συνεχίζει με μια έκφραση Boolean. Εκφράζεται συντακτικά ως εξής:

διεκδικώ BooleanExpr;

Αν BooleanExpr αξιολογείται ως αληθινό, δεν συμβαίνει τίποτα και η εκτέλεση συνεχίζεται. Εάν η έκφραση αξιολογηθεί ως ψευδής, ωστόσο, AssertionError αποστασιοποιείται και ρίχνεται, όπως αποδεικνύεται στην καταχώριση 1.

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

δημόσια τάξη AssertDemo {public static void main (String [] args) {int x = -1; διεκδικούν x> = 0; }}

Ο ισχυρισμός στην καταχώριση 1 υποδεικνύει την πεποίθηση του προγραμματιστή ότι η μεταβλητή Χ περιέχει μια τιμή μεγαλύτερη ή ίση με 0. Ωστόσο, αυτό δεν συμβαίνει σαφώς. ο διεκδικώ Η εκτέλεση της δήλωσης οδηγεί σε ρίψη AssertionError.

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

Εξαίρεση στο νήμα "main" java.lang.AssertionError στο AssertDemo.main (AssertDemo.java:6)

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

διεκδικώ BooleanExpr : π.χ.;

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

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

δημόσια τάξη AssertDemo {public static void main (String [] args) {int x = -1; assert x> = 0: "x <0"; }}

Συλλογή καταχώρισης 2 (javac AssertDemo.java) και εκτελέστε το με ενεργοποιημένους ισχυρισμούς (java -ea AssertDemo). Αυτή τη φορά, θα πρέπει να παρατηρήσετε την ακόλουθη ελαφρώς διευρυμένη έξοδο, η οποία περιλαμβάνει τον λόγο της ρίψης AssertionError:

Εξαίρεση στο νήμα "main" java.lang.AssertionError: x <0 στο AssertDemo.main (AssertDemo.java:6)

Για οποιοδήποτε από τα δύο παραδείγματα, τρέξιμο AssertDemo χωρίς το - ναι Η επιλογή (ενεργοποίηση ισχυρισμών) δεν έχει αποτέλεσμα. Όταν οι ισχυρισμοί δεν είναι ενεργοποιημένοι, δεν εκτελούνται, αν και εξακολουθούν να υπάρχουν στο αρχείο κλάσης.

Προϋποθέσεις και μετα-προϋποθέσεις

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

  • ΕΝΑ προϋπόθεση είναι μια συνθήκη που πρέπει να αξιολογηθεί ως αληθής πριν από την εκτέλεση ορισμένης ακολουθίας κώδικα. Οι προϋποθέσεις διασφαλίζουν ότι οι καλούντες τηρούν τις συμβάσεις τους με τους καλούντες.
  • ΕΝΑ μετά την κατάσταση είναι μια συνθήκη που πρέπει να αξιολογηθεί ως αληθινή μετά την εκτέλεση ορισμένης ακολουθίας κώδικα. Οι προϋποθέσεις διασφαλίζουν ότι οι καλούντες τηρούν τις συμβάσεις τους με τους καλούντες.

Προϋποθέσεις

Μπορείτε να επιβάλλετε προϋποθέσεις σε δημόσιους κατασκευαστές και μεθόδους κάνοντας σαφείς ελέγχους και ρίχνοντας εξαιρέσεις όταν είναι απαραίτητο. Για ιδιωτικές μεθόδους βοηθού, μπορείτε να επιβάλλετε προϋποθέσεις καθορίζοντας ισχυρισμούς. Εξετάστε την καταχώριση 3.

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

εισαγωγή java.io.FileInputStream; εισαγωγή java.io.InputStream; εισαγωγή java.io.IOException; κλάση PNG {/ ** * Δημιουργήστε μια παρουσία PNG, διαβάστε το καθορισμένο αρχείο PNG και αποκωδικοποιήστε το * σε κατάλληλες δομές. * * @param filespec διαδρομή και όνομα αρχείου PNG για ανάγνωση * * @throws NullPointerException όταν αρχείο αρχείων είναι * μηδενικό * / PNG (String filespec) ρίχνει το IOException {// Επιβολή προϋποθέσεων σε μη ιδιωτικούς κατασκευαστές και // μεθόδους. εάν (filespec == null) ρίξτε νέο NullPointerException ("το filespec είναι null"); δοκιμάστε (FileInputStream fis = νέο FileInputStream (filespec)) {readHeader (fis); }} private void readHeader (InputStream is) ρίχνει το IOException {// Επιβεβαιώστε ότι η προϋπόθεση ικανοποιείται σε ιδιωτικές // βοηθητικές μεθόδους. assert is! = null: "null πέρασε στο είναι"; }} δημόσια τάξη AssertDemo {public static void main (String [] args) ρίχνει το IOException {PNG png = new PNG ((args.length == 0)? null: args [0]); }}

ο PNG Η τάξη στην Λίστα 3 είναι η ελάχιστη αρχή μιας βιβλιοθήκης για την ανάγνωση και την αποκωδικοποίηση αρχείων εικόνας PNG (φορητά γραφικά δικτύου). Ο κατασκευαστής συγκρίνει ρητά αρχείο αρχείων με μηδενικό, ρίχνουν NullPointerException όταν αυτή η παράμετρος περιέχει μηδενικό. Το θέμα είναι να επιβληθεί η προϋπόθεση ότι αρχείο αρχείων δεν περιέχει μηδενικό.

Δεν είναι κατάλληλο να προσδιορίσετε διεκδίκηση filespec! = null; επειδή η προϋπόθεση που αναφέρεται στο Javadoc του κατασκευαστή δεν θα (τεχνικά) θα τηρηθεί όταν οι ισχυρισμοί απενεργοποιήθηκαν. (Στην πραγματικότητα, θα τιμήθηκε γιατί FileInputStream () θα ρίξει NullPointerException, αλλά δεν πρέπει να βασίζεστε σε συμπεριφορά χωρίς έγγραφα.)

Ωστόσο, διεκδικώ είναι κατάλληλο στο πλαίσιο του ιδιωτικού readHeader () βοηθητική μέθοδος, η οποία θα ολοκληρωθεί τελικά για να διαβάσει και να αποκωδικοποιήσει μια κεφαλίδα 8 byte ενός αρχείου PNG. Η προϋπόθεση ότι είναι να περάσει πάντα μια μη μηδενική τιμή θα διατηρείται πάντα.

Μετα προϋποθέσεις

Οι μεταϋποθέσεις καθορίζονται συνήθως μέσω ισχυρισμών, ανεξάρτητα από το εάν η μέθοδος (ή ο κατασκευαστής) είναι δημόσια. Εξετάστε την καταχώριση 4.

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

δημόσια τάξη AssertDemo {public static void main (String [] args) {int [] array = {20, 91, -6, 16, 0, 7, 51, 42, 3, 1}; ταξινόμηση (πίνακας); για (int element: array) System.out.printf ("% d", element); System.out.println (); } ιδιωτικό στατικό boolean isSorted (int [] x) {για (int i = 0; i x [i + 1]) επιστροφή false; επιστροφή αληθινή? } ιδιωτικό στατικό κενό (int [] x) {int j, a; // Για όλες τις ακέραιες τιμές εκτός από την αριστερή τιμή ... για (int i = 1; i 0 && x [j - 1]> a) {// Shift αριστερή τιμή - x [j - 1] - μία θέση στα δεξιά της - // x [j]. x [j] = x [j - 1]; // Ενημέρωση θέσης εισαγωγής στην αρχική θέση της μετατοπισμένης τιμής // (μία θέση προς τα αριστερά). j--; } // Εισαγάγετε μια θέση εισαγωγής (η οποία είναι είτε η αρχική θέση εισαγωγής // είτε η τελική θέση εισαγωγής), όπου η τιμή είναι μεγαλύτερη από // ή ισούται με όλες τις τιμές στα αριστερά της. x [j] = α; } assert isSorted (x): "ο πίνακας δεν ταξινομείται"; }}

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

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

Ισχυρισμοί έναντι εξαιρέσεων στην Java

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

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

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

Πότε να χρησιμοποιείτε εξαιρέσεις

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

public double sqrt (double x) {assert x> = 0: "το x είναι αρνητικό"; // ...}

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

public double sqrt (double x) {if (x <0) ρίξτε νέο IllegalArgumentException ("το x είναι αρνητικό"); // ...}

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

Ίσως έχετε παρατηρήσει μια λεπτή διαφορά μεταξύ του ισχυρισμού και της λογικής εντοπισμού σφαλμάτων. Οι δοκιμές ισχυρισμού x> = 0, ενώ οι δοκιμές λογικής ανίχνευσης σφαλμάτων x <0. Ο ισχυρισμός είναι αισιόδοξος: Υποθέτουμε ότι το επιχείρημα είναι εντάξει. Αντίθετα, η λογική εντοπισμού σφαλμάτων είναι απαισιόδοξη: Υποθέτουμε ότι το επιχείρημα δεν είναι εντάξει. Οι ισχυρισμοί τεκμηριώνουν σωστή λογική, ενώ οι εξαιρέσεις τεκμηριώνουν εσφαλμένη συμπεριφορά χρόνου εκτέλεσης.

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

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