length-Methode bei for-Schleife

Hallo,

eine for Schleife durchläuft die Elemente eines Arrays:

for (int element = 0; element < elementsArray.length; element++) {
    // Tue etwas
}```
Das Array enthält natürlich noch mehr Elemente. 
Wendet die Laufzeitumgebung nun bei jedem Schleifendurchlauf die length-Methode auf das Array an oder ermittelt der Compiler bereits die Länge? Ich könnte ja auch folgendes schreiben:
```String[] elementsArray = { "acsm", "al5001" };
int elementsCount = elementsArray.length;
for (int element = 0; element < elementsCount; element++) {
    // Tue etwas
}```
Welche Schreibweise ist besser?

Besten Dank im Voraus.

Die erste Schreibweise ist besser weil sie eine Zeile spart :wink:

Was wolltest du denn ereichen?

Danke.

[QUOTE=maki]Die erste Schreibweise ist besser weil sie eine Zeile spart :wink:

Was wolltest du denn ereichen?[/QUOTE]Persönlich bevorzuge ich auch die kürzeren Schreibweisen.
Falls die Laufzeitumgebung bei jedem Schleifendurchlauf die length-Methode auf das Array anwenden muss, könnte es ja sein, dass es bei Arrays mit sehr vielen Elementen performanter wäre, die Länge vorher nur einmal zu ermitteln.

Die Länge wird ja nicht “ermittelt”, sondern nur “ausgelesen”. Die liegt einfach im Array-Objekt in einer Variable, und wird so oder so nur aktualisiert, wenn was neues ins Array rein kommt.

Die laenge eines Arrays ist fest nach der Erzeugung.
length liefert nicht die Anzahl der Elemente, sondern die (feste) groesse des Arrays.

Ansosnten:
Microoptimierungen sind meist sinnfrei, besser man optimiert nachdem man mit einem Profiler durchgemessen hat und vergleicht nach der Optimierung wieder.

Premature Optimization…

[QUOTE=reno][…]

[…]
1.String[] elementsArray = { “acsm”, “al5001” };
2.int elementsCount = elementsArray.length;
3.for (int element = 0; element < elementsCount; element++) {
4.// Tue etwas
5.}

Welche Schreibweise ist besser?
[/QUOTE]

Die zweite Variante wird oft wie folgt formuliert, einfach um den Scope der Variable möglichst klein zu halten.

2.for (int element = 0, count = elementsArray.length; element < count; element++) {
3.// Tue etwas
4.}

Und was besser ist, das kommt auf den Anwendungsfall an. Falls sich die unterliegende Datenstruktur ändert wirst du nicht darumkommen es wie im ersten Fall zu schreiben. Falls die Ermittlung der Anzahl eine teure Operation ist (man kann auch über andere Strukturen iterieren) wirst du sicher die zweite Variante bevorzugen.
Und ob man sich sicher sein kann das die JVM das im zweiten Fall vernünftig optimiert, wer weiß. Was aber höchstwahrscheinlich der Fall ist, in der zweiten Version ist die Längenvariable auf dem Stack und wahrscheinlich im Cache oder wird sogar in einem Register gehalten. Ich nehme deshalb an das die zweite Version nie langsamer ist als die erste Variante.

Richtig, die Länge beim Array ist fest nach der Erzeugung, mein Fehler. Ich arbeite zu viel mit ArrayLists in letzter Zeit, sry :slight_smile:

Dass die zweite Version nie langsamer ist als die erste Variante habe ich auch vermutet. Ich hätte gedacht, dass sie sogar schneller sein könnte, falls die length-Methode aus mehreren Codezeilen bestehen würde. Das ist aber anscheinend doch nicht der Fall und ich weiß nun, dass sich der Optimierungsaufwand hier nicht lohnt.

Dank euch.

[QUOTE=reno]Dass die zweite Version nie langsamer ist als die erste Variante habe ich auch vermutet. Ich hätte gedacht, dass sie sogar schneller sein könnte, falls die length-Methode aus mehreren Codezeilen bestehen würde. Das ist aber anscheinend doch nicht der Fall und ich weiß nun, dass sich der Optimierungsaufwand hier nicht lohnt.
[/QUOTE]
Wie ThreadPool richtig sagte, komm t es auf den Anwendungsfall an.

In deinem Falle, also mit Arrays, ist es egal.
Bei einer LinkedList zB. kann es auch egal sein, muss aber nicht.
Da hilft IMHO nur messen anstatt praeventiv ueberall voreilig zu “optimieren”, fuehrt meist zu haesslichem Code und dieser muss gerechtfertigt sein.

Und um es nochmal ganz deutlich zu sagen (andere hatten es schon angedeutet). length ist eine finales FELD des Arrays, auf das direkt zugegriffen wird. Es ist KEINE Methode. Insofern bringt ein vorheriges Kopieren keinerlei Vorteile hinsichtlich Geschwindigkeit. Das gilt für Arrays, da diese eine fixe Länge haben und diese deswegen als finales Feld zugreifbar gemacht werden kann. Für Collections gilt das nicht. Ihre “Länge” (die hier Größe/size) heißt, ist variabel. Hier darum der Zugriff über die METHODE size(). Auch wenn meist vernachlässigbar, ist der wiederholte Aufruf der Methode ineffizienter als einmal aufrufen, in Variable speichern und dann auslesen.

[QUOTE=reno]eine for Schleife durchläuft die Elemente eines Arrays:

for (int element = 0; element < elementsArray.length; element++) {
    // Tue etwas
}```Welche Schreibweise ist besser?[/QUOTE]Diese:```String[] elementsArray = { "acsm", "al5001" };
for (String element :elementsArray) {
   System.out.println(element);
}```Die "alte" Schreibweise solltest Du nur nutzen, wenn Du die Indexvariable selbst auswerten musst (beispelsweise um festzustellen, ob Du gerade den ersten/letzten Eintrag hast, was aber ehr selten der Fall ist...).

bye
TT

@Timothy_Truckle :

Er hat nach einer for-schleife, nicht nach einer foreach-schleife gefragt.

@TO: Zählvariable sollten nicht unnötig lange namen haben, weil sie tatsächlich nur in der Schleife existieren. Einfaches ‘i’ reicht - macht das Ganze auch wieder kürzer.
Ich würde deine erste Variante nehmen, das Andere ist quasi das Gleiche nur umständlicher.

Mit einer foreach-Schleife habe ich auch schon geliebäugelt. Die Indexvariable selbst muss ich zwar nicht auswerten, ich muss aber bei jedem Durchlauf den Zählerstand ausgeben, so dass ich in dem Fall eine zusätzliche Variable benötigen würde. Da hätte ich dann wieder 2 Codezeilen mehr.

zwischen for und for-each kann oft nicht unterschieden werden, letztere oft unbekannt für Neulinge, ein Hinweis darauf lohnt sich immer,
dass das ausgeschlossen ist kann man nicht annehmen

betrifft auch ein wenig die Frage nach der Zähl-Grenze, der intern umgewandelte Code für Arrays ist anscheinend die Variante 1,
http://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.14.2

ansonsten mit der grundsätzlichen Alternative Iteratoren umgesetzt

edit: ein paar Stunden zu spät :wink:

[QUOTE=reno]Mit einer foreach-Schleife habe ich auch schon geliebäugelt. Die Indexvariable selbst muss ich zwar nicht auswerten, ich muss aber bei jedem Durchlauf den Zählerstand ausgeben, so dass ich in dem Fall eine zusätzliche Variable benötigen würde. Da hätte ich dann wieder 2 Codezeilen mehr.[/QUOTE]``` List elementsArray = Arrays.asList(“acsm”, “al5001” );
for (String element :elementsArray) {
System.out.println(element+" index="+elementsArray.indexOf(element));
}


bye
TT

na das ist ein wenig künstlich, in solchen Fällen gehe ich auch auf for-Schleife,

das indexOf() muss nicht nur (O(n^2)) alle Elemente durchgehen, welches schon für Zählung heftig wäre, sondern auch noch lauter equals-Vergleiche,
dazu generell der Overhead durch die Pseudoliste auf das Array,

alles im Normalfall im Nano-Bereich, unerheblich,
aber wenn schon anfangs über eine Variable für length nachgedacht wurde, dann im Vergleich ja gigantische Arbeit :wink:

und bei Doppelten auch noch Mega-Problem,
so, das wars an Superlativen

Um das zu unterstreichen:


import java.util.Arrays;
import java.util.List;

public class SillyLoops {

    public static void main(String[] args) {
        List<String> list = Arrays.asList("eins", "zwei", "eins");

        for (String element : list) {
            System.out.println(element + " index=" + list.indexOf(element));
        }

        System.out.println("---");

        for (int i=0; i<list.size(); ++i) {
            String element = list.get(i);
            System.out.println(element + " i=" + i
                    + " index=" + list.indexOf(element));
        }
    }

}

Ausgabe:

eins index=0
zwei index=1
eins index=0
---
eins i=0 index=0
zwei i=1 index=1
eins i=2 index=0

Aus der Dokumentation von indexOf:

Returns the index of the first occurrence of the specified element in this list, or -1 if this list does not contain the element. More formally, returns the lowest index i such that (o==null ? get(i)==null : o.equals(get(i))), or -1 if there is no such index.

Hab mal irgendwo gelesen, dass “for:each” für Arrays mehr oder weniger das dümmste ist, was man machen kann weil:

  1. Das Array wird intern in ein Iterable umgewandelt.
  2. Der Indexzähler ist (wie gesagt) in der Schleife nicht vorhanden und bevor man dafür wieder einen Zähler hinzufügt (wenn man ihn braucht), ist man mit der normalen for-Schleife bereits wieder besser bedient.

Selbst wenn das so ist, ist es auf keinen Fall das dümmste, weil foreach einfach besser lesbar ist. Und wenn 2. nicht zutrifft, gibt es keine Rechtfertigung für die Zählvariable.

Foreach wurde meines Wissens nach sogar für Arrays gabaut. Wie das in Java ist, weiß ich nicht, in C# bietet sich das an und ist für Arrays besser (die Syntax ist auch anders, als bei Java).
Für mich ist ne for-schleife eh nur ne Schleife zum runter/hochzählen. Bei irgendwelchen Aktionen würde ich while nehmen - ne persönliche Macke von mir.