Wann sollte eine letzte für Methodenparameter und lokale Variablen verwenden?

StackOverflow https://stackoverflow.com/questions/154314

  •  03-07-2019
  •  | 
  •  

Frage

Ich habe ein paar Referenzen ( zum Beispiel ), die so viel wie möglich mit final vorschlagen und ich frage mich, wie wichtig das ist. Dies ist vor allem im Zusammenhang mit den Verfahrensparametern und lokaler Variablen, nicht endgültig Methoden oder Klassen. Für Konstanten, macht es offensichtlich Sinn.

Auf der einen Seite kann der Compiler einige Optimierungen machen und es macht die Programmierer die Absicht klarer. Auf der anderen Seite, fügt es Ausführlichkeit und die Optimierungen können trivial sein.

Ist es etwas, das ich sollte sich bemühen, sich zu erinnern?

War es hilfreich?

Lösung

Obsess über:

  • Endgültige Felder - Kennzeichnung Felder als letzte Kräfte sie durch Bauende festgelegt werden, dass Feldverweis unveränderlich zu machen. Dies ermöglicht eine sichere Veröffentlichung von Feldern und kann die Notwendigkeit zur Synchronisation vermeidet später liest. (Beachten Sie, dass für einen Objektverweis, nur das Feld Referenz ist unveränderlich -. Dinge, die Referenz-Objekt bezieht sich noch ändern zu können, und das wirkt sich die Unveränderlichkeit)
  • Endgültige statische Felder -. Obwohl ich Aufzählungen jetzt für viele der Fälle verwenden, wo ich verwenden, um statische endgültige Felder verwenden

Betrachten wir aber verwenden umsichtig:

  • Abschlussklassen - Rahmen / API-Design ist der einzige Fall, in dem ich es für
  • .
  • Endgültige Methoden - Grundsätzlich gleiche wie letzte Klassen. Wenn Sie Template-Methode Muster wie verrückt und Kennzeichnung Sachen endgültig verwenden, angewiesen sind Sie wahrscheinlich zu viel auf Erbschaft und nicht genug auf Delegation.

ignorieren, wenn nicht das Gefühl anal:

  • Methodenparameter und lokale Variablen - ich dies selten weitgehend tun, weil ich faul bin und ich finde es den Code unübersichtlich. Ich werde vollständig zugeben, dass Markierungsparameter und lokale Variablen, die ich werde mich nicht ändern ist „righter“. Ich wünschte, es war der Standard. Aber es ist nicht und ich finde den Code schwieriger zu verstehen, über und über mit Finale. Wenn ich in einem fremden Code bin, werde ich sie nicht herausziehen, aber wenn ich neuen Code schreibe ich werde sie nicht in. Eine Ausnahme ist der Fall, wo man etwas endgültig zu markieren, so dass Sie zugreifen können es aus einer anonymen inneren Klasse.

Andere Tipps

  

Ist es etwas, das ich sollte sich bemühen, sich daran zu erinnern, zu tun?

Nein, wenn Sie Eclipse verwenden, weil Sie eine Aktion speichert automatisch konfigurieren können, um diesen final Modifikatoren für Sie hinzufügen. Dann sind Sie die Vorteile für weniger Aufwand erhalten.

Die Entwicklungszeit Vorteile der „final“ sind mindestens so wichtig wie die Laufzeitvorteile. Es erzählt Zukunft Herausgeber des Codes etwas über Ihre Absichten.

eine Klasse „final“ Markierung zeigt an, dass Sie keine Anstrengungen bei der Konstruktion oder Implementierung der Klasse Erweiterung zu behandeln anmutig gemacht haben. Wenn die Leser Änderungen an der Klasse machen, und wollen die „endgültige“ Modifikator entfernen, können sie dies auf eigene Gefahr. Es liegt an ihnen, um sicherzustellen, dass die Klassenerweiterung gut behandelt.

eine Variable "final" Marking (und es im Konstruktor zuweisen) ist mit Dependency Injection nützlich. Es gibt die „Mitarbeiter“ Natur der Variablen.

ein Verfahren "final" Marking in abstrakten Klassen nützlich ist. Es gibt eindeutig, wo die Erweiterungspunkte sind.

Ich habe Markierungsmethode Parameter und Einheimischen gefunden als final als Refactoring Hilfe nützlich ist, wenn das betreffende Verfahren ein unverständliches Durcheinander mehrere Seiten lang ist. Sprinkle final liberal, sehen, was Fehler der Compiler (oder IDE) „nicht auf endgültige Variablen zuweisen“ wirft, und Sie können nur herausfinden, warum die Variable „Daten“ endet null, obwohl mehrere genannt (veraltet) Kommentare schwören, dass passieren kann, nicht.

Dann können Sie einige der Fehler beheben, indem die wiederverwendet Variablen mit neuen Variablen ersetzt erklärt der Einsatzstelle näher. Dann finden Sie Sie ganze Teile des Verfahrens in Scoping Klammern wickeln kann, und plötzlich bist du ein IDE keypress weg von „Method Extract“ und Ihre Monster bekam nur verständlicher.

Wenn Ihre Methode ist nicht bereits ein wartbaren Wrack, ich denke, es Wert sein könnte Sachen endgültig in die Menschen davon abzuhalten, es in das Wrack drehen; aber wenn es ein kurzes Verfahren (siehe: nicht wartbaren), dann riskieren Sie eine Menge Ausführlichkeit hinzufügen. Insbesondere ist Java-Funktion Signaturen schwer genug, in 80 Zeichen zu passen, wie es ohne Zusatz von sechs pro Argument ist!

Ich verwende final die ganze Zeit Java mehr Ausdruck basieren. Siehe Java Bedingungen (if,else,switch) sind nicht Ausdruck basiert, die ich immer besonders gehasst haben, wenn Ihr in die funktionale Programmierung verwendet (dh ML, Scala oder Lisp).

So sollten Sie immer versuchen, (IMHO) verwenden endgültige Variablen, wenn die Bedingungen verwendet wird.

Lassen Sie mich Ihnen ein Beispiel:

    final String name;
    switch(pluginType) {
        case CANDIDATE_EXPORT:
            name = "Candidate Stuff";
            break;
        case JOB_POSTING_IMPORT:
            name = "Blah";
            break;
        default:
            throw new IllegalStateException();
    }

Wenn nun eine andere case Anweisung hinzufügen und nicht gesetzt name der Compiler fehl. Der Compiler wird auch fehlschlagen, wenn Sie auf jeden Fall nicht brechen (die Sie die Variable gesetzt). Dies ermöglicht Ihnen, Java sehr ähnlich Lisp der let Ausdrücke zu machen und macht es so Ihr Code nicht massiv eingerückt ist (wegen der lexikalischen Scoping-Variablen).

Und wie @Recurse bemerkt (aber anscheinend -1 mir) Sie können mit aus der vorhergehenden tun String name final machen den Compilerfehler zu bekommen (was ich nie gesagt, konnte man nicht), aber man konnte leicht der Compiler Fehler machen weggehen Einstellung Name nach der switch-Anweisung, die die Expression Semantik oder schlechter zu vergessen wegwirft break die Sie nicht einen Fehler verursachen kann (trotz allem, was @Recurse sagt) ohne final mit:

    String name;
    switch(pluginType) {
        case CANDIDATE_EXPORT:
            name = "Candidate Stuff";
            //break; whoops forgot break.. 
            //this will cause a compile error for final ;P @Recurse
        case JOB_POSTING_IMPORT:
            name = "Blah";
            break;
    }
    // code, code, code
    // Below is not possible with final
    name = "Whoops bug";

Aufgrund der Bug Einstellungsnamen (außer zu vergessen, die auch einen anderen Fehler break) kann ich jetzt dies versehentlich tun:

    String name;
    switch(pluginType) {
        case CANDIDATE_EXPORT:
            name = "Candidate Stuff";
            break;
        //should have handled all the cases for pluginType
    }
    // code, code, code
    // Below is not possible with final
    name = "Whoops bug";

Die letzte Variable erzwingt eine einzelne Bewertung dessen, was Name sein sollte. Ähnlich wie eine Funktion, die einen Rückgabewert hat immer einen Wert zurückgeben (ohne Berücksichtigung von Ausnahmen) wird der Name Schalterblock hat Namen aufzulösen und somit gebunden an diesen Schalterblock, die Refactoring Teile des Codes erleichtert (dh Eclipe refactor: Extrakt-Methode) .

Das oben in OCaml:

type plugin = CandidateExport | JobPostingImport

let p = CandidateExport

let name = match p with
    | CandidateExport -> "Candidate Stuff"
    | JobPostingImport -> "Blah" ;;

Die match ... with ... werten wie eine Funktion, dh Ausdruck. Beachten Sie, wie sieht es aus wie unsere switch-Anweisung.

Hier ist ein Beispiel in Schema (Racket oder Chicken):

(define name 
    (match b
      ['CandidateExport "Candidate Stuff"]
      ['JobPostingImport "Blah"]))

Nun, das hängt alles von Ihrem Stil ... wenn Sie die letzten wie das Sehen, wenn Sie nicht die Variable werden ändern, dann verwenden. Wenn Sie es nicht sehen, MÖGEN ... dann lassen Sie es aus.

Ich persönlich mag so wenig Ausführlichkeit wie möglich, so neige ich dazu, zusätzliche Keywords zu verwenden zu vermeiden, die nicht wirklich notwendig ist.

Ich ziehe es allerdings dynamische Sprachen, so dass es wahrscheinlich keine Überraschung Ich mag Ausführlichkeit zu vermeiden.

Also, ich würde sagen, nur die Richtung wählen Sie in Richtung lehnen und gehen nur mit ihm (was auch immer der Fall ist, versuchen, konsequent zu sein).


Als Randbemerkung, habe ich an Projekten gearbeitet, die sowohl Verwendung und nicht über ein solches Muster verwenden, und ich habe keinen Unterschied in der Höhe von Bugs oder Fehler gesehen ... Ich glaube nicht, ist es ein Muster das wird sehr groß Ihre Anzahl der Fehler oder etwas verbessern, aber wieder ist es Stil, und wenn Sie die Absicht gerne ausdrücken, dass Sie es nicht ändern wird, dann gehen Sie vor und verwenden Sie es.

Es ist in Parameter nützlich, um den Parameterwert durch einen Unfall zu vermeiden, ändern und einen subtilen Fehler einzuführen. Ich benutze diese Empfehlung zu ignorieren, aber nach ein paar 4 Stunden zu verbringen. in einem schrecklichen Verfahren (mit Hunderten von Zeilen Code und mehrere fors, verschachtelten ifs und alle Arten von schlechten Praktiken) Ich würde Ihnen empfehlen, es zu tun.

 public int processSomethingCritical( final int x, final int y ){
 // hundreds of lines here 
     // for loop here...
         int x2 = 0;
        x++; // bug aarrgg...
 // hundreds of lines there
 // if( x == 0 ) { ...

 }

Natürlich in einer perfekten Welt dies nicht passieren würde, aber .. gut .. manchmal muss man anderen Code unterstützen. :(

Wenn Sie eine Anwendung schreiben, dass jemand den Code nach lesen, sagen wir, 1 Jahr, dann ja, verwenden endgültig auf Variable, die nicht die ganze Zeit geändert werden sollte. Auf diese wird Ihr Code mehr „selbsterklärend“ sein und die Chance, auch für andere Entwickler reduzieren dumme Dinge zu tun, wie eine lokale Konstante als temporären lokalen Variable.

Wenn Sie einige Wegwerf-Code schreiben, dann, nah, nicht die Mühe, die Konstante alle zu identifizieren und sie endgültig zu machen.

werde ich so viel verwenden endgültig, wie ich kann. Dadurch wird Flag, wenn Sie versehentlich das Feld ändern. I auch Verfahrensparameter Abbindezeit. Dabei habe ich mehrere Fehler von Code gefangen Ich habe übernommen, wenn sie versuchen, auf ‚‘ ein Parameter vergessen Java nach Wert übergibt.

Es ist von der Frage nicht klar, ob dies offensichtlich, aber wirkt sich auf eine Methode Parameter endgültig machen nur den Körper des Verfahrens. Es ist nicht alle interessanten Informationen über die an den Aufrufer Absichten Methode vermitteln. Die Aufgabe in übergeben werden kann nach wie vor innerhalb der Methode mutiert werden (Finale sind nicht consts), und der Umfang der Variablen ist innerhalb des Verfahrens.

Ihre genaue Frage zu beantworten, würde ich nicht die Mühe, eine Instanz oder eine lokale Variable zu machen (einschließlich Methodenparameter) endgültig, wenn der Code es erforderlich (zB die Variable von einer inneren Klasse verwiesen wird), oder eine wirklich komplizierte Logik zu klären .

Zum Beispiel Variablen, ich würde sie endgültig machen, wenn sie logisch Konstanten sind.

Es gibt viele Einsatzmöglichkeiten für die Variable final. Hier sind nur ein paar

Endgültige Konstanten

 public static class CircleToolsBetter {
     public final static double PI = 3.141;
        public double getCircleArea(final double radius) {
          return (Math.pow(radius, 2) * PI);
        }
    }

Dies ist für andere Teile des Codes können dann verwendet werden, oder von anderen Klassen zugegriffen wird, auf diese Weise, wenn Sie jemals den Wert ändern würde würden Sie nicht ändern man muss um eins.

Endgültige Variablen

public static String someMethod(final String environmentKey) {
    final String key = "env." + environmentKey;
    System.out.println("Key is: " + key);
    return (System.getProperty(key));

  }

}

In dieser Klasse baut man eine scoped letzte Variable, die ein Präfix zu dem Parameter environmentKey hinzufügt. In diesem Fall ist die letzte Variable nur endgültig innerhalb des Ausführungs Umfangs, die bei jeder Durchführung des Verfahrens unterschiedlich ist. Jedes Mal, wenn die Methode eingegeben wird, ist die letzte rekonstruiert. Sobald es aufgebaut ist, kann sie nicht während der Rahmen des Verfahrens der Ausführung geändert werden. Auf diese Weise können Sie eine Variable in einem Verfahren für die Dauer des Verfahrens beheben. siehe unten:

public class FinalVariables {


  public final static void main(final String[] args) {
    System.out.println("Note how the key variable is changed.");
    someMethod("JAVA_HOME");
    someMethod("ANT_HOME");
  }
}

Endgültige Konstanten

public double equation2Better(final double inputValue) {
    final double K = 1.414;
    final double X = 45.0;

double result = (((Math.pow(inputValue, 3.0d) * K) + X) * M);
double powInputValue = 0;         
if (result > 360) {
  powInputValue = X * Math.sin(result); 
} else {
  inputValue = K * Math.sin(result);   // <= Compiler error   
}

Diese sind besonders nützlich, wenn Sie wirklich lange Schlangen von Codes haben, und es wird Compiler-Fehler erzeugen, so dass Sie laufen in nicht auf Logik / Geschäft Fehler, wenn jemand versehentlich Variablen ändert, die nicht geändert werden sollten.

Endgültige Kollektionen

Verschiedenen Fall, wenn wir über Kollektionen sprechen, müssen Sie sie als unveränderbar setzen.

 public final static Set VALID_COLORS; 
    static {
      Set temp = new HashSet( );
      temp.add(Color.red);
      temp.add(Color.orange);
      temp.add(Color.yellow);
      temp.add(Color.green);
      temp.add(Color.blue);
      temp.add(Color.decode("#4B0082")); // indigo
      temp.add(Color.decode("#8A2BE2")); // violet
      VALID_COLORS = Collections.unmodifiableSet(temp);
    }

sonst, wenn Sie nicht setzen es als nicht änderbar:

Set colors = Rainbow.VALID_COLORS;
colors.add(Color.black); // <= logic error but allowed by compiler

Abschlussklassen und Endgültige Methoden kann nicht bzw. erweitert oder überschrieben werden.

EDIT: Das letzte Klasse PROBLEM IN BEZUG Einkapselung Adresse:

Es gibt zwei Möglichkeiten, um eine Klasse endgültig zu machen. Die erste ist das Schlüsselwort final in der Klassendeklaration zu verwenden:

public final class SomeClass {
  //  . . . Class contents
}

Die zweite Möglichkeit, eine Klasse endgültig zu machen, ist alle seine Konstrukteuren als privat zu deklarieren:

public class SomeClass {
  public final static SOME_INSTANCE = new SomeClass(5);
  private SomeClass(final int value) {
  }

es letzte Markierung erspart Ihnen die Mühe, wenn herauszufinden, dass es tatsächlich ein endgültiges, ist Blick auf diese Test-Klasse zu demonstrieren. den ersten Blick sieht Öffentlichkeit.

public class Test{
  private Test(Class beanClass, Class stopClass, int flags)
    throws Exception{
    //  . . . snip . . . 
  }
}

Leider, denn der einzige Konstruktor der Klasse privat ist, ist es unmöglich, diese Klasse zu erweitern. Im Fall der Test-Klasse, gibt es keinen Grund, dass die Klasse endgültig sein sollte. Die Test-Klasse ist ein gutes Beispiel dafür, wie implizite Abschlussklassen können zu Problemen führen.

So Sie es Endnote sollten, wenn Sie implizit eine Klasse final machen, indem es Konstruktor privat zu machen.

Etwas eines Kompromisses, wie Sie erwähnen, aber ich ziehe die explizite Verwendung von etwas über die implizite Verwendung. Dies wird helfen, eine gewisse Zweideutigkeit für zukünftige Maintainer des Codes entfernen - auch wenn es nur Sie.

Wenn Sie innere (anonym) Klassen, und das Verfahren benötigt Variable der umschließenden Methode zuzugreifen, müssen Sie diese Variable als final haben.

Anders als das, was Sie gesagt haben, ist richtig.

Mit final Schlüsselwort für eine Variable, wenn Sie diese Variable als immutable machen

Durch die Variable als endgültig erklärt, es Entwicklern hilft mögliche Modifikation Fragen der Variablen, um auszuschließen, in hochMultiThread-Umgebung.

Mit Java-8-Version, haben wir ein weiteres Konzept namens " effectively final variable ". Eine nicht abschließende Variable als letzter Variable hieven kann.

lokale Variablen aus einem Lambda-Ausdruck referenziert wird, muss endgültige oder effektiv endgültig

  

Eine Variable wird als wirksam final , wenn es nicht nach der Initialisierung im lokalen Block geändert wird. Dies bedeutet, dass Sie jetzt die lokale Variable ohne abschließende Schlüsselwort innerhalb einer anonymen Klasse oder Lambda-Ausdruck verwenden können, vorausgesetzt, sie müssen effektiv endgültig sein.

Bis Java 7, können Sie nicht eine nicht endgültige lokale Variable in einer anonymen Klasse verwenden, sondern von Java 8 können Sie

Haben Sie einen Blick auf diese Artikel

Eine sehr einfache Antwort haben wir 3 Fälle mit Final mit Variablen, Finale mit Methoden && Finale mit Klassen ..

1.Final mit Variable: u `t Diese Variable mehr als einmal vergeben ..

2.Final mit Methoden: u `t diese Methode überschreiben ..

3.Final mit Klassen: u `t eine endgültige Klasse erweitern

Zu allererst wird das endgültige Schlüsselwort verwendet, um eine Variable konstant zu machen. Konstante bedeutet, es ändert sich nicht. Zum Beispiel:

final int CM_PER_INCH = 2.54;

Sie würden die Variable endgültig erklären, weil ein Zentimeter pro Zoll ändert sich nicht.

Wenn Sie versuchen, einen endgültigen Wert außer Kraft zu setzen, ist die Variable, was es zuerst erklärt. Zum Beispiel:

final String helloworld = "Hello World";
helloworld = "A String"; //helloworld still equals "Hello World"

Es ist ein Übersetzungsfehler, die so etwas wie lautet:

local variable is accessed from inner class, must be declared final

Wenn Ihre Variablen können nicht als final deklariert werden oder wenn Sie nicht wollen, es endgültig, dies zu erklären versuchen:

final String[] helloworld = new String[1];
helloworld[0] = "Hello World!";
System.out.println(helloworld[0]);
helloworld[0] = "A String";
System.out.println(helloworld[0]);

Dies wird Druck:

Hello World!
A String
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top