# ArrayList Rückgabewerte aus einer Funktion



## MiMa (17. Sep 2017)

Hi,
ich möchte mehrere Datein verarbeiten, die sich auch in Unterverzeichnissen befinden können.
Daher muss ich das ganze dann mit einer rekursiven Funktion realisieren.
Die ganze Verarbeitung der Dateien habe ich dann mitten in die Rekusion gebaut und am Ende wurde das ganze unübersichtlich.
Daher habe ich mir überlegt, zuerst eine Dateiliste erstellen zu lassen, die alle Datensätze rekursiv sammelt und dann nacheinander abarbeitet.
Da ich nicht weiss wie viele Datensätze es sein werden, kann ein Array nicht verwendet werden. Daher habe ich mich entschieden eine ArrayList zu nehmen, an diese Datensätze angehangen werden können.
Meine Funktion "dateiListeMR" benötigt einen String Parameter mit dem Pfad des Quellverzeichnisses. Zurück gegeben wird dann eine ArrayList mit den gesammelten Dateien als File.

```
// erstellt eine Dateiliste mit Rekursiver Verzeichnistiefe
    public ArrayList dateiListeMR(String quellOrdner) {

        //Dateipfad zum Quellverzeichnis erstellen
        File pfad = new File(quellOrdner);

        // File Array mit allen Dateien aus dem QuellVerzeichnis füllen
        File[] normaleDateiListe = pfad.listFiles();
        ArrayList<File> rekursiveDateiListe = new ArrayList<File>();

        // Wenn das Verzeichnis nicht leer ist, dann Inhalt verarbeiten
        if (normaleDateiListe != null) {
            // Wenn die normaleDateiListe nicht leer ist, Einträge verarbeiten
            // for earch Schleife, arbeitet jede Zeile des Arrays ab
            for (File inhaltListe : normaleDateiListe) {
                // Verarbeitet den Inhalt der Dateiliste
                if (inhaltListe.isFile()) {
                    // Wenn der Inhalt eine Datei ist, an die rekursiveDateiListe anhängen
                    rekursiveDateiListe.add(inhaltListe);
                } else {
                    // Wenn ein Verzeichnis, dann Rekursiver Funktionsaufruf
                    dateiListeMR(inhaltListe.toString());
                } // Rekursiver Funktionsaufruf
            } // Verarbeitet den Inhalt der Dateiliste
        } // Wenn die Dateiliste nicht Leer ist

        // Rekursive Dateiliste in der Konsole ausgeben
//       for (int i = 0; i < rekursiveDateiListe.size(); i++)
//       System.out.println(rekursiveDateiListe.get(i));
     
       return rekursiveDateiListe;
    } // dateiListeMR
```
Die Funktion an sich arbeitet korrekt, denn ich erhalte genau 10 Datensätze, die sich in meinen Quellverzeichnis mit Unterverzeichnissen befinden.
Verwendet wird meine Funktion durch diesen Aufruf

```
ArrayList<File> dateiListe = new ArrayList<File>();
        dateiListe = dateiObjekt.dateiListeMR(dateiObjekt.getQuellOrdner());
        System.out.println("Anzahl der Datensätze in der Liste " + dateiListe.size());

        for (int i = 0; i < dateiListe.size(); i++) {
            System.out.println(dateiListe.get(i));
        }
```
Ein Problem scheint in der zurück gegebenen ArrayListe, in dem sich dann anscheinend nur 2 Dateien befinden. Und zwar sind das diese, die im root des Quellverzeichnisses sind.
Es fehlen alle Dateien in den Unterverzeichnissen.
Aber die ArrayList wurde vollständig erstellt. Innerhalb der Funktion wurde die ArrayListe ausgegeben und war mit 10 Datensätzen vollständig.
Nach der Übernahme der ArrayList habe ich die Datensätze nochmal zählen lassen und auch ausgegeben. Es waren dann nur noch 2 Datensätze??

Ich selbst kann den Fehler nicht finden und wäre für Hilfe Dankbar.

Vielen Dank
M


----------



## MiMa (17. Sep 2017)

Habe jetzt die ArrayListe in ein Array umgewanelt und ein paar Konsolenausgaben gemacht.
Anscheinend habe ich ein Problem in der Rekursion?


----------



## tommysenf (17. Sep 2017)

MiMa hat gesagt.:


> } *else* {
> _// Wenn ein Verzeichnis, dann Rekursiver Funktionsaufruf_
> dateiListeMR(inhaltListe.toString());
> } _// Rekursiver Funktionsaufruf_



Hier rufst du zwar die Rekursion auf, aber du verwertest die Rückgabe nicht sondern verwirfst sie...


----------



## looparda (17. Sep 2017)

Du musst Daten, die zwischen den Funktionsaufrufen der Rekursion geteilt werden müssen, über eine gemeinsame Variable teilen. Oder du benutzt statt solch einer Variable geschickt den return-Wert auf dem Call-Stack und bastelst aus diesen Teilstücken die Ergebnisliste.


----------



## MiMa (17. Sep 2017)

Rekursion ist so eine Sache für mich, da muss ich alles mal wieder bis auf das kleinste herunter.
Habe jetzt noch mal einen neuen Versuch gemacht, in der ich alle Dateipfade auf die Konsole ausgebe.
Die rekursive Funktion

```
// Erstellt eine Dateiliste mit einer Rekursiven Verzeichnistiefe
    public static void erstelleDateiListe(File[] dateiListe) throws IOException{
        // Durchlaufen der übergebenen Dateiliste
        for (int i = 0; i < dateiListe.length; i++) {
            // Wenn der Datensatz eine Datei ist, auf die Konsole ausgeben
            if (dateiListe[i].isFile()) {
                System.out.println(dateiListe[i].getCanonicalPath());
            } // if
            else if (dateiListe[i].isDirectory()) {
                // Wenn der Datensatz ein Verzeichnis ist, Inhalt des neu gefundenen
                // Verzeichnisses als Parameter in die rekursive Funktion übergeben
                erstelleDateiListe(dateiListe[i].listFiles());
            } // else-if
        } // Durchlaufen der Dateiliste
    } // erstelleDateiListe
```
Aufruf der Funktion

```
// Erzeugt ein Datei-Objekt und schreibt das QuellVerzeichnis über
        // den Konstruktor direkt in die Instanzvariable quellOrdner
        Datei dateiObjekt = new Datei(pfadQuelle);
       
        // Quellverzeichnis in ein File-Objekt umwandeln
        File quellVerzeichnis = new File(dateiObjekt.getVerzeichnisPfadQuelle());
               
        // Aufruf der Rekursiven Funktion
        Datei.erstelleDateiListe(quellVerzeichnis.listFiles());
```
Das hat jetzt wieder geklappt.
Die Frage ist jetzt wie ich gefundene Dateien in eine Array Liste hinzufügen kann?
Wenn ich jetzt bei der Funktion zusätzlich den Parameter für ein ArrayList hinzufüge und die sich selbst aufruft, wird dann immer die gleiche ArrayList mitgeführt?
Wird dort tatsächlich mit der .add Funktion addiert?


----------



## looparda (17. Sep 2017)

MiMa hat gesagt.:


> Wenn ich jetzt bei der Funktion zusätzlich den Parameter für ein ArrayList hinzufüge und die sich selbst aufruft, wird dann immer die gleiche ArrayList mitgeführt?


Richtig. Das ist die gemeinsame Variable, die ich erwähnt habe.


MiMa hat gesagt.:


> Die Frage ist jetzt wie ich gefundene Dateien in eine Array Liste hinzufügen kann?





MiMa hat gesagt.:


> Wird dort tatsächlich mit der .add Funktion addiert?


Genau, du fügst mit add(T elem); zur Liste hinzu.


----------



## MiMa (17. Sep 2017)

Die Funktion sieht mittlerweile so aus

```
// Erstellt eine Dateiliste mit einer Rekursiven Verzeichnistiefe
    public static void erstelleDateiListe(File[] dateiListe,
            ArrayList<File> sammelListe) throws IOException{
        // Durchlaufen der übergebenen Dateiliste
        for (int eintrag = 0; eintrag < dateiListe.length; eintrag++) {
            // Wenn der Datensatz eine Datei ist, auf die Konsole ausgeben
            if (dateiListe[eintrag].isFile()) {
                System.out.println(dateiListe[eintrag].getCanonicalPath());
                sammelListe.add(dateiListe[eintrag]);
            } // if
            else if (dateiListe[eintrag].isDirectory()) {
                // Wenn der Datensatz ein Verzeichnis ist, Inhalt des neu gefundenen
                // Verzeichnisses als Parameter in die rekursive Funktion übergeben
                erstelleDateiListe(dateiListe[eintrag].listFiles(), sammelListe);
            } // else-if
        } // Durchlaufen der Dateiliste
    } // erstelleDateiListe
```
Es funktioniert die Anzahl der Einträge kann ich nun auch ausserhalb der Funktion abrufen. 
Die Anzahl der Einträge stimmt.
Vielen Dank für die Hilfe.
MiMa


----------



## looparda (17. Sep 2017)

Deine sammelListe ist an die Instanz gebunden. Die Funktion erstelleDateiListe ist aber static. Du kannst aus dem statischen Kontext auf keine Instanzvariablen zugreifen, weil du von Natur von static aus keinen this-Pointer hast.
dateiListe ist ein Array. Arrays kannst du nur per index auslesen. dateiListe[0], dateiListe[1] ... dateiListe[n]. Du könntest über das array iterieren und eintrag für eintrag der Liste hinzufügen oder aber das array in eine Liste überführen, weil List<E> folgende Funktionen bietet:
boolean add(E e)
void add(int index, E element)
*boolean addAll(Collection<? extends E> c)*
boolean addAll(int index, Collection<? extends E> c)


----------



## tommysenf (17. Sep 2017)

looparda hat gesagt.:


> Deine sammelListe ist an die Instanz gebunden. Die Funktion erstelleDateiListe ist aber static. Du kannst aus dem statischen Kontext auf keine Instanzvariablen zugreifen, weil du von Natur von static aus keinen this-Pointer hast.


Was in diesem Kontext völliger Unsinn ist, da es sich um einen Parameter handelt.


looparda hat gesagt.:


> dateiListe ist ein Array. Arrays kannst du nur per index auslesen. dateiListe[0], dateiListe[1] ... dateiListe[n]. Du könntest über das array iterieren und eintrag für eintrag der Liste hinzufügen oder aber das array in eine Liste überführen, weil List<E> folgende Funktionen bietet:
> boolean add(E e)
> void add(int index, E element)
> *boolean addAll(Collection<? extends E> c)*
> boolean addAll(int index, Collection<? extends E> c)


Auch hier verstehe ich den Sinn nicht, da auf dateiListe nur lesend zugegriffen wird


----------



## MiMa (17. Sep 2017)

Die Dateiliste habe ich in der Klasse Datei definiert.

```
private ArrayList<File> sammelListe;
```
Ebenfalls habe ich in der Klasse Datei folgenden Konstruktor

```
// Konstruktor für Datei-Objekt mit Angabe des Quellverzeichnises
    public Datei(String verzeichnisPfadQuelle) {
        this.verzeichnisPfadQuelle = verzeichnisPfadQuelle;
        this.sammelListe = new ArrayList();
    }
```
Für das abrufen habe ich Methoden

```
public ArrayList<File> getSammelListe() {
        return sammelListe;
    }

    public void setSammelListe(ArrayList<File> sammelListe) {
        this.sammelListe = sammelListe;
    }
```
Abrufen funktioniert so

```
System.out.println("\nDie Gesammelte Liste enthält " + dateiObjekt.getSammelListe().size() + " Einträge");
```

Das auslesen der einzelnen Inhalte funktioniert auch

```
for (int ausgabe = 0 ; ausgabe < dateiObjekt.getSammelListe().size(); ausgabe++) {
            System.out.println(dateiObjekt.getSammelListe().get(ausgabe));
        }
```


----------



## looparda (17. Sep 2017)

@tommysenf Es traten die Probleme
- Zugriff auf Instanzvaraiablen aus einer static Funktion und
- wie bekomme ich Elemente aus einem Array in eine Liste auf
Was genau hab ich davon jetzt falsch erklärt? Wenn du in Sinnhaftigkeit oder Designaspekten helfen willst mach das doch gern.


----------



## MiMa (17. Sep 2017)

Ich habe in meiner Klasse Datei in den Bauplan eine Instanvariable eingebaut und über den Konstruktor erzeugt. Ich kann damit innerhalb der rekusiven Funktion auf diese zugreifen. 
Nachdem die Rekursive Funktion beendet ist, enhält diese dann alle Ergebnisse, auf die ich zugreifen kann. Zumindest funktioniert das Konstrukt bei mir. Ist das denn falsch?
Ein anderer Gedanke, der mir dann einfällt, den Parameter sammelListe wieder zu entfernen und innerhalb der Funktion  die Sammelliste zu erstellen und alle gesammelten Einträge mit return zurück zu geben. Das hatte ich mit der ersten Version eigentlich vor, was aber nicht geklappt hat. Jeder neue Aufruf der Funktion würde dann immer eine neue sammelListe erzeugen. Ich hätte jetzt keine Ahnung wie ich das realisieren müsste damit ich eine Sammelliste erhalte, die dann zurück gegeben werden könnte.


----------



## Harry Kane (17. Sep 2017)

looparda hat gesagt.:


> Es traten die Probleme
> - Zugriff auf Instanzvaraiablen aus einer static Funktion und
> - wie bekomme ich Elemente aus einem Array in eine Liste auf


Ich kann keine Hinweis darauf finden, dass es in diesem Thread um eines der geschilderten Probleme geht. Ich kann ja noch nicht mal eine Instanzvariable erspähen, und auch keinen Versuch, eine Instanzmethode aus einer Klassenmethode heraus aufzurufen.


----------



## tommysenf (17. Sep 2017)

MiMa hat gesagt.:


> Ein anderer Gedanke, der mir dann einfällt, den Parameter sammelListe wieder zu entfernen und innerhalb der Funktion die Sammelliste zu erstellen und alle gesammelten Einträge mit return zurück zu geben. Das hatte ich mit der ersten Version eigentlich vor, was aber nicht geklappt hat. Jeder neue Aufruf der Funktion würde dann immer eine neue sammelListe erzeugen. Ich hätte jetzt keine Ahnung wie ich das realisieren müsste damit ich eine Sammelliste erhalte, die dann zurück gegeben werden könnte.



Wie ich schon schrieb musst du den Rückgabewert des rekursiven Aufrufs auch beachten. Also statt


```
// Wenn ein Verzeichnis, dann Rekursiver Funktionsaufruf
                    dateiListeMR(inhaltListe.toString());
```

musst du das Ergebnis auch mit in deine aktuelle Ergebnisliste mit aufnehmen:


```
// Wenn ein Verzeichnis, dann Rekursiver Funktionsaufruf
                    rekursiveDateiListe.addAll(dateiListeMR(inhaltListe.toString()));
```


----------



## looparda (18. Sep 2017)

Der Beitrag inkl. Code wurde tatsächlich nachträglich geändert. Ich hätte zitieren sollen.


----------



## MiMa (18. Sep 2017)

Nach etwas Ruhe habe ich eine neue Version der Funktion.
Losgelöst von der Instanvariable mit einer Dateiliste von Typ ArrayList als Rückgabewert.

```
// Erstellt eine Dateiliste mit einer Rekursiven Verzeichnistiefe
    // Gibt eine Dateiliste als Rückgabewert zurück
    public static ArrayList<File> sammleDateiListe(File dateiListe, ArrayList<File> sammelListe) {
        IndexLogger.info("Funktion sammleDateiListe wurde aufgerufen");
        if (dateiListe == null || sammelListe == null) {
            IndexLogger.info("Die übergebene dateiListe, sammelListe ist leer");
            return null;
        } // if
  
        File[] suchListe = dateiListe.listFiles();
        IndexLogger.info("Eine suchListe für neu gefundene Verzeichnisse wurde erstellt");
        for (File eintrag : suchListe) {
            if (eintrag.isDirectory()) {
                IndexLogger.info("Der Eintrag ist ein Verzeichnis, Funktion ruft sich selbst auf");
                sammleDateiListe(eintrag, sammelListe);
            } // if
            else if (eintrag.isFile()){
            sammelListe.add(eintrag);
            IndexLogger.info("Die Datei wurde der sammelListe hinzugefügt");
            } // else-if
        } // for-Schleife
        IndexLogger.info("Die sammelListe wird zurückgegeben");
        return sammelListe;
    } // sammleDateiListe
```
Die Ausgabe auf der Konsole

```
Es wurde 10 Einträge gesammelt
N:\Dateien\datei10.txt
N:\Dateien\datei01.txt
N:\Dateien\02\datei02.txt
N:\Dateien\02\03\datei03.txt
N:\Dateien\02\03\04\datei04.txt
N:\Dateien\02\03\04\05\datei05.txt
N:\Dateien\06\datei06.txt
N:\Dateien\06\07\datei07.txt
N:\Dateien\06\07\08\datei08.txt
N:\Dateien\06\07\08\09\datei09.txt
BUILD SUCCESSFUL (total time: 0 seconds)
```
Das Logfile

```
INFO  rekursion.Datei    Funktion sammleDateiListe wurde aufgerufen
INFO  rekursion.Datei    Eine suchListe wurde erstellt
INFO  rekursion.Datei    Die Datei wurde der sammelListe hinzugefügt
INFO  rekursion.Datei    Die Datei wurde der sammelListe hinzugefügt
INFO  rekursion.Datei    Der Eintrag ist ein Verzeichnis, Funktion ruft sich selbst auf
INFO  rekursion.Datei    Funktion sammleDateiListe wurde aufgerufen
INFO  rekursion.Datei    Eine suchListe wurde erstellt
INFO  rekursion.Datei    Die Datei wurde der sammelListe hinzugefügt
INFO  rekursion.Datei    Der Eintrag ist ein Verzeichnis, Funktion ruft sich selbst auf
INFO  rekursion.Datei    Funktion sammleDateiListe wurde aufgerufen
INFO  rekursion.Datei    Eine suchListe wurde erstellt
INFO  rekursion.Datei    Die Datei wurde der sammelListe hinzugefügt
INFO  rekursion.Datei    Der Eintrag ist ein Verzeichnis, Funktion ruft sich selbst auf
INFO  rekursion.Datei    Funktion sammleDateiListe wurde aufgerufen
INFO  rekursion.Datei    Eine suchListe wurde erstellt
INFO  rekursion.Datei    Die Datei wurde der sammelListe hinzugefügt
INFO  rekursion.Datei    Der Eintrag ist ein Verzeichnis, Funktion ruft sich selbst auf
INFO  rekursion.Datei    Funktion sammleDateiListe wurde aufgerufen
INFO  rekursion.Datei    Eine suchListe wurde erstellt
INFO  rekursion.Datei    Die Datei wurde der sammelListe hinzugefügt
INFO  rekursion.Datei    Die sammelListe wird zurückgegeben
INFO  rekursion.Datei    Die sammelListe wird zurückgegeben
INFO  rekursion.Datei    Die sammelListe wird zurückgegeben
INFO  rekursion.Datei    Die sammelListe wird zurückgegeben
INFO  rekursion.Datei    Der Eintrag ist ein Verzeichnis, Funktion ruft sich selbst auf
INFO  rekursion.Datei    Funktion sammleDateiListe wurde aufgerufen
INFO  rekursion.Datei    Eine suchListe wurde erstellt
INFO  rekursion.Datei    Die Datei wurde der sammelListe hinzugefügt
INFO  rekursion.Datei    Der Eintrag ist ein Verzeichnis, Funktion ruft sich selbst auf
INFO  rekursion.Datei    Funktion sammleDateiListe wurde aufgerufen
INFO  rekursion.Datei    Eine suchListe wurde erstellt
INFO  rekursion.Datei    Die Datei wurde der sammelListe hinzugefügt
INFO  rekursion.Datei    Der Eintrag ist ein Verzeichnis, Funktion ruft sich selbst auf
INFO  rekursion.Datei    Funktion sammleDateiListe wurde aufgerufen
INFO  rekursion.Datei    Eine suchListe wurde erstellt
INFO  rekursion.Datei    Die Datei wurde der sammelListe hinzugefügt
INFO  rekursion.Datei    Der Eintrag ist ein Verzeichnis, Funktion ruft sich selbst auf
INFO  rekursion.Datei    Funktion sammleDateiListe wurde aufgerufen
INFO  rekursion.Datei    Eine suchListe wurde erstellt
INFO  rekursion.Datei    Die Datei wurde der sammelListe hinzugefügt
INFO  rekursion.Datei    Die sammelListe wird zurückgegeben
INFO  rekursion.Datei    Die sammelListe wird zurückgegeben
INFO  rekursion.Datei    Die sammelListe wird zurückgegeben
INFO  rekursion.Datei    Die sammelListe wird zurückgegeben
INFO  rekursion.Datei    Die sammelListe wird zurückgegeben
```
Ich hoffe, das ich es diesmal richtig gemacht habe. 
Das Thema habe ich schon öfters versucht zu verarbeiten.
Danke


----------

