Dauerhaftes Speichern einer Eingabe bei einer ArrayList

LeKon

Mitglied
Gude Community,

ich versuche gerade eine generische Liste zu programmieren, die mir Strings in eine ArrayListe legt und davor abgleicht ob dieser String schon drin ist oder nicht. Jetzt habe ich das "Grundgerüst" (sieht wahrscheinlich nicht gut aus, aber funktioniert so wie ich mir das vorstelle) geschrieben. Aber logischerweise werden meine Eingaben ja nicht gespeichert, sondern nur kurzfristig da angezeigt. Wie genau kriegt man das hin, dass man eine Liste schreibt, die dauerhaft eine eingegebene String speichert?

Java:
import java.util.ArrayList;
import java.util.Scanner; 

public class Listen {
    
    static ArrayList<String> list = new ArrayList<>();
    Scanner scan = new Scanner(System.in);
    
    
    
    public static void main(String[] args) {
       
        
        list.add("test");
        list.add("test1");
        InList();
        
        System.out.println(list);
        
    }
    
    
        public static void InList() {
            Scanner scanner = new Scanner(System.in);
            while (true){
                String s = scanner.next();
               
              if(list.contains(s)==false){
                  list.add(s);
                  
              }
              
              else {
                  System.out.println("Bereits vorhanden)");
              }
              
               
                if(s.equals("stop")) {
                    list.remove("stop");
                    break;
                }
                System.out.println(s);
            }
          
            scanner.close();
        }
    }
 
Gude Community,

ich versuche gerade eine generische Liste zu programmieren, die mir Strings in eine ArrayListe legt und davor abgleicht ob dieser String schon drin ist oder nicht. Jetzt habe ich das "Grundgerüst" (sieht wahrscheinlich nicht gut aus, aber funktioniert so wie ich mir das vorstelle) geschrieben. Aber logischerweise werden meine Eingaben ja nicht gespeichert, sondern nur kurzfristig da angezeigt. Wie genau kriegt man das hin, dass man eine Liste schreibt, die dauerhaft eine eingegebene String speichert?

Java:
import java.util.ArrayList;
import java.util.Scanner;

public class Listen {
   
    static ArrayList<String> list = new ArrayList<>();
    Scanner scan = new Scanner(System.in);
   
   
   
    public static void main(String[] args) {
      
       
        list.add("test");
        list.add("test1");
        InList();
       
        System.out.println(list);
       
    }
   
   
        public static void InList() {
            Scanner scanner = new Scanner(System.in);
            while (true){
                String s = scanner.next();
              
              if(list.contains(s)==false){
                  list.add(s);
                 
              }
             
              else {
                  System.out.println("Bereits vorhanden)");
              }
             
              
                if(s.equals("stop")) {
                    list.remove("stop");
                    break;
                }
                System.out.println(s);
            }
         
            scanner.close();
        }
    }
Ich würde hier das Prüfen auf stop vor dem hinzufügen der Liste machen dann musst du es auch nicht aus der Liste wider entfernen.
 
Der TE wird wohl Anfänger sein der sich mit den Collection noch nicht weit genug beschäftigt hat.
Daher sind solche Hinweise sehr wichtig, denn so hat der TE eine Chance, dazu zu lernen.

Daher:
List: Enthält auch doppelte Einträge und Elemente haben eine Reihenfolge.
Set: Kann keine doppelten Einträge enthalten, Elemente haben keine Reihenfolge.
SortedSet: Keine doppelten Einträge wie beim Set aber Elemente habe eine Ordnung / Reihenfolge.
 
Daher sind solche Hinweise sehr wichtig, denn so hat der TE eine Chance, dazu zu lernen.

Daher:
List: Enthält auch doppelte Einträge und Elemente haben eine Reihenfolge.
Set: Kann keine doppelten Einträge enthalten, Elemente haben keine Reihenfolge.
SortedSet: Keine doppelten Einträge wie beim Set aber Elemente habe eine Ordnung / Reihenfolge.
das musst du mir nicht Erklärten sondern den TE
 
In Zeile 38 prüft du mit if ob stop eingegeben wurde. Wenn du das als erstes in der while nach der Eingabe machst verlässt du ja gleich die Schleife.
Kommst dann gar nicht mehr zum add der Liste.
Kannst also das löschen des stop aus der Liste sparen.
 
Ein paar Anmerkungen abseits deiner Frage:

Wofür ist die Instanzvariable "scan" da, wenn du doch in der main() noch eine Instanz von Scanner erzeugst? Und als Ergänzung dazu: Ein Scanner sollte nicht von dir geschlossen werden, weil du damit auch System.in schließen wirst (was in dem gezeigten Programm keine Auswirkung hat, weil es anschließend beendet wird).

eine generische Liste
Generisch ist die Liste gar nicht, aber vermutlich hast du etwas anderes damit gemeint. 😉

public static void InList()

Namen von Methoden sollen in Java per Konvention immer mit einem Kleinbuchstaben beginnen und ein Verb enthalten. Der Name soll beschreiben, was die Methode tut, insofern wäre als Methodenname isInList() schon in Ordnung, allerdings macht deine Methode noch viel mehr, denn sie nimmt offenbar auch Benutzereingabe entgegen. Die Regel hierzu ist: Ein- und Ausgabe, sollte von der Logik getrennt sein. Deine Methode isInList() sollte demnach ausschließlich prüfen, ob der String bereits in der Liste ist. Die Eingabe sollte einer anderen Methode vorbehalten sein.

if(list.contains(s)==false){

Eine if-Bedingung prüft einen Wahrheitswert (Boolean), also etwas wie if (boolean) {. Das kann ein Vergleich wie n < 10 sein. Dieser Ausdruck liefert als Ergebnis ein boolean, was als Bedingung für if() verwendet werden kann. Die Methode contains() liefert als Ergebnis ebenfalls einen boolean-Wert, der direkt als Bedingung verwendet werden kann, also if (list.contains(s)) {. Der zusätzliche Vergleich auf true wäre überflüssig. Da du wissen möchtest ob der String nicht enthalten ist, brauchst du eine Negation: if (!list.contains(s)) { (das Ausrufezeichen), was ausgesprochen "wenn nicht Liste enthält s" entsprechen würde. Das "== false" ist hier nicht falsch, aber es ist nicht so gut lesbar und Programmierer sind i.d.R. faul und möchten nicht viel schreiben).

Die Prüfung ob "stop" eingegeben wurde kannst du vor dem Einfügen des Wortes machen, dann musst du das Wort nicht wieder aus der Liste entfernen.
 
Am einfachsten ginge das so:
Java:
import java.util.ArrayList;
import java.util.function.Function;

public class Listen {
    public static final ArrayList<String> list = new ArrayList<>() {
        public final Function<String, Boolean> precondition = s -> s != null && !contains(s);
        @Override
        public boolean add(String s) {
            if (precondition.apply(s)) {
                return super.add(s);
            }
            return false;
        }
    };

    public static void main(String[] args) {
        System.out.println(list.add("1"));
        System.out.println(list.add("1"));
        System.out.println(list.add(null));
        System.out.println(list.add("3"));
        System.out.println(list.add("2"));
        System.out.println("list = " + list);
    }
}

Aber das ist nicht gut, weil ich mit .add(0, "..."); zum Beispiel immer noch etwas hinzufügen kann. Deswegen: Die Liste kapseln und eine eigene add Methode hinzufügen.
in welchem universum ist das einfach?
 
Daher sind solche Hinweise sehr wichtig, denn so hat der TE eine Chance, dazu zu lernen.

Daher:
List: Enthält auch doppelte Einträge und Elemente haben eine Reihenfolge.
Set: Kann keine doppelten Einträge enthalten, Elemente haben keine Reihenfolge.
SortedSet: Keine doppelten Einträge wie beim Set aber Elemente habe eine Ordnung / Reihenfolge.
Als Spezialfall noch das LinkedHashSet, keine doppelten Einträge und hat keine Ordnung wie ein SortedSet. Die Elemente behalten aber die Reihenfolge ihres Einfügens in das Set (insertion-order).
 
Java:
import java.util.ArrayList;
import java.util.function.Function;

public class Listen {
    public static final ArrayList<String> list = new ArrayList<>() {
        public final Function<String, Boolean> precondition = s -> s != null && !contains(s);
        @Override
        public boolean add(String s) {
            if (precondition.apply(s)) {
                return super.add(s);
            }
            return false;
        }
    };

    public static void main(String[] args) {
        System.out.println(list.add("1"));
        System.out.println(list.add("1"));
        System.out.println(list.add(null));
        System.out.println(list.add("3"));
        System.out.println(list.add("2"));
        System.out.println("list = " + list);
    }
}
Java:
public class Listen {
    public static final ArrayList<String> list = new ArrayList<>();

    public static void main(String[] args) {
        System.out.println(list.add("1"));
        System.out.println(list.add("1"));
        System.out.println(list.add(null));
        System.out.println(list.add("3"));
        System.out.println(list.add("2"));
        System.out.println("list = " + list);
    }
    public static boolean add(String value){
        if(value != null && !list.contains(value)){
            list.add(value);
            return true;
        }
        return false;
    }
}
was denkst du ist einfacher hmm?

man könnte es noch kürzen auf
if(!list.contains(Object.requiresNonNull(value))
aber da hab ich die syntax nicht im kopf und wäre eher eine verkomplizierung
 
Java:
public class Listen {
    public static final ArrayList<String> list = new ArrayList<>();

    public static void main(String[] args) {
        System.out.println(list.add("1"));
        System.out.println(list.add("1"));
        System.out.println(list.add(null));
        System.out.println(list.add("3"));
        System.out.println(list.add("2"));
        System.out.println("list = " + list);
    }
    public static boolean add(String value){
        if(value != null && !list.contains(value)){
            list.add(value);
            return true;
        }
        return false;
    }
}
was denkst du ist einfacher hmm?

man könnte es noch kürzen auf

aber da hab ich die syntax nicht im kopf und wäre eher eine verkomplizierung
public static boolean add(String value) - wird nie verwendet. Es gibt auch keine Kapselung hier.
 
Aber logischerweise werden meine Eingaben ja nicht gespeichert, sondern nur kurzfristig da angezeigt. Wie genau kriegt man das hin, dass man eine Liste schreibt, die dauerhaft eine eingegebene String speichert?
Java:
import java.io.IOException;
import java.util.Scanner;

public class TestSet {
    private final static String EXIT = "exit";
    private final static Scanner input = new Scanner(System.in);

    public static void main(String[] args) throws IOException {
        PermanentStringSet set = new PermanentStringSet("./data.txt");
        String word = null;
        do {
            System.out.println("'exit' zum Beenden");
            System.out.print("Gib ein Wort ein.> ");
            word = input.next();
            if (!word.equals(EXIT))
                set.add(word);
        } while (!word.equals(EXIT));
        set.saveData();
        System.out.print(set);
    }
}
Java:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;

@SuppressWarnings("serial")
public class PermanentStringSet extends HashSet<String> {
    private String path;

    public PermanentStringSet(String path) {
        super();
        this.path = path;
        readData();
    }

    private void readData() {
        File file = new File(path);
        BufferedReader br;
        if (!file.exists())
            return;
        try {
            br = new BufferedReader(new FileReader(file));
            String word = null;
            while ((word = br.readLine()) != null)
                add(word);
            br.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void saveData() throws IOException {
        FileWriter fw = new FileWriter(new File(path));
        for (String word : this)
            fw.write(word + System.lineSeparator());
        fw.close();
    }

    @Override
    public String toString() {
        return Arrays.toString(toArray(new String[size()]));
    }
}
 
Java:
import java.io.IOException;
import java.util.Scanner;

public class TestSet {
    private final static String EXIT = "exit";
    private final static Scanner input = new Scanner(System.in);

    public static void main(String[] args) throws IOException {
        PermanentStringSet set = new PermanentStringSet("./data.txt");
        String word = null;
        do {
            System.out.println("'exit' zum Beenden");
            System.out.print("Gib ein Wort ein.> ");
            word = input.next();
            if (!word.equals(EXIT))
                set.add(word);
        } while (!word.equals(EXIT));
        set.saveData();
        System.out.print(set);
    }
}
Java:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;

@SuppressWarnings("serial")
public class PermanentStringSet extends HashSet<String> {
    private String path;

    public PermanentStringSet(String path) {
        super();
        this.path = path;
        readData();
    }

    private void readData() {
        File file = new File(path);
        BufferedReader br;
        if (!file.exists())
            return;
        try {
            br = new BufferedReader(new FileReader(file));
            String word = null;
            while ((word = br.readLine()) != null)
                add(word);
            br.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void saveData() throws IOException {
        FileWriter fw = new FileWriter(new File(path));
        for (String word : this)
            fw.write(word + System.lineSeparator());
        fw.close();
    }

    @Override
    public String toString() {
        return Arrays.toString(toArray(new String[size()]));
    }
}
Ich denke die Lösung ist vollkommen in Ordnung. Wenn das Programm gekillt wird, dann wird möglicherweise nie gespeichert. Das Problem hat man aber ggf. immer. Ich persönlich hätte bei einer Liste/Set eher an eine DB-Lösung gedacht, aber wahrscheinlich nur weil ich aus der Ecke Web und Datenbanken komme.
 
Ein paar Anmerkungen abseits deiner Frage:

Wofür ist die Instanzvariable "scan" da, wenn du doch in der main() noch eine Instanz von Scanner erzeugst? Und als Ergänzung dazu: Ein Scanner sollte nicht von dir geschlossen werden, weil du damit auch System.in schließen wirst (was in dem gezeigten Programm keine Auswirkung hat, weil es anschließend beendet wird).


Generisch ist die Liste gar nicht, aber vermutlich hast du etwas anderes damit gemeint. 😉

public static void InList()

Namen von Methoden sollen in Java per Konvention immer mit einem Kleinbuchstaben beginnen und ein Verb enthalten. Der Name soll beschreiben, was die Methode tut, insofern wäre als Methodenname isInList() schon in Ordnung, allerdings macht deine Methode noch viel mehr, denn sie nimmt offenbar auch Benutzereingabe entgegen. Die Regel hierzu ist: Ein- und Ausgabe, sollte von der Logik getrennt sein. Deine Methode isInList() sollte demnach ausschließlich prüfen, ob der String bereits in der Liste ist. Die Eingabe sollte einer anderen Methode vorbehalten sein.

if(list.contains(s)==false){

Eine if-Bedingung prüft einen Wahrheitswert (Boolean), also etwas wie if (boolean) {. Das kann ein Vergleich wie n < 10 sein. Dieser Ausdruck liefert als Ergebnis ein boolean, was als Bedingung für if() verwendet werden kann. Die Methode contains() liefert als Ergebnis ebenfalls einen boolean-Wert, der direkt als Bedingung verwendet werden kann, also if (list.contains(s)) {. Der zusätzliche Vergleich auf true wäre überflüssig. Da du wissen möchtest ob der String nicht enthalten ist, brauchst du eine Negation: if (!list.contains(s)) { (das Ausrufezeichen), was ausgesprochen "wenn nicht Liste enthält s" entsprechen würde. Das "== false" ist hier nicht falsch, aber es ist nicht so gut lesbar und Programmierer sind i.d.R. faul und möchten nicht viel schreiben).

Die Prüfung ob "stop" eingegeben wurde kannst du vor dem Einfügen des Wortes machen, dann musst du das Wort nicht wieder aus der Liste entfernen.
Vieelen Dank für Anmerkungen und die Tipps!
Werde gleich verbesserungen vornehmen.
Die erste Scanner Instanz habe ich vergessen zu entfernen danke😂
 

Zurück
Oben