Bessere Performance durch final: wann denn überhaupt?

nossek

Aktives Mitglied
Guten Abend,

es ist ja hier schon häufiger diskutiert worden, (und an anderen Stellen wird es häufig behauptet) dass eine Verwendung von final (für Klassen, Methoden, Variabeln oder Argumente) unter Umständen Performance verbessert.

Ich bin gard ziemlich viel am rumtesten was Performance angeht. Und habe noch nie einen Fall gefunden, wo "final" irgendwas gebracht hat.

Kann mir vielleicht jemand einen Fall umschreiben, wo das was bringt?

Danke, Gruß

nossek
 
Viel spannender fände ich persönlich jetzt wie du das getestet hast (oder getestet zu haben glaubst :bae: ).

Ob und wann es wirklich verläßlich messbar etwas bringt... das ist mit vielen "wenn"s und "aber"s versehen. Üblicherweise wird 'final' auch weniger für Optimierungen empfohlen, sondern eher weil es teilweise als "guter Stil" angesehen wird. (Das kann an manchen Stellen zutreffen, und ich habe mir das standardmäßige "private final" schon fast angewöhnt, aber bei Methodenparametern konnte ich mich noch nicht (systematisch) dazu durchringen...).

Am ehesten könnte ich mir wirklich messbare Auswirkungen noch bei vielen (vielen, vielen, vielen) Aufrufen von public-Methoden einer finalen/nicht finalen Klasse vorstellen, aber ... an den meisten Stellen ist der Bytecode, der entsteht, unabhängig vom "final"... und da könnte dann auch nichtmal der JIT das "final" ausnutzen...
 
Hmnaja 🙂 Achte mal drauf, bei wie vielen Fields du "final" dazuschreiben könntest - es sind mehr, als man im ersten Moment denken würde (schon allein die meisten Collections, und alles was einmal im Konstruktor übergeben wird). Es gibt ja auch das Mantra: "Minimize Mutability", und wenn man versucht, dem zu folgen, ergeben sich häufige 'final's fast von allein. Tatsächlich denke ich, dass die ALLERmeisten Fehler in Programmen nicht mit falsch implementierten Algorithmen oder so zusammenhängen, sondern direkt mit einem fehlerhaften Zustand zu tun haben. Multithreading (was immer wichtiger wird) verstärkt dieses Problem nochmal überproportional.

EDIT: Aber natürlich gibt es "manchmal" immernoch setter und damit auch nicht-finale private Variablen
 
Viel spannender fände ich persönlich jetzt wie du das getestet hast (oder getestet zu haben glaubst ).

Uh, den ganzen code kann ich hier nicht posten, verwende etliche eigene Klassen...

Mal so grob ein Beispiel:

habe zB eine Klasse NumberUtil, nur mit statischen Methoden.

eine Methode heisst
Java:
public static double map(double value, double isMin, double isMax, double targetBoundary1, double targetBoundary2)
die skaliert einen Wert aus einem gegebenen Wertebereich [isMin-isMax] auf einen gewünschten Wertebereich [targetBoundary1-targetBoundary2].

dann eine Klasse ArrayUtil, in der die entsprechende Methode...
Java:
public static double[] mapArray(double[] array, double isMin, double isMax, double targetBoundary1, double targetBoundary2)
... map(...) auf ein array anwendet - und entsprechend für jedes einzelne Element des arrays die Methode aus meiner NumberUtil aufruft.

Habe das mit sehr großen arrays und tausenden von Durchläufen getestet, und ob nun die ArrayUtil und die NumberUtil oder die Argumente der Methoden final sind oder nicht, macht wie gesagt keinen Unterschied.

Und, ja, ich habe die Ausgabe der Methoden über die Konsole ausgegeben (damit nicht verwendete Ergebnisse nicht womöglich wegoptimiert werden. Und die Zeit für die Konsolenausgabe nicht mitgestoppt...

Edit: Vielleicht wird es aus opitmierungsperspektive erst wichtig, wenn die Klassen auch nicht-statische Methoden haben?!

Edit2: Und vielleicht beschäftige ich mich auch grad zuviel mit "premature optimization"
 
Zuletzt bearbeitet:
@Marco Ja ok im Bereich der GUI-Programmierung zB mag das wohl stimmen. Ich meine wie oft tauscht man denn die Referenz auf einen Button x oder so aus.. Aber ich finde man sollte grundsätzlich auf final verzichten, und nur wenn's nötig ist dazuschreiben (und nicht andersrum). Ich finde ein final impliziert die bewusste Design-Entscheidung, dass sich der Wert zur Laufzeit nicht ändern darf bzw. wird. Das musst du erstmal rechtfertigen können, zB im Hinblick auf die Software-Logik (eben so Dinge wie id's, wo final ja eigentlich immer zu sehen ist). Aber wenn du's nicht kannst, dann solltest du es auch nicht final machen. Denn der Nachteil von "Per-Default" finals ist, dass du dir damit erstmal ohne handfestes Argument einschränkst. Warum dir die Möglichkeit nehmen, zur Laufzeit dynamisch zu sein, oder abzuleiten, overriden etc? Und wenn dir irgendwann mal kommt, du willst das doch nicht final machen, dann darfst du erstmal refactoren: Setter erstellen, nicht vergessen den Kontroll-Code der bisher direkt im Konstruktor steht da reinzuziehen, usw. Es reicht imho erstmal den Setter private zu halten. Denn wenn man in der eigenen Klasse rumwerkelt, dann sollte man eigentlich wissen, welcher Zustand erlaubt ist und welcher nicht.

@nossek:
Und vielleicht beschäftige ich mich auch grad zuviel mit "premature optimization"

Es gibt oder gab hier mal jmd mit einer ganz guten Signatur. Die lautete:

There are two rules for optimization:
1) Don't do it
2) (For experts only) Don't do it yet

Da ist was dran.. Für 99% aller Apps gilt eh immer 1), egal wie expert du bist. Denn es ist sch*** egal ob deine Suchanfrage, Filterung oder Whatever in 13ms abläuft oder in 9ms. Und das sind schon Werte für sehr komplexe Berechnungen.
 
Zuletzt bearbeitet:
M.E. hilft final vor allem, Fehler zu vermeiden; Performance-Aspekte sind aber durchaus auch da (wenn auch nicht so stark, wie man das vielleicht erwarten würde). Methoden, die final sind, kann der Compiler "inlinen", also quasi an die Stelle des Aufrufs kopieren. Das spart etwas Zeit für den Methodenaufruf, vergrößert aber (bei nicht-trivialen Methoden) den (Byte-)Code.

Beispiel:
Java:
public class Final {

	private final int i1 = 1;
	private int i2 = 1;


	public final int getI1() {
		return i1;
	}

	public int getI2() {
		return i2;
	}

	public final int getI11() {
		return getI1();
	}

	public int getI22() {
		return getI2();
	}
}

Daraus entsteht folgender Bytecode:
Java:
Compiled from "Final.java"
public class Final extends java.lang.Object{
public Final();
  Code:
   0:	aload_0
   1:	invokespecial	#1; //Method java/lang/Object."<init>":()V
   4:	aload_0
   5:	iconst_1
   6:	putfield	#2; //Field i1:I
   9:	aload_0
   10:	iconst_1
   11:	putfield	#3; //Field i2:I
   14:	return

public final int getI1();
  Code:
   0:	iconst_1
   1:	ireturn

public int getI2();
  Code:
   0:	aload_0
   1:	getfield	#3; //Field i2:I
   4:	ireturn

public final int getI11();
  Code:
   0:	aload_0
   1:	invokevirtual	#4; //Method getI1:()I
   4:	ireturn

public int getI22();
  Code:
   0:	aload_0
   1:	invokevirtual	#5; //Method getI2:()I
   4:	ireturn

}

Man sieht, dass bei getI1() direkt der Wert der Konstanten in den Bytecode kopiert wurde; getI1() ist also geringfügig kürzer (und damit theoretisch zur Laufzeit auch schneller) als getI2(). Bei getI11() hat der Compiler den Vorteil allerdings nicht genutzt; hier bringt final bzgl. Performance nichts, da de rBytecode identisch ist mit der non-final-Variante getI22().
 
Kurzum: final verbessert Deine Performance nicht.

Vorsicht ist allerdings bei Murrays-Beispiel geboten, denn die Methoden getI1() und getI11() können nun auch nicht mehr vererbt werden!
 
Kurzum: final verbessert Deine Performance nicht.
Das kann man m.E. so nicht sagen. Man sieht im (zugegebenermaßen konstruierten) Beispiel ja, das getI1() kürzer ist als getI2(). Wenn die VM eine Anweisung weniger abzuarbeiten hat, dann geht das geringfügig schneller. Bei dieser trivialen Methode ist sogar der Bytecode kürzer als in der non-final-Variante, wodurch Laden und Verifizieren der Klassen ebenfalls etwas beschleunigt werden sollten.
Aber: dieser Effekte sind sehr, sehr klein.

Vorsicht ist allerdings bei Murrays-Beispiel geboten, denn die Methoden getI1() und getI11() können nun auch nicht mehr vererbt werden!
Wie HDI schon sagte: vererbt sehr wohl, aber wer von dieser Klasse erbt, der kann die Implementierung dieser Methoden nicht mehr verändern, weil er sie nicht überschreiben kann. Das kann aber manchmal durchaus gewünscht sein.
 
Also ich finde man sollte final nicht auf Grund von Performance einsetzen, so einfach. Soweit ich weiß fehlt es bisher weltweit an einem Exempel aus der Praxis, bei dem es im Hinblick auf Performance etwas gebracht hat Dinge final zu machen.
 
Say what? :autsch: Hast du denn keine sich ändernden Daten in deiner Software oder was? final kommt bei mir nur in sehr seltenen Fällen vor, zB bei Membern für eine id.

Falls Du Eclipse verwendest: Einfach mal die entsprechende Save Action aktivieren. Passiert mir recht oft, dass da zahlreiche finals hinzugefügt werden (sowohl bei eigenem als auch bei fremdem Code).

Soweit ich weiß fehlt es bisher weltweit

Ich kenne auch keinen aus Bielefeld...
 
Naja final bringt schon etwas.

Zitat aus der VM Specifiaction:

... If a method is final or implicitly final, a compiler or a runtime code generator can safely "inline" the body of a final method, replacing an invocation of the method with the code in its body.

Das heißt wenn eine Methode final ist kann eine Methode leichter geinlined wird.

Java:
class A{
   public final void foo(){
        System.out.println("HALLO WELT");
   }
   
   public void bar(){
        foo();
    }
}

Kann problemlos umgewandelt werden in:

Java:
class AInline{

    public final void foo(){
        System.out.println("HALLO WELT");
    }
 
   public void bar(){
        System.out.println("HALLO WELT");
    }
}

Ohne final ginge das nicht, da es dann eine Klasse B geben könnte die die Methode foo überschreibt, und somit das Verhalten von bar ändert.

Durch final kann die JVM oder der Compiler den Code einfach inlinenen was günstiger ist als ein Methodenaufruf, da kein Methodenstack angelegt werden muss, keine Parameterreferencen kopiert werden müssen, und was sonst so zu einem Methodenaufruf gehört.

Im Großen und Ganzen ist das Microoptimierung. Final sollte trotzdem so oft wie möglich eingesetzt werden um das Open-Closed Prinzip und damit das Liskovsches Substitutionsprinzip einzuhalten.
 
Jetzt fängt wieder einer an... Wir haben bereits geklärt dass final in der Theorie mehr Performance bringen kann, es aber aus diesem Grunde nicht in der Praxis eingesetzt werden sollte.

Im Großen und Ganzen ist das Microoptimierung.
Ganz genau. Und das bringt nur Ärger.

Final sollte trotzdem so oft wie möglich eingesetzt werden um das Open-Closed Prinzip und damit das Liskovsches Substitutionsprinzip einzuhalten.
Hast du den Artikel selbst überhaupt gelesen? Wenn du überall final hinklatscht dann ist da nix mehr mit Erweiterung. Keine Ableitung (final class), kein Override (final method), und mit "geschlossen für Modifikationen" ist nur Datenkapselung gemeint (Modifikation über Setter) und nicht, dass der Wert selbst sich niemals ändern darf.
 
Klar hab ich den Artikel gelesen. Hast du meinen Beitrag gelesen?

Ich habe mir die Mühe gemacht in der Spezifikation nach einem Hinweis zu suchen wieso final Performazevorteile bringt. Das einzige was dazu drin steht, ist das inlinen von Code durch den Compiler/JIT, das war ein Askept der noch nicht aufgeführt war und da die Frage war wieso final Performanzvorteile bringt dachte ich, dass ich ihn schreiben kann. Falls nicht bitte ich dich um Entschuldigung.

Was final wahrlos hinklatschen angeht, stimme ich dir zu, beim Programmieren darf man ruhig nachdenken. Nur 99% der Bugs die ich so täglich fixe gehen entweder darauf zurück, das Klassen maximal mutabel sind oder Klassen Methoden wahrlos überschreiben und somit das Verhalten von anderen Methoden ändern. Beides wäre durch final nicht möglich.

und mit "geschlossen für Modifikationen" ist nur Datenkapselung gemeint (Modifikation über Setter) und nicht, dass der Wert selbst sich niemals ändern darf.

Das hast du irgendwie falsch verstanden. Mit "Closed for Modifikation" ist nicht der Zustand eines Objektes gemeint, sondern das Verhalten einer Klasse hinsichtlich Vererbung.
 
das inlinen von Code durch den Compiler/JIT, das war ein Askept der noch nicht aufgeführt war
Schau dir mal den Beitrag von Murray weiter oben an 😉 (STRG+F und "inline"). Aber unabhängig von diesem speziellen Hinweis (natürlich kann man mal ein Posting oder einen Satz überlesen bzw das topic nur überfliegen wenn man sich einhakt) gab es jetzt schon diverse Antworten in denen gesagt wurde:
1) final kann Performance bringen in der Theorie
2) in der Praxis sollte der TO das aber gleich wieder vergessen
Deswegen habe ich mich gefragt warum du die Performance-Geschichte jetzt wieder aufrollst.

Was final wahrlos hinklatschen angeht, stimme ich dir zu, beim Programmieren darf man ruhig nachdenken. Nur 99% der Bugs die ich so täglich fixe gehen entweder darauf zurück, das Klassen maximal mutabel sind oder Klassen Methoden wahrlos überschreiben und somit das Verhalten von anderen Methoden ändern. Beides wäre durch final nicht möglich.
Wie du schon sagst, man kann auch mal nachdenken. Wer "wahrlos" überschreibt der sollte den Job halt nicht machen. Ich finde man kann nicht sagen "Ich mach das final weil sonst jemand, der null Ahnung hat von dem was er da tut, einen Fehler machen könnte". Ich weiß ja nicht wo du arbeitest, aber wenn das 99% der Bugs sind, dann such dir andere Kollegen. Und "beides wäre durch final nicht möglich" - richtig. Schon mal überlegt, dass es vllt einen Grund gab dass die Methode overrided wurde? Da hat die Impementierung aus der Vaterklasse nicht ausgereicht. Ok, mach sie final, dann kann man keinen Fehler machen. weil man nämlich nichts machen kann, ist das jetzt besser?

edit: Und warum Murray sich bei dir bedankt dafür dass du das wiederholst was er gesagt hat versteh ich nicht, aber da hat wohl jmd was gegen mich ;(
 
Zuletzt bearbeitet:
Kleine Anmerkung von mir zu diesem Thema, auf die nicht eingegangen werden muss:

Um final wirklich zu verstehen muss man funktionale Programmierung verstanden haben.
 
Sorry bei das Wörtchen inline hab ich in Murrays Posting anscheinend überlesen und mich mehr auf das Codebeispiel und den Bytecode konzentriert, da wird ja keine Methode geinlined und ich dachte es geht da um das laden der Konstante im Vergleich zu einer nicht Konstante.

99% ist vielleicht etwas übertrieben, aber es ist ein großer Teil. Die Bugs die ich so kenne entstehen oft dadurch, dass eine kleine Änderung große Auswirkungen haben. In großen komplexen Systemen ist das nun mal so, dass man unmöglich alle Auswirkungen einer Änderung überblicken kann. Besonders fieß zu finden sind Fehler die durch eine indirekte Codeänderung, wie z.B. Ableitungen, reingekommen sind. Wenn ich meinen Code schon so robust mache, dass keine Änderungen möglich sind, signalisiere ich meinen Kollegen "wenn du diese Methode überschreibst, kann etwas schlimmes passieren" oder "wenn dieser Wert sich ändert, fällt etwas an einer ganz anderen Stelle um". Ohne das er/sie alle Zusammenhänge analysieren muss, kann er/sie sich eine andere Lösung ausdenken oder zu mir kommen und zusammen schauen ob es nicht doch geht.

Die Hemmschwelle ein "final" wegzumachen ist doch sehr hoch. Oder es mit einem Zitat aus dem Jornalismus zu sagen "Einer muss sich immer anstrengen, entweder derjenige der ließt oder derjenige der schreibt".
 
edit: Und warum Murray sich bei dir bedankt dafür dass du das wiederholst was er gesagt hat versteh ich nicht, aber da hat wohl jmd was gegen mich ;(
Also ich bestimmt nicht.

"Dankenswert" fand ich nicht so sehr die Wiederholung, sondern die Aussage
Nur 99% der Bugs die ich so täglich fixe gehen entweder darauf zurück, das Klassen maximal mutabel sind oder Klassen Methoden wahrlos überschreiben und somit das Verhalten von anderen Methoden ändern. Beides wäre durch final nicht möglich.
 
Aber ich finde man sollte grundsätzlich auf final verzichten, und nur wenn's nötig ist dazuschreiben (und nicht andersrum). Ich finde ein final impliziert die bewusste Design-Entscheidung, dass sich der Wert zur Laufzeit nicht ändern darf bzw. wird. Das musst du erstmal rechtfertigen können, zB im Hinblick auf die Software-Logik (eben so Dinge wie id's, wo final ja eigentlich immer zu sehen ist). Aber wenn du's nicht kannst, dann solltest du es auch nicht final machen. Denn der Nachteil von "Per-Default" finals ist, dass du dir damit erstmal ohne handfestes Argument einschränkst. Warum dir die Möglichkeit nehmen, zur Laufzeit dynamisch zu sein, oder abzuleiten, overriden etc?
ich seh das genau anders rum. Man sollte begruenden, warum einen variable nicht final sein soll. Einfach per se mal einen Mutator hinzufuegen, weil der bestimmt irgendwann mal gebraucht werden koennte ist falsch. Code sollte nicht aufgrund von moeglichen Geschehnissen enstehen, sondern weil es der Verwender verlangt.
Ist einem zum Entwicklungszeitpunkt unklar, ob eine Variable geaendert werden soll, so ist es sicherer final zu setzen, da man dies spaeter ohne Probleme wieder rueckgaengig machen kann. Andersrum ist das, sobald der Code in verwendung ist (moeglich noch API) schwer bis gar nicht moeglich.
Du erstellst hoffentlich auch nicht automatisch fuer jeder Variable gleich getter und setter ?

Alles in allem sollte man defensiv programmieren. So wenig wie moeglich nach aussen geben und sowenig wie moeglich mutable gestalten. Erst wenn der aktive Bedarf da ist.

Ergo, solange es niemand zwingt deine Variablen / Klassen nicht final zu halten, gehoert ein final da in.

Final bei methoden zeigt hervorragend, ob diese Methode ueberschrieben werden soll oder nicht. Es zeigt bei Klassen eindeutig welche fuer Vererbung frei sind und bei Variablen welche mutable sind. Wer Dynamik braucht kann diese spaeter immer noch einbauen
 
Erstmal stimme ich bygones zu 100% zu und zum zweiten kommt diese Aussage

"Final erhöht die Performance"

bestimmt auch daher, dass es bei vernünftigem Einsatz in einer Multithreading Umgebung eben stimmt. Wenn hier soviel wie möglich final ist, dann kann man nahezu auf Synchronisation verzichten und auch die Sichtbarkeit von Änderungen muss nicht zwischen verschiedenen Threads geflusht werden. Bei so simplen aufrufen, wie der TO hier dargestellt hat, wird man da mit Sicherheit keinen Performancegewinn sehen.
 
Ich denke schon, dass es stimmt, dass final Performance Vorteile bringt:

Die JVM nutzt Method-Inlining (C/C++ Programmierern sagt das vlt noch was) bei final, static und private MEthods, sofern KEINE lokalen Variablen darin enthalten sind und es keinen Rückgabetypen gibt.

Sprich damit werden die Sprunganweisungen minimiert. Ich habe das bei meiner Serialisierungslibarry germerkt. Gerade wenn es unheimlich viele verschachtelte kleine Funktionen gibt, macht das viel (ok, soviel nun auch wieder nicht) aus. Außerdem geschieht inlining auch nur bei -server Varianten (Ok, ist ja heute überall so). Bei mir viel das z.b. bei Umwandlungsfunktionen ins Gewicht: Also in etwa sowas:

Converter.intToArray(54, byteArray); // ist static und ist void

In dem Fall würde die Funktion an den Stellen wo es laut dem Compiler Sinn macht, inlining erfahren.

Ich das mal auf den unendlich vielen Oracle Seiten gelesen. Leider hab ich grad keine Zeit , das wieder rauszusuchen. Also glaubt es oder zweifelt es an 😉

Gruß,
Chris

AUßERDEM: Wie Marco schon geschrieben hat, ist final ein wichtiges Sprachmittel für Multithreading. WEnn man sich mal das JavaMemoryModell anschaut, dann wird das eindeutig klar: final Variablen müssen z.b. NICHT synchronisiert werden (was logisch ist) aber es geht noch weiter, denn final Variablen agieren in die eine Richtung ähnlich den volatile Variablen, denn die Sichtbarkeit wird garantiert auch beim ThreadContext Wechsel.... Mit final zu arbeiten macht sehr viel Sinn!
 
[...]
final Variablen müssen z.b. NICHT synchronisiert werden (was logisch ist)

Das ist trifft nur bei primitiven Typen zu. Alles andere sind Referenzen. Es ist schön wenn man eine Referenz auf final setzt, man den Inhalt dieser Referenz aber beliebig ändern kann. D.h. final List<Integer> lst = new ArrayList<Integer>(); muss immernoch synchronisiert werden wenn man Schreib- und Lesevorgänge parallel auf der Liste ausführt.
 
Edit2: Und vielleicht beschäftige ich mich auch grad zuviel mit "premature optimization"

Wenn es wirklich um messbare Performancevorteile geht: Ja. Da werden 1000 final's nicht so viel bringen wie ein unbedachtes 'new ArrayList()' oder ein überflüssiges 'Collections.sort()'...

Aber die Frage, wann und ob 'final' geht ja darüber hinaus:


Aber ich finde man sollte grundsätzlich auf final verzichten, und nur wenn's nötig ist dazuschreiben (und nicht andersrum). Ich finde ein final impliziert die bewusste Design-Entscheidung, dass sich der Wert zur Laufzeit nicht ändern darf bzw. wird. Das musst du erstmal rechtfertigen können, zB im Hinblick auf die Software-Logik (eben so Dinge wie id's, wo final ja eigentlich immer zu sehen ist). Aber wenn du's nicht kannst, dann solltest du es auch nicht final machen. Denn der Nachteil von "Per-Default" finals ist, dass du dir damit erstmal ohne handfestes Argument einschränkst. Warum dir die Möglichkeit nehmen, zur Laufzeit dynamisch zu sein, oder abzuleiten, overriden etc? Und wenn dir irgendwann mal kommt, du willst das doch nicht final machen, dann darfst du erstmal refactoren: Setter erstellen, nicht vergessen den Kontroll-Code der bisher direkt im Konstruktor steht da reinzuziehen, usw.

Ich bemühe mich auch, nicht unreflektiert irgendwelche Empfehlungen anzunehmen und weiterzugeben. Aber in diesem Punkt leuchten mir die Vorteile des "Minimize Mutability" ein, das immerhin kein geringerer als Josh Bloch in "Effective Java" propagiert:
"Classes should be immutable unless there's a very good reason to make them mutable....If a class cannot be made immutable, limit its mutability as much as possible."
(zu den Gründen: Siehe das entsprechende Buch)

Teilweise ist bygones (und andere) schon darauf eingegangen, aber ... so wie du die Frage stellst, klingt es natürlich sehr suggestiv: "Warum dir die Möglichkeit nehmen, zur Laufzeit dynamisch zu sein...?" 😉 Es geht ja nicht um "dynamisch sein", sondern nur darum, dass man sich ganz genau im Klaren ist (und am Code deutlich macht) welche Zustände und Änderungen man erlaubt und welche nicht. Darum eine Suggestivfrage in die andere Richtung: Wenn du eine Klasse mit 10 Fields erstellst - klickst du dann erstmal pauschal in Eclipse auf "Generate Setters and Getters" für alle Fields :autsch: Wohl auch nicht 😉
Overriding wird durch 'final fields' ja nicht beeinflußt, aber durch 'final methods' - und auch da ist es eigentlich gut, pauschal bei allen 'final' dazuzuschreiben, außer, wenn man sich GANZ sicher ist (und auch deutlich machen will!) dass JEDER diese Methode überschreiben darf. Es gibt nicht viele Methoden, für die das der Fall ist - und die meisten, bei denen das der Fall ist, sind sowieso "protected abstract"...
Der Zusammenhang dieses Punktes mit den Open-Closed-Principle wird ja weiter unten schon erwähnt.


Das kann man m.E. so nicht sagen. Man sieht im (zugegebenermaßen konstruierten) Beispiel ja, das getI1() kürzer ist als getI2(). Wenn die VM eine Anweisung weniger abzuarbeiten hat, dann geht das geringfügig schneller.

Ja, das ist schon fast "Zufall", wegen der iconst-Instruktion. Bei einem 'private final int i=5' würde es ja schon nichts mehr bringen 😉

Ansonsten... bezogen sich alle beiträge auf das, was ich schon im 1. und 2. geschrieben oder angedeutet hatte:
- 'final' bei Methoden kann einen Vorteil bringen. Als Grund wurde bisher genannt, dass sie durch das 'fina' geinlinet werden können. Es KÖNNTE auch Vorteile bringen, weil sie das "Poly" in dem Wort "Polymorphie" ggf. auf "Mono" reduzieren könnte (in bezug auf [JavaSpecialists 158] - Polymorphism Performance Mysteries Explained ) aber das müßte man noch genauer durchdenken.
- Allgemein dient 'final' aber nicht höherer Performance, sondern einer Einschränkung (unerwünschter!) Veränderbarkeit, sowohl auf Ebene der Objekte als auch der Klassen.
 
Also bei Methoden, Klassen und auch Membern mag das ja sinnvoll sein, aber warum braucht ihr final bei Methodenparametern? Ich sage es ehrlich, in den meisten Fällern brauche ich es nicht. Warum?
Wenn ich einen Parameter als final deklariere, damit ich ihn in meiner 10-100, 200 oder 300? zeiligen Methode nicht versehentlich doch verändern kann, habe ich etwas bei der der Methode falsch gemacht. Ganz einfach, sie ist zu lang!

Lösung: Kürzere Methoden, mehr Methoden, mehr Klassen und schon brauchts keine final Parameter mehr 😉

edit: Das mit der Optimierung im gezeigten Beispiel ist übrigens kein muß für ein Compiler oder Runtime-Optimierer, sondern kann implementiert werden oder auch nicht (dann hat man eben man Pech gehabt, wenn man sich drauf verlassen hat).

nochmal edit: Man kann sich mit der gezeigten Optimierung übrigens auch gut selber ins Knie schiessen. Klasse B wird dementsprechend inline optimiert und bekommt den Code von einer Methode von Klasse A eingeimpft. Super. Klasse A ändert sich, wird neu kompiliert, Klasse B nicht. Dumm gelaufen für Klasse B.
Ähnlich ist es mit dem berühmten "public final static String", dessen Wert auch schön direkt in den Bytecode anderer Klassen geht, während bei anderen atomare Datentypen ein Verweis darauf in den Bytecode geht.
 
Zuletzt bearbeitet:
Also bei Methoden, Klassen und auch Membern mag das ja sinnvoll sein, aber warum braucht ihr final bei Methodenparametern? Ich sage es ehrlich, in den meisten Fällern brauche ich es nicht. Warum?

Das würde mich auch interessieren. Es wird zwar immer wieder gepredigt, aber üblicherweise ohne Begründung. Ich verwende Parameter immer dann neu, wenn ich sie im Rahmen der Anfangsprüfung modifiziere (z. B. [c]String#trim()[/c] ausführen oder eine [c]null[/c]-Referenz durch einen Default-Wert ersetzen). Ich möchte mal sehen, wie das lesbarer werden soll, wenn man sich dafür neue Variablennamen aus dem Hintern ziehen muss.

Man kann sich mit der gezeigten Optimierung übrigens auch gut selber ins Knie schiessen. Klasse B wird dementsprechend inline optimiert und bekommt den Code von einer Methode von Klasse A eingeimpft. Super. Klasse A ändert sich, wird neu kompiliert, Klasse B nicht. Dumm gelaufen für Klasse B.

Ich war bisher davon ausgegangen, dass das Inlining in der JVM stattfindet und nicht im Compiler. Quellen dafür wären aber mal interessant.
 
Bei sowas wie [c]public static final int[/c] kann man dieses "Einsetzen" recht leicht testen, mit zwei Klassen, von denen man dann per Hand nur die Klasse mit dem int neu compiliert.
 
Bei Konstanten (primitive Datentypen, Strings und Klassen-Objekte) sollte es ja klar sein. Die werden per [c]ldc[/c] direkt aus dem Constant Pool geholt. Mir ging es eher um Inlining von Methoden.
 

Neue Themen


Zurück
Oben