ArrayList<String> --> double[] array

lubi27X

Aktives Mitglied
Guten Tag, wie kann ich eine String Liste in ein double Array konvertieren?

Ich habe eine Datei mit Zahlen angelegt, welches eingelesen wird. Anschließend soll diese String Liste in ein double array konvertiert werden. Später soll halt eine Exception abgefangen werden, falls in der Datei mal in einer Zeile keine Zahl sondern ein String steht.
In Zeile 17 bin ich nun dabei, diese String Liste in ein double Array zu konvertieren.
Java:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.Scanner;

public class main {

    public static void main(String[] args) {

        try
        {
            String filename = "C:\\Users\\Admin\\eclipse-workspace\\Übung_8_Aufgabe_3\\Zahlen";
            List<String> lines = Files.readAllLines(Paths.get(filename));
            double[] array = lines.toArray(new Double[lines.size()]);
            System.out.println(lines);
            
        }
        catch (IOException e)
        {
            System.out.println("");
        }
        
    }

}
 
Java:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;

public class main {

    public static void main(String[] args) {

        try
        {
            String filename = "C:\\Users\\Admin\\eclipse-workspace\\Übung_8_Aufgabe_3\\Zahlen";
            List<String> lines = Files.readAllLines(Paths.get(filename));
            
            double[] array = new double[lines.size()];
            
            for (int i = 0; i < lines.size(); i++)
            {
                array[i] = Double.parseDouble(lines.get(i));
            }
            System.out.println(Arrays.toString(array));
            
        }
        catch (IOException e)
        {
            System.out.println("");
        }
        
    }

}

Habe da jetzt so gemacht.
 
sieht grundlegend nicht schlecht aus ... aber:
Java:
array[i] = Double.parseDouble(lines.get(i));
Überleg mal genau, was die Zeile macht (besser: versucht zu machen) !!

'get' holt die i-te Zeile der Liste, mithin einen String!
Und dieser String soll jetzt in einen double-Werte gewandelt werden??

Was willst Du denn mit dem Code überhaupt ereichen?
VG Klaus
 
Ja, der Ansatz ist goldrichtig und so wird es gelöst.

Wenn es um "elegantere" Lösungen geht, dann würde ich ab Java 8 zu Streams greifen - dann wird daraus ein 1-Zeiler (geschrieben auf 3 Zeilen).

Überleg mal genau, was die Zeile macht (besser: versucht zu machen) !!
Was übersehe ich da? Es ist ein einfaches parsen eines Wertes. Er geht davon aus, dass die Datei korrekt ist und nur gültige double Werte enthält.
 
Vielleicht erstmal zu meinem Ziel. Ich will die Zeilen einer Datei einlesen . Die Datei habe ich einfach Zeile für Zeile mit Zahlen gefüttert.
Java:
1.0
2.8
3
4.8

Die Zahlen sollen eingelesen werden und in ein double Array konvertiert werden.
Jetzt soll ich aber auf Ausnahmen reagieren. Steht in einer Zeille der Datei keine Zahl, sondern ein String, soll es zu keiner Fehlermeldung kommen, sondern die "fehlerhafte" Zeile ignoriert und auf der Konsole ausgegeben werden. So viel dazu.

Jetzt starte ich erstmal damit, meine String Liste in einem double Array zu konvertieren.

Überleg mal genau, was die Zeile macht (besser: versucht zu machen) !!

'get' holt die i-te Zeile der Liste, mithin einen String!
Und dieser String soll jetzt in einen double-Werte gewandelt werden??
Ich weiß nicht so recht was du meinst? Mein Code funktioniert doch.
Java:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;

public class main {

    public static void main(String[] args) {

        try
        {
            String filename = "C:\\Users\\Admin\\eclipse-workspace\\Übung_8_Aufgabe_3\\Zahlen";
            List<String> lines = Files.readAllLines(Paths.get(filename));    //Hier ggf. IOException
            
            double[] array = new double[lines.size()];
            
            for (int i = 0; i < lines.size(); i++)
            {
                array[i] = Double.parseDouble(lines.get(i));    //Hier ggf. NullPointerException oder NumberFormatException
            }
            System.out.println(Arrays.toString(array));
            
        }
        catch (IOException e)
        {
            System.out.println("hansgustav");
        }
        catch (NumberFormatException g)
        {
            System.out.println("Zeile ist keine Zahl");
        }
    }
}

In Zeile 34 reagiere ich auf NumFormatExceptions, sprich falls in der Datei anstatt einer Zahl "Hans" steht, fängt mein Code die NumberFormatException und gibt "Zeile ist keine Zahl aus".

Jetzt muss ich es nur noch schaffen, dass die fehlerhafte Zeile ausgegeben wird.
 
Jetzt möchte ich den Code gerne noch etwas verbesser und zwar soll er leere Zeilen nicht mitzählen.. Wie macht man das am Besten? Würde mich nur über paar Tipps freuen, damit ich das selbst umsetzen kann.
Jetzt habe ich mal in meiner Datei noch paar leere Zeilen hinzugefügt, doch irgendwie sieht das hässlich aus.. Wenn eine Zeile in meiner Datei leer ist, soll er die nicht an das double array hängen.

1617286121525.png
 
Willst Du denn bei Zeilen, die nicht auswertbar sind, ein 0.0 stehen haben?

Wenn Du nur die Werte selbst haben willst, dann solltest Du Dir überlegen, ob Du nicht auf eine List umsteigen willst (Oder ein anderen Typ, der eine dynamische Größe hat...)

Und dann kannst Du in der for Schleife einfach hin gehen und abprüfen, ob der Wert ausgewertet werden soll oder nicht. Wenn nicht, dann machst Du einfach ein break; oder so.

Ggf. willst Du Dir auch einmal Streams absehen. Dann wird es aus meiner Sicht deutlich einfacher.
Files.lines gibt dir ein Strem<String>.
Dann kannst Du mit Filter ausfiltern, was Du nicht haben willst.
Die Umwandlung kann über ein mapToDouble erfolgen (Wegen der ParseException ggf. eine eigene Methode schreiben, die da dann als Methodenreferenz angegeben wird. Statt einer Exception wird dann NaN zurück gegeben.
NaN kannst Du dann noch heraus filtern ...
Am Ende Ergebnis einsammeln und fertig ...

Das einfach einmal so ohne es im Detail zu durchdenken als eine mögliche Idee...
 
Das ist meine Datei mit den Zahlen. Wie man sehen kann, steht in Zeile 10 bis 12 nichts. Genau diese Zeilen sollen nicht eingelesen werden.
1617287696281.png

In meiner for schleife muss also irgendwie eine Abfrage rein, die prüft, ob eine Zeile leer ist.
 
Wie geschrieben: einfaches if um dann ein break (Dann wird die Schleife ganz verlassen) oder continue (dann geht es mit dem nächsten Wert weiter) löst das.
 
In meiner for schleife muss irgendwie eine Abfrage rein, die prüft, ob eine Zeile leer ist.
Das ist der einfachste Teil:
Java:
String zeile = lines.get(i);
if (zeile.isEmpty()) {
  //
} else {
  array[i] = Double.parseDouble(zeile);
}
Dein Problem ist dann vielmehr, dass dein Array so groß ist, wie die Datei Zeilen hat. Du wirst also dennoch an irgendwelchen Stellen 0.0 stehen haben. Um das zu verhindern, musst du mehr tun, als nach leeren Zeilen zu fragen.
 
Was auch gar nicht gut ist, dass hier der Programmablauf per Exception gesteuert wird.
Wobei mir die Alternative nicht besser gefällt.
Zeigt ja den regulären Ausdruck / Code, der es prüfen soll ... wenn es statt in der Doku in einer Methode zu finden wäre ... oder es ein tryParseDouble oder so geben würde, das z.B. ein Optional zurück geben würde ...

Das ist somit durchaus ein Fall, denn ich so mal nicht anmeckern würde ....
 
Java:
        try
        {
            String filename = "C:\\Users\\Admin\\eclipse-workspace\\Übung_8_Aufgabe_3\\Zahlen";
            List<String> lines = Files.readAllLines(Paths.get(filename));    //Hier ggf. IOException
            
                double[] array = new double[lines.size()];
            
            
                
                for (int i = 0; i < lines.size(); i++)
                {
                    try
                    {
                        if (lines.get(i).isEmpty())
                        {
                            continue;
                        }
                        else
                        {
                            array[i] = Double.parseDouble(lines.get(i));    //Hier ggf. NullPointerException oder NumberFormatException
                        }
                    }
                    catch (NumberFormatException g)
                    {
                        System.err.println("In Zeile: " + (i + 1) +" steht keine Zahl: " +lines.get(i));
                    }
                }
//                System.out.println(Arrays.toString(array));
        }
        catch (IOException e)
        {
            System.out.println("hansgustav");
        }
    }
}

Müsste doch eigentlich so funktionieren..Falls die Zeile leer ist, geht es mit den nächsten Wert weiter.
komischerweise geht es nicht
 
Naja, die Alternative gibt es ja und die kommt mit Leerzeilen, Kommentarzeilen, Währungsangaben usw. klar:

Java:
        final File file = new File("data.txt");
        final ArrayList<Double> list = new ArrayList<>();
        try (Scanner scanner = new Scanner(file)) {
            scanner.useLocale(Locale.US);

            double nextDouble;
            // loop for the whole scanner
            while (scanner.hasNext()) {
                // if the next is a double, print found and the double
                if (scanner.hasNextDouble()) {
                    nextDouble = scanner.nextDouble();
                    System.out.println("Found: " + nextDouble);
                    list.add(nextDouble);
                 } else {
                     // if a double is not found, print "Not Found" and the token
                     System.out.println("Not Found: " + scanner.next());
                }
            }

        }
       System.err.println("Result: " + list);

Im Allgemeinen ist die Verwendung von Ausnahmen für den Kontrollfluss ein Anti-Pattern.
Als kurze Zusammenfassung, warum es generell ein Anti-Pattern ist:
  • Exceptions sind im Grunde genommen ausgeklügelte GOTO-Anweisungen
  • Die Programmierung mit Exceptions führt daher zu schwieriger zu lesendem und verständlichem Code
  • Die meisten Sprachen haben bereits Kontrollstrukturen, die Probleme ohne die Verwendung von Ausnahmen lösen können
  • Argumente für die Effizienz sind für moderne Compiler, die dazu neigen, unter der Annahme zu optimieren, dass Ausnahmen nicht für den Kontrollfluss verwendet werden, hinfällig.
 
komischerweise geht es nicht
Was genau geht nicht? Was ist das Verhalten, das Du siehst und was ist das Verhalten, das Du erwartest?

Generell ist es doppelt gemoppelt. Da Du noch einen else Zweig hast, brauchst Du kein continue. Somit wäre der Block beim if leer und den kann man dann weglassen durch umdrehen der Bedingung:

Java:
                        if (!lines.get(i).isEmpty()) {
                            array[i] = Double.parseDouble(lines.get(i));    //Hier ggf. NullPointerException oder NumberFormatException
                        }

Die Idee mit dem continue / break ist, auf einen else Zweig zu verzichten. Du hast also sozusagen das Pattern:
Java:
Schleife {
    if (tolleBedingung) continue;
    
    // Mach hier irgendwas
}

Schleife kann irgend eine Schleife sein (for, while) und tolleBedingung halt irgend eine Bedingung, die erfüllt sein muss ...
Hintergrund für sowas ist, dass man die Einrücktiefe nicht unnötig hoch haben möchte. Beim ersten hast du für die Tätigkeit einfach eine Ebene mehr als bei der anderen Lösung. Und dieses Pattern ist zumindest in meinem Umfeld "üblich", aber halt weniger bei Schleifen sondern bei Methoden. Eine Methode hat in der Regel immer den Aufbau:
1. Validierungsblock - hier werden Parameter und Zustand der Instanz verifiziert, ggf. eine Exception geworfen oder bei speziellen Werten, direkt eine Antwort gegeben.
2. Berechnungs- / Aktionsblock - die eigentliche Tätigkeit der Methode.
3. Rückgabe - in der Regel einfach ein return.
Das ist natürlich nix festgelegtes, aber darauf läuft es meistens hinaus ...
 

Neue Themen


Zurück
Oben