Variable in Schleife deklarieren, Speicherplatz, Garbage Collector

texs89

Mitglied
Hallo,
ich habe mir die Frage gestellt ob es grundsätzlich immer sinnvoll ist Variablen außerhalb von Schleifen zu deklarieren oder ob das egal ist? Bezogen auf das Codebeispiel läuft das Programm ja ewig, bis es beendet wird. Wird dann mit jedem Schleifendurchlauf neuer Speicherplatz durch die Variablen und den Scanner usw. belegt, was ein Problem sein kann? Dann würde es ja Sinn machen diese vorher also außerhalb der while-Schleife zu deklarieren. Oder ist das egal? Wann werden denn Variablen grundsätzlich wieder freigegeben durch den Garbage Collector?

Vielen Dank für Eure Antworten!

Beispielcode:
Java:
   public static void main(String[] args) {

        while (true) {
            Scanner scan = new Scanner(System.in);
            // Eingabeaufforderungen für Mietkosten, Einkommen und Anzahl Kinder
            System.out.print("Bitte geben Sie die monatlichen Mietkosten ein: ");
            double mietkosten = scan.nextDouble();
            System.out.print("Bitte geben Sie das monatliche Einkommen ein: ");
            double einkommen = scan.nextDouble();
            System.out.print("Bitte geben Sie die Anzahl der Kinder ein: ");
            int anzahlKinder = scan.nextInt();

            // Berechnung des Wohngelds
            double wohngeld = berechneWohngeld(mietkosten, einkommen);
            // Berechnung des Kinderzuschlags
            double kinderzuschlag = berechneKinderzuschlag(anzahlKinder);
            // Pruefung Gesamtzahlung
            double gesamtzahlung = berechneGesamtzahlung(mietkosten, kinderzuschlag, wohngeld);
            // Ausgabe des berechneten Wohngelds (inkl. Kinderzuschlag)
            ausgabeWohngeld(gesamtzahlung);
        }
    }
 

httpdigest

Top Contributor
Den Scanner solltest du schon nur ein einziges Mal außerhalb der Schleife deklarieren und initialisieren.
Bei Variablendeklarationen an sich ist es egal, wo du sie deklarierst. Da ist der Interpreter und Compiler selbstverständlich schlau genug, durch Reachability-Analyse zu sehen, wie lange eine Variable Gültigkeit hat und wann deren Speicherplatz wiederverwendet werden kann.
Das Problem ist nur beim dynamischen Initialisieren einer Variablen mit immer wieder einem neuen Objekt.
Sowas ist im Falle eines Scanners sogar eigentlich falsch, da er im Zweifel mehr seines Inputs einliest und puffert.
 

KonradN

Super-Moderator
Mitarbeiter
Evtl. der kurze Hinweis: Es macht Sinn, Variablen immer so nah wie möglich an der Benutzung zu deklarieren. Es ist also unüblich, dass man am Anfang alle Variablen deklariert um diese dann irgendwann zu nutzen. (Das ist / war so üblich bei Skriptsprachen. Davon ist man weg!)

Aber natürlich sollte man Dinge nicht öfters machen als unbedingt notwendig. In diesem Fall ist es so, dass Du EINEN Scanner brauchst. Daher erstellst Du diesen nur ein einziges Mal und daher wäre dies vor der Schleife.
 

White_Fox

Top Contributor
Bei manchen Klassen könnte der Compiler sowas theoretisch wegoptimieren, zumindest wenn es bekannte Klassen sind (was bei Scanner der Fall wäre). Ich weiß aber nicht ob der Compiler das tatsächlich auch macht.

Ansonsten würde ich mir herzlich wenig Gedanken darum machen, wann du eine Variable deklarierst. Zum Thema Quellcodeoptimierung habe ich hier irgendwann mal was geschrieben: https://www.java-forum.org/thema/vom-sinn-quellcode-zu-optimieren-lesestoff-fuer-anfaenger.197081/

Normalerweise, nach althergebrachter Tradition, sollte man 'new' in Schleifen möglichst vermeiden, da der Compiler damit neuen Speicher belegt. Sehr wahrscheinlich, daß Java das früher auch mal so gemacht hat.
So weit ich weiß, alloziiert die JVM heute aber den Speicher nicht (mehr?) direkt vom Betriebssystem, sondern nimmt gleich einen größeren Block. Dein Programm benötigt z.B. jetzt 25MB RAM, dann fragt die JVM beim Betriebssystem direkt nach z.B. 100MB. Und wenn dein Programm nach einer Weile immer mehr braucht und irgendwann 80MB RAM belegt, alloziiert die JVM schon mehr Speicher noch bevor er wirklich nicht mehr reicht.
Und auch das Betriebssystem ist mittlerweile schlau genug, Speicherbereiche, die lange genug im RAM rumschimmeln ohne gelesen oder geändert zu werden, auf der Festplatte zwischenzuparken. In Windows heißt das Auslagerungsdatei.
Insofern sollte ein 'new' in einer Schleife heute eigentlich kein Problem sein. Wobei Scanner aber, wie gesagt, durchaus eine Ausnahme sein könnte, wobei der Scanner andererseits wieder so ein Spezialfall mit seinem Zugriff auf den Inputstream ist, andererseits blockiert der Scanner den Schleifendurchlauf und ob man so schnell etwas neues eingeben kann daß der alte Scanner das noch einlesen kann...

Am besten ist eigentlich immer noch, man probiert es einfach mal aus. Ich habe im Studium am liebsten in Laborübungen die Grenzen von allem möglichen direkt ausgetestet. In Laboren, also einer gesicherten Umgebung, kann man sowas machen, und bei Softwarespielereien kann sowieso kaum etwas kaputt gehen. Früher konnte man relativ leicht seinen kompletten Rechner zerballern und mußte dann das Betriebssystem neu installieren, ich meine das auch Hardwareschäden durch Software hervorgerufen werden konnten, aber diese Zeiten sind lange vorbei.

Also, bau doch mal eine Testklasse die in paar Strings verarbeitet (z.B. das erste Zeichen entfernt), damit auch etwas mehr Speicher benötigt wird als es bei einem lumpigen Integer der Fall wäre, und dann machst du zwei Schleifendurchläufe. Einmal erstellst du das Objekt einmal, und beim zweiten Mal erzeugst du das Objekt stets wieder neu, und stoppst die Zeit für beide Durchläufe. Die Apache Stopwatch-Klasse empfiehlt sich da. Und du stoppst die Zeit natürlich nicht für einen einzigen Durchlauf, sondern für z.B. 100.000 Durchläufe.
 

KonradN

Super-Moderator
Mitarbeiter
Es geht hier nicht um eine Optimierung von Code bezüglich Laufzeitverhalten! Es geht schlicht um Lesbarkeit! Und aus Sicht von Clean Code sollte man diesbezüglich immer darauf achten, dass der Code so lesbar wie nur irgendwie möglich ist.

Und wie @httpdigest ausgeführt hat, führt dies sogar ggf. zu einem unerwünschten Verhalten (Daher wird da ein Compiler schlicht nichts wegoptimieren! Scanner hat einen internen State, zu dem der Compiler nichts weiss. Wie soll er da irgend etwas optimieren?)
 

White_Fox

Top Contributor
Es geht hier nicht um eine Optimierung von Code bezüglich Laufzeitverhalten! Es geht schlicht um Lesbarkeit!
Ja – dir geht es darum (zu Recht natürlich). Ich glaube aber nicht daß der TS das im Sinne hatte als er den Thread eröffnet hat, immerhin erkundigt er sich explizit nach dem Speicherverhalten.

Wie soll er da irgend etwas optimieren?
Das war etwas ins Blaue spekuliert. Ich habe mich nie mit den Innereien der Standardbibliothek beschäftigt und auch nicht mit de Innereien der JVM. Meine Überlegung war rein struktureller Natur: Am Ende wird immer wieder der Inputstream über das Scannerobjekt ausgelesen. Rein von außen betrachtet (d.h. solche internen Feinheiten, wie httpdigest sie angesprochen hat mal außen vor gelassen) macht es keinen Unterschied, ob der Scanner in- oder außerhalb der Schleife initialisiert wird.

Mir ist schon klar daß das so nicht allgemeingültig ist. Wenn ich beispielsweise eine Klasse nehme die einen statischen Zähler hat der bei jedem Konstruktoraufruf inkrementiert werden würde, wäre dieser Zählerstand am Ende ein anderer.
Ich würde allerdings, ohne es wirklich zu wissen, davon ausgehen daß die Compilerbauer für die Klassen der Standardbibliothek besondere Optimierungen eingebaut haben. Immerhin sind diese Klassen ja bekannt, im Gegensatz zu dem was sich die Programmierer selber zurechtschnitzen.
 

White_Fox

Top Contributor
Eine Frage hätte ich mal noch @KonradN :
Evtl. der kurze Hinweis: Es macht Sinn, Variablen immer so nah wie möglich an der Benutzung zu deklarieren. Es ist also unüblich, dass man am Anfang alle Variablen deklariert um diese dann irgendwann zu nutzen. (Das ist / war so üblich bei Skriptsprachen. Davon ist man weg!)
Warum? Was gewinnt man, welche Last wird man los?
Ich habe das bisher immer genau so gemacht (Variablen am Anfang deklarieren), wahrscheinlich habe ich irgendwann mal gelesen daß es so gu wäre, und mir wäre bisher auch kein Nachteil dadurch aufgefallen. Aber du wirst das ja nicht ohne Grund schreiben.
 

httpdigest

Top Contributor
Was gewinnt man, welche Last wird man los?
Die Last der "Metal Complexity".
  • Du möchtest nicht immer wieder zig Zeilen hoch und runter scrollen, um den Typ einer Variablen zu finden, wenn du eine Referenz auf die Variable im Code siehst; idealerweise ist die Deklaration nicht weit weg von der Nutzung (wenn du gerade mal keine IDE mit mouse-hover/intellisense verwendest) - es verbessert einfach das Verständnis beim Lesen des Codes (z.B. auch für Reviews an Merge/Pull Requests, die nicht immer unbedingt in einer IDE gemacht werden müssen)
  • Du möchtest, wenn du eine neue Variable brauchst, auch nicht wieder bis zum Anfang der Funktion scrollen, sie dort deklarieren und dann wieder zurück zur Nutzungsstelle
 

KonradN

Super-Moderator
Mitarbeiter
Von der Funktionalität her macht es keinen Unterschied. Lokale Variablen landen auf dem Stack, d.h. der Compiler muss eh alles zusammen suchen und dann direkt am Methodenanfang "hinterlegen". Es gibt da also zur Laufzeit keinen Unterschied.

Das ist einfach ein Punkt, der bei Clean Code üblich ist. Hintergrund dabei ist aus meiner Sicht einfach ein: Was zusammen gehört ist zusammen. Wenn Du die Variable am Kopf der Methode deklarierst, dann gibst Du da ja einen Typ an und so. Und bei der Nutzung weiter unten ist dann unklar, was es ist? Oder bei Anpassungen musst Du erst nach oben scrollen um dann wieder nach unten zu scrollen um da weiter zu machen?
Es ist einfach unpraktisch - gerade wenn es längere Abschnitte werden.

Im Bereich Clean Code kommt man aber eh zu kurzen Methoden. Da spielt es dann immer weniger eine Rolle, weil sich nur minimal verschiebt.

Das wäre so meine Begründung. Generell ist das aber ein Thema, das jeder so machen darf, wie es es möchte. Es gibt dann auch interessante Aussagen wie in https://kmtsandeepanie.medium.com/how-to-write-clean-code-82aa5db6889d

Erst: "Better to declare variables as much as close to their usage." - ok, das habe ich ja gesagt ... aber dann kommt:
"When considering local variables, it is better if they are declared at the top of each function," - das ist aber dann doch das gegenteil? Aber es geht ja weiter und er grenzt es noch ein:
"control variables used in for loops should be declared within the loop statement. Instance variable declaration should appear at the top of the class."

In Klassen auf jeden Fall irgend eine Ordnung haben. Welche ist egal.
 

httpdigest

Top Contributor
Ich würde allerdings, ohne es wirklich zu wissen, davon ausgehen daß die Compilerbauer für die Klassen der Standardbibliothek besondere Optimierungen eingebaut haben. Immerhin sind diese Klassen ja bekannt, im Gegensatz zu dem was sich die Programmierer selber zurechtschnitzen.
Das haben sie ganz explizit nicht gemacht, um die Verantwortlichkeiten hier klar zu trennen und Interoperabilität zwischen einer Classlibrary und der JVM zu schaffen.
Aber erstmal: wenn wir hier von "Compiler" reden, dann meinen wir zwei verschiedene Dinge:
  • javac , bzw. der Java Quellcode -> JVM Bytecode Übersetzer (der ist wirklich unfassbar struntzdumm und guckt sich nicht den Code von aufgerufenen Methoden oder andere Klassen an als die gerade übersetzte)
  • die JVM (wie z.B. HotSpot) bzw. der Interpreter oder auch der JIT Laufzeitcompiler: Dieser übersetzt einfach Methoden nach bestimmten Metriken (häufig aufgerufen, oder enthält häufig iterierte Schleifen, etc.) und "guckt" dabei auch in aufgerufene Methoden mittels "Inlining". ABER er hat kein Wissen oder macht eine Unterscheidung zwischen JRE Klassenbibliotheks-Klassen oder nutzerdefinierten Klassen. Diese Unterscheidung macht höchstens nur der Bootstrap Classloader aus Sicherheitsgründen, damit User nicht alles mögliche in java.* überschreiben können.
Das einzige, was eine JVM aus Performancegründen macht, ist, bestimmte übliche und kleine Methoden wie etwa Math.sin(), Math.sqrt(), etc. mit handgeschriebenem Assembly-Code oder einfach einzelnen Prozessorinstruktionen bei der Kompilierung zu ersetzen, da es keinen Sinn ergibt, für solche Methoden auch noch eine Java-Implementierung bereitzustellen. Hier wird entweder also eine in C geschriebene Funktion (die mit der Classlibrary (also OpenJDK oder GNU Classpath) mitgeliefert wird) aufgerufen, oder aber die JVM (wie eben angesprochen) hat ein "Intrinsics" dafür und weiß einfach, dass der Prozessor, auf dem der Code gerade ausgeführt wird, dafür eine oder wenige schnellere Instruktionen nativ hat.
 

temi

Top Contributor
Was gewinnt man, welche Last wird man los?
Ich würde noch ergänzen, dass du auf diese Weise, den Gültigkeitsbereich einer Variable so klein wie möglich hältst.

Das erhöht die Les- und Wartbarbeit und reduziert Fehlermöglichkeiten, siehe auch Thema 57 aus "Effective Java" von Bloch.

Im Gegensatz dazu, könntest du alle Variablen global machen... (nicht gut).
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
S Warum kann ich nicht mehr als eine Variable in einer for Schleife deklarieren ? Java Basics - Anfänger-Themen 1
M Variable in einer Schleife initialisieren Java Basics - Anfänger-Themen 46
W Schleife und einmal variable++ zu viel Java Basics - Anfänger-Themen 20
T Variable in for Schleife ansprechen ohne Array ? Java Basics - Anfänger-Themen 25
I For Schleife - Variable verändern Java Basics - Anfänger-Themen 4
D Variable Anzahl an Buttons per Schleife Java Basics - Anfänger-Themen 7
H [erledigt] Variable initialisiert, aber nicht verfügbar (Schleife) Java Basics - Anfänger-Themen 3
R Variablen For Schleife, Variable in String inkrementieren Java Basics - Anfänger-Themen 5
J Sichtbarkeit Variable in Schleife Java Basics - Anfänger-Themen 5
D Javafx XYChart Variable in Schleife erzeugen? Java Basics - Anfänger-Themen 18
F Variable ohne Initialisierung in For Schleife Java Basics - Anfänger-Themen 5
N Variablen Variable nach Schleife nutzen Java Basics - Anfänger-Themen 5
C Variable Zeichenkette innerhalb einer Schleife ersetzen Java Basics - Anfänger-Themen 4
G Variable nach Schleife zurückgesetzt Java Basics - Anfänger-Themen 5
M Auf Variable in For-Schleife zugreifen! Java Basics - Anfänger-Themen 7
K Lokale Variable in for Schleife Java Basics - Anfänger-Themen 5
K Variable Menge an Variablennamen per Schleife erstellen Java Basics - Anfänger-Themen 10
M Länge eines Arrays als Variable speichern möglich? Java Basics - Anfänger-Themen 14
R Liste in Variable speichern Java Basics - Anfänger-Themen 6
J Java long- in int-Variable umwandeln Java Basics - Anfänger-Themen 6
Nitrogames Variablen Variable aus JOptionPane Abfrage in Array einfügen Java Basics - Anfänger-Themen 4
E Variable von 1. Fenster an 2. Fenster übergeben. Java Basics - Anfänger-Themen 7
T Datum als Variable wert Java Basics - Anfänger-Themen 4
G Variable aktualisiert sich nicht in rekursiver Methode Java Basics - Anfänger-Themen 4
R Compiler-Fehler Variable wird nicht gefunden bzw. erkannt? Java Basics - Anfänger-Themen 2
Say super.methode / super.variable und super(variable) Java Basics - Anfänger-Themen 2
M variable in anderer funktion aufrufen Java Basics - Anfänger-Themen 10
N Was Passiert mit dem Namen einer Variable, wenn man diese einer Liste Hinzufügt Java Basics - Anfänger-Themen 16
T Variable von Objekten in einer Methode überprüfen Java Basics - Anfänger-Themen 26
U Wie mache ich die Variable xyz eindeutig/unique? Java Basics - Anfänger-Themen 20
JordenJost char variable funktioniert irgendwie nicht a+b ergibt nicht à Java Basics - Anfänger-Themen 4
M Variable Felderanzahl Java Java Basics - Anfänger-Themen 10
T Variable durch Action Listener ändern Java Basics - Anfänger-Themen 2
stormyark Fehler beim überschreiben einer Variable Java Basics - Anfänger-Themen 1
P Zähler Variable für mehrere Objekte Java Basics - Anfänger-Themen 6
S Eine Variable in einem Array speichern Java Basics - Anfänger-Themen 5
I Methoden Wieso wird mein Array "a" verändert und meine Variable "a" nicht? Java Basics - Anfänger-Themen 4
M String mit Variable vergleichen Java Basics - Anfänger-Themen 9
M Methoden Wert einer Variable geht verloren? Java Basics - Anfänger-Themen 6
G variable kopieren bzw. woanders benutzen Java Basics - Anfänger-Themen 6
Ameise04 Variablen Inhalt einer Variable im Code verwenden? Java Basics - Anfänger-Themen 9
J Double Variable und Addition Java Basics - Anfänger-Themen 2
I Variable innerhalb Methode: Local variable test defined in an enclosing scope must be final or effectively final Java Basics - Anfänger-Themen 3
KogoroMori21 Variable im Parameter und Ohne Java Basics - Anfänger-Themen 5
Vivien Auf eine Variable von einer anderen Klasse aus zugreifen Java Basics - Anfänger-Themen 3
H Datentypen Wertebereich von <Klassenname> <Variable> Java Basics - Anfänger-Themen 12
M Private Variable Java Basics - Anfänger-Themen 2
idontknow707 Matrix nach z.B. Variable durchsuchen Java Basics - Anfänger-Themen 4
s.marcii Modulo in der Variable einsetzen - ist das möglich? Java Basics - Anfänger-Themen 2
N Variable aus anderen Variablen in statischer Klasse berechnen/abspeichern? Java Basics - Anfänger-Themen 4
Y Wie kann ich die Variable in der Try Catch returnen? Java Basics - Anfänger-Themen 3
K Übergabe des Wertes einer Variable aus main() in eine Klassenmethode Java Basics - Anfänger-Themen 8
B Inkrement von Variable Java Basics - Anfänger-Themen 8
V Variablen statische Variable einer Objektvariable zuordnen Java Basics - Anfänger-Themen 3
L Variable von einer Methode zu einer anderen Methode inkl. einer "Zwischenmethode" Java Basics - Anfänger-Themen 1
J JTextField Bezeichnung als Variable Java Basics - Anfänger-Themen 3
N Wie kann ich eine meine Variable Final machen? Java Basics - Anfänger-Themen 1
NeoLexx Variable für Array wird nicht korrekt übergeben Java Basics - Anfänger-Themen 45
M Enum-Variable HashMap zuweisen Java Basics - Anfänger-Themen 5
H Variable um 1 erhört ausgeben Java Basics - Anfänger-Themen 4
V Erste Schritte Eine Array-Variable mit Benutzereingaben befüllen Java Basics - Anfänger-Themen 3
J Fehlermeldung unklar. non-static variable player0 cannot be referenced from a static context Java Basics - Anfänger-Themen 4
P non-static variable cannot be referenced from a static context Java Basics - Anfänger-Themen 6
A Wie zwei zahlen in einer Variable speichern? Java Basics - Anfänger-Themen 7
W Problem mit dem Wert von boolean-Variable Java Basics - Anfänger-Themen 3
M Input/Output JTextField Eingabe in String Variable speichern Java Basics - Anfänger-Themen 15
A Kann man eine Methode als Variable speichern und danach noch verändern? Java Basics - Anfänger-Themen 6
L cannot find symbol variable Kon Java Basics - Anfänger-Themen 8
C Statischer Typ aber Variable nicht statisch? Java Basics - Anfänger-Themen 5
H Variable.methode aufstellen, verstehen Java Basics - Anfänger-Themen 2
R Warnung, wenn eine Variable eingegeben wird Java Basics - Anfänger-Themen 6
S Variable einscannen Java Basics - Anfänger-Themen 30
N Best Practice Rückgabe eines Terminal Befehls in eine Variable speichern Java Basics - Anfänger-Themen 27
M Erste Schritte Mit Variable verschiedene Texte in Textfeld einfügen Java Basics - Anfänger-Themen 27
J Input-Variable nicht sichtbar Java Basics - Anfänger-Themen 2
L Warum ist Variable null? Java Basics - Anfänger-Themen 3
E Variable (Vektor) in andere Methode übergeben Java Basics - Anfänger-Themen 4
A OOP Variable in anderer Klasse durch Methode aufrufen und einer anderen Variable gleichsetzen Java Basics - Anfänger-Themen 2
S Variable Parameter Java Basics - Anfänger-Themen 5
D Datei auslesen & Werte in Variable speichern Java Basics - Anfänger-Themen 12
P if - Statement erkennt variable nicht. Java Basics - Anfänger-Themen 12
J Ungewollte Wertveränderung einer Variable Java Basics - Anfänger-Themen 9
R Variablen Variable an FXML-Controller übergeben Java Basics - Anfänger-Themen 4
J Zugriff auf Variable in anderem Programm Java Basics - Anfänger-Themen 5
R variable istpositiv might not have been initialized Java Basics - Anfänger-Themen 2
A Methodenname aus variable Java Basics - Anfänger-Themen 2
L Variable aus einer Klasse in einer anderen Klasse nutzen Java Basics - Anfänger-Themen 6
P Methode soll Variable einer anderen Klasse ändern. Wie? Java Basics - Anfänger-Themen 1
Hanschyo Variable nicht initialisiert Java Basics - Anfänger-Themen 6
deatzi Variable aus If Abfrage später nutzen Java Basics - Anfänger-Themen 4
L Variable in If-Statement initialisieren Java Basics - Anfänger-Themen 4
C return kann nicht auf variable zugreifen Java Basics - Anfänger-Themen 26
S Wie erstelle ich eine Vorbedingung für eine Variable einer Methode ? Java Basics - Anfänger-Themen 5
V Warum speichert meine String-Variable nummerische Werte? Java Basics - Anfänger-Themen 3
J Wert eines Arrays einer Variable zuweisen, sobald der Wert eines anderen Arrays eintritt Java Basics - Anfänger-Themen 2
DaCrazyJavaExpert Compiler-Fehler Variable nicht mit null initialisiert, trotzdem: NullPointerException Java Basics - Anfänger-Themen 28
A Erste Schritte Mein Programm erkennt die variable EinAus.readInt nicht Java Basics - Anfänger-Themen 15
Aprendiendo [JAVA-Syntax] (int... variable) bei einem Konstruktor Java Basics - Anfänger-Themen 8
F Variablen If else: Einer Variable einen Wert hinzufügen oder so? Java Basics - Anfänger-Themen 6
Aprendiendo Interpreter-Fehler "non-static variable this cannot be referenced from a static context" Java Basics - Anfänger-Themen 2

Ähnliche Java Themen

Neue Themen


Oben