2010-08-24 6 views
20

Ich habe PMD verwendet, um mögliche Probleme in meinem Java-Code zu erkennen, und ich habe seinen Rat gefunden, zwischen dem Nützlichen, dem Idiosynkratischen und dem "WTF ?!" zu unterscheiden.Everything's Final

Eines der Dinge, die es mir sagen, ist die Verwendung des Schlüsselwortes final für buchstäblich jede Variable, die ich anhängen kann, einschließlich der Eingabeparameter. Für tatsächliche Konstanten scheint das vernünftig, aber für andere Sachen scheint es mir einfach seltsam, vielleicht sogar ein bisschen kontraproduktiv.

Gibt es konkrete Vorteile/Nachteile zu hängen final auf jeder Variablendeklaration Sie können?

+1

Siehe http://stackoverflow.com/questions/137868/using-final-modifier-whene-applicable-in-java –

Antwort

21

"Jede variable Deklaration, die Sie möglicherweise können" klingt ein bisschen extrem, aber final ist eigentlich in vielerlei Hinsicht vorteilhaft. Manchmal wünsche ich, dass final das Standardverhalten war, und kein Schlüsselwort erforderlich, aber echte "Variablen" erforderte einen Modifikator variable. Scala adoptierte so etwas wie diesen Ansatz mit seinen val und var Schlüsselwörtern — mit val (das final -ähnliche Schlüsselwort) wird dringend empfohlen.

Es ist besonders wichtig, sorgfältig zu prüfen, ob jede Elementvariable final, volatile oder keines ist, da die Threadsicherheit der Klasse davon abhängt, ob dies richtig ist. Werte, die den Variablen final und volatile zugewiesen sind, sind immer für andere Threads sichtbar, ohne einen synchronized Block zu verwenden.

Für lokale Variablen ist es nicht so kritisch, aber die Verwendung von final kann Ihnen helfen, über Ihren Code klarer zu denken und einige Fehler zu vermeiden. Wenn Sie nicht erwarten, dass sich ein Wert innerhalb einer Methode ändert, sagen Sie dies mit final, und lassen Sie den Compiler unbemerkt von dieser Erwartung Kenntnis nehmen.Mir ist das derzeit nicht bewusst, aber es ist leicht vorstellbar, dass ein JIT-Compiler diesen Hinweis verwenden könnte, um die Leistung zu verbessern.

In der Praxis deklariere ich lokale Variablen final wann immer ich konnte. Ich mag das visuelle Durcheinander nicht und es scheint umständlich. Aber das heißt nicht, dass es nicht etwas ist, das ich tun sollte.

Es wurde vorgeschlagen, das Schlüsselwort var in Java einzufügen, um Typinterferenzen zu unterstützen. Als Teil dieses Vorschlags gab es jedoch eine Reihe von Vorschlägen für zusätzliche Möglichkeiten zur Festlegung der Unveränderbarkeit lokaler Variablen. Ein Vorschlag war beispielsweise, das Schlüsselwort val hinzuzufügen, um eine unveränderbare Variable mit abgeleitetem Typ zu deklarieren. Alternativ, einige befürworten die Verwendung von final und var zusammen.

+0

Im Nachhinein betrachtet wäre das gewesen das beste. Es hätte jedoch eine C-Semantik durchbrochen, die explizit versucht wurde, C++ - Programmierern einen einfachen Übergang zu geben. –

2

Dies ist ein gängiges Idiom für Werkzeuge wie PMD. Zum Beispiel sind unten die entsprechenden Regeln in Checkstyle. Es ist wirklich eine Frage des Stils/der Vorliebe und du könntest für beide Seiten argumentieren.

Meiner Meinung nach ist die Verwendung von final für Methodenparameter und lokale Variablen (falls zutreffend) ein guter Stil. Das Idiom "Design for Extension" ist umstritten.

5

final teilt den Leser, dass der Wert oder die zugeordneten Referenz zuerst die gleichen später zu jeder Zeit ist.

Wie alles, was endgültig ist in diesem Szenario endgültig sein kann, ein fehlt final sagt dem Leser, dass der Wert wird Änderung später, und das zu berücksichtigen.

+0

Das ist sinnvoll für Primitive oder für unveränderliche Objekte wie String. Aber fördert dies ein falsches Sicherheitsgefühl für veränderbare Objekte? – BlairHippo

+0

Ein fehlendes Finale sagt Ihnen nur, dass es sich später ändern kann, sicher nicht, dass es das wird. Das anzunehmen ist einfach falsch. Wenn eine Klasse nicht als endgültig definiert ist, kann sie unterklassifiziert sein, bedeutet nicht, dass es sich um eine Klasse handelt. Die Verwendung von final für alle Variablen ist offen für Diskussionen (siehe hier), so dass ihre Abwesenheit genauso leicht auf die Präferenz von Programmierern zurückzuführen ist. – Robin

+1

@Robin, bitte beachten Sie, dass das OP sagte "Alles ist endgültig". Das ist der Fall, über den ich diskutiere. Bitte lesen Sie die Fragen richtig, bevor Sie die Antworten ablehnen. –

1

PMD hat auch Optionsregeln, die Sie einschalten können, beschwert sich über final; Es ist eine willkürliche Regel.

Wenn ich ein Projekt mache, bei dem die API in ein anderes Team - oder in die Welt - exportiert wird, lasse die PMD-Regel so, wie sie ist. Wenn Sie gerade etwas entwickeln, das für immer und immer eine geschlossene API sein wird, deaktivieren Sie die Regel und sparen Sie sich etwas Zeit.

1

Hier sind einige Gründe, warum es benefitial sein kann fast alles alsfinal

Schluss 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 kann dann für andere Teile des Codes verwendet wird, markiert zu haben, oder Auf diese Weise können Sie den Wert ändern, ohne ihn einzeln ändern zu müssen.

Schluss 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 bauen Sie eine endgültige Variable scoped, die ein Präfix zu dem Parameter environmentKey hinzufügt. In diesem Fall ist die letzte Variable nur innerhalb des Ausführungsbereichs gültig, der bei jeder Ausführung der Methode unterschiedlich ist. Jedes Mal, wenn die Methode eingegeben wird, wird das Finale rekonstruiert. Sobald es konstruiert ist, kann es im Rahmen der Methodenausführung nicht geändert werden. Auf diese Weise können Sie eine Variable in einer Methode für die Dauer der Methode fixieren. 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"); 
    } 
} 

Schluss 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 nicht laufen in der Logik/Geschäftsfehler, wenn jemand versehentlich Variablen ändert, die nicht geändert werden sollen.

Schluss Kollektionen

Verschiedene 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 es nicht als unveränderbar festgelegt:

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

Finale Klassen und Schluss Methoden nicht bzw. erweitert oder überschrieben werden.

EDIT: UM DAS FINAL CLASS PROBLEM IN BEZUG AUF ENCAPSULATION 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 final ist zu erklären, alle seine Konstrukteure als privat zu machen:

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

es letzte Markierung spart das Problem, wenn Sie herausfinden, dass es sich wirklich um ein Finale handelt, um einen Blick auf diese Testklasse zu werfen. sieht auf den ersten Blick öffentlich aus.

Da der einzige Konstruktor der Klasse privat ist, ist es leider nicht möglich, diese Klasse zu erweitern. Im Fall der Testklasse gibt es keinen Grund, dass die Klasse endgültig sein sollte. Die Klasse Test ist ein gutes Beispiel dafür, wie implizite finale Klassen Probleme verursachen können.

Also sollten Sie es endgültig markieren, wenn Sie implizit eine Klasse endgültig machen, indem Sie es Konstruktor privat machen.