tutorials.de Buch-Aktion 05/2012
ERLEDIGT
NEIN
ANTWORTEN
8
ZUGRIFFE
1601
EMPFEHLEN
  • An Twitter übertragen
  • An Facebook übertragen
AUF DIESES THEMA
ANTWORTEN
  1. #1
    will2k will2k ist offline Mitglied Silber
    Registriert seit
    Jan 2008
    Beiträge
    58
    Hallo,

    Ich habe folgende GUI:

    Der Benutzer gibt verschiedene Strings ein in eine editierbare JCombobox. Danach drückt er rechts davon den add Button damit der string der JCB geaddet wird. Der Benutzer kann auch in der Liste mit dem delete Button einen Eintrag löschen. Doch das alle ist nebensächlich... Wichtiger ist, dass beim drücken des Save Buttons ALLE String-Elemente in der JComboBox in einer xml datei gespeichert werden in einer List<String>.

    Wenn aber jedesmal alle Strings die sich in der JCB befinden in die xml Datei geschrieben werden. Bekomme ich ja jedesmal redundante Elemente in der xml Datei so:

    Inhalt der JCB:

    String1
    String2
    String3


    Inhalt der xml datei:

    String1
    String2
    String3
    String1
    String2
    String3
    String1
    String2
    String3

    Nun frage ich micht wie ich verhindern kann das jedesmal ALLE Strings aus der JCBox in der xml gespeichert werden...

    1.) Gibt es eine jaxb Annotation z.B. die besagt ein Element in einer Liste darf nur einmal vorkommen?

    oder

    2.)Bevor ich jeden String in der JCB der xml Datei hinzufüge prüfe ich ob der String in der xml schon vorhanden ist. Bei 10 strings in der JCB und existieren 10 strings in der xml datei ergibt das 100 IF prüfungen was net so performant sein dürfte...

    Weiß jemand hier eine vernüftige Lösung ?
     

  2. #2
    Avatar von zeja
    zeja zeja ist offline Mitglied Diamant
    tutorials.de Premium-User
    Registriert seit
    Sep 2006
    Beiträge
    2.962
    Nun die Lösung ist ganz einfach: Nimm ein Set und keine List. In einem Set kann jedes Element nur einmal vorhanden sein.

    Die JAXB Annotationen kannst du so weiter verwenden.
     

  3. #3
    will2k will2k ist offline Mitglied Silber
    Registriert seit
    Jan 2008
    Beiträge
    58
    Zitat Zitat von zeja Beitrag anzeigen
    Nun die Lösung ist ganz einfach: Nimm ein Set und keine List. In einem Set kann jedes Element nur einmal vorhanden sein.

    Die JAXB Annotationen kannst du so weiter verwenden.

    ganz so einfach ists auch net

    und anstatt List liste = new ArrayList() musst ich ne = new HashSet() nehmen und weiteres Problem ergibt sich dadurch:

    Code :
    1
    2
    3
    4
    
    for(int i = 0 ; i < settingsData.getSetMovieFormat().size() ; i++)
            {
                getMovieFormatCB().addItem(settingsData.getSetMovieFormat().get(i));                
            }

    Das HashSet/Set kennt keine get(i); methode, wie lese ich nun die Strings einzeln aus dem Set aus und einzeln in die JComboBox genannt movieFormatCB ? Es gibts zwar eine addAll() methode für die Set doch eine AddAllitem gibts für die JCBox leider nicht.

    Wie könnt ich da jetzt am geschicktesten vorgehen?
    Geändert von will2k (18.05.08 um 15:09 Uhr)
     

  4. #4
    Avatar von zeja
    zeja zeja ist offline Mitglied Diamant
    tutorials.de Premium-User
    Registriert seit
    Sep 2006
    Beiträge
    2.962
    Man sollte über Listen sowieso nicht mit einer normalen for-Schleife zugreifen. Das ist einfach zu langsam.

    Besser ist es einen Iterator zu nehmen:
    Code java:
    1
    2
    3
    4
    5
    6
    
    final Set s = new HashSet();
    //elemente hinzufügen...
    for(final Iterator it = s.iterator(); it.hasNext(); ){
        final String element = it.next();
        System.out.println(element);
    }

    Oder noch einfacher ab Java 1.5:
    Code java:
    1
    2
    3
    4
    5
    
    final Set<String> s = new HashSet<String>();
    //elemente hinzufügen...
    for(final String element : s){
        System.out.println(element);
    }

    Achso noch besser wäre für dich wohl ein TreeSet<String> denn dann sind die Elemente sogar alphabetisch sortiert, was immer ganz gut ist in soner Combobox.
     

  5. #5
    will2k will2k ist offline Mitglied Silber
    Registriert seit
    Jan 2008
    Beiträge
    58
    Code :
    1
    2
    3
    4
    5
    
    SettingsData settingsData = new SettingsData();
                JAXBContext jc = JAXBContext.newInstance(SettingsData.class);           
                Marshaller m = jc.createMarshaller();
                m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);          
                OutputStream os = new FileOutputStream( "test.xml" );


    Code :
    1
    2
    3
    4
    
      for(String  element : this.getMovieFormatCB().toString())
                 {           
                     settingsData.getSetMovieFormat().add(element);          
                 }

    das hier ist code aus der saveXML-Methode. Ich will ja alle strings aus der JCombobox auslesen element für element, doch this.getMovieFormatCB() mag java nicht... alle Strings aus der JCB in ein String-Array lesen und dieses Array mit for zu durchlaufen element für element kanns ja net sein oder?


    Code :
    1
    
        m.marshal(settingsData, os);


    Fehler bei this.getMovieFormatCB().toString() -->

    Code :
    1
    
    Can only iterate over an array or an instance of java.lang.Iterable
     

  6. #6
    Avatar von zeja
    zeja zeja ist offline Mitglied Diamant
    tutorials.de Premium-User
    Registriert seit
    Sep 2006
    Beiträge
    2.962
    Also nochmal zum Verständnis:
    for(String element : list)
    Liest sich als: Für alle String element in list

    Bei der Combobox müßte es heißen:
    Code java:
    1
    2
    3
    4
    
    JComboBox box = new JComboBox();
    for(int i = 0; i < box.getItemCount(); i++){
        Object elem = box.getItemAt(i);
    }

    Hast du noch Probleme damit die API zu verwenden?

    Ich würde dir außerdem statt:
    settingsData.getSetMovieFormat().add(element);
    empfehlen in settingsData direkt eine Methode addMovieFormat vorzustehen. Ist ein wenig schöner.

    Besonders weil man in einem get eigentlich keine Modifizierbare Liste/Set zurückgeben sollte:
    Code java:
    1
    2
    3
    
    public Set getMovieFormats(){
        return Collections.unmodifiableSet(movieFormats);
    }

    Das verhindert daß versehentlich Elemente einfach so hinzugefügt werden können.
     

  7. #7
    Avatar von zerix
    zerix zerix ist offline Hausmeister
    tutorials.de Moderator
    Registriert seit
    May 2005
    Beiträge
    4.335
    @zeja
    Wie sollte man denn auf eine Liste zugreifen? Der Iterator ist langsamer als mit einer normalen for-Schleife.

    Die performanteste Lösung die ich kenne um über eine Liste zu iterieren ist diese
    Code :
    1
    2
    3
    
    for(int i=0, size = list.size(); i<size; i++){
       
    }
    Man sollte auch die Größe der Liste einer Variablen zuordnen, wie hier im Beispiel und nicht
    Code :
    1
    
    for(int i=0; i<list.size(); i++)
    da so bei jedem Schleifendurchlauf die Listengröße neu abgefragt wird.

    Code java:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
     
     
    public class ListIterationPerformance
    {
     
      /**
       * @param args
       */
      public static void main(String[] args)
      {
        List<String> list1 = new ArrayList<String>();
        
        fillList(list1);
        
        long start, stop;
        
        start = System.currentTimeMillis();
        for(String s : list1){
          
        }
        stop = System.currentTimeMillis();
        System.out.println(stop-start);
        
        start = System.currentTimeMillis();
        for(Iterator<String> it = list1.iterator(); it.hasNext();){
          it.next();
        }
        stop = System.currentTimeMillis();
        System.out.println(stop-start);
        
        
        
        start = System.currentTimeMillis();
        for(int i = 0, size = list1.size(); i<size; i++){
          list1.get(i);
        }
        stop = System.currentTimeMillis();
        System.out.println(stop-start);
      }
      
      private static void fillList(List<String> list){
        
        for(int i = 0; i < 1000000; i++){
          list.add("test"+i);
        }
        
      }
     
    }


    78
    62
    16
    Bei einem Set kann man natürlich nur mit einem Iterator auf eine Liste zugreifen. Wobei man die altmodische Variante nehmen sollte und nicht die seit Java 1.5.

    MFG

    Sascha
     
    Es ist schwer Allwissend zu sein. Aber ich komme damit klar. ;-)

  8. #8
    Avatar von zeja
    zeja zeja ist offline Mitglied Diamant
    tutorials.de Premium-User
    Registriert seit
    Sep 2006
    Beiträge
    2.962
    Achja das war wieder die Sache die in Java keinen Sinn macht: Ein Iterator ist langsamer als ein direkter Zugriff. Für mich sollte nen Iterator immer den schnellsten Zugriff bieten...

    Aber einen Fehler hast du gemacht in deinem Performance-Test: Der Iterator ist nur schneller als das for-each weil du die Zuweisung an einen String herausgelassen hast, der ja im for-each gemacht wird.

    Korrekter ist es also so:
    Code java:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    
    package de.tutorials;
     
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
     
    public class ListIterationPerformance {
     
        public static void main(String[] args) {
            List<String> list1 = new ArrayList<String>();
     
            fillList(list1);
     
            long start, stop;
     
            start = System.currentTimeMillis();
            forEachLoop(list1);
            stop = System.currentTimeMillis();
            System.out.println("For each:\t" + (stop - start));
     
            start = System.currentTimeMillis();
            forIteratorLoop(list1);
            stop = System.currentTimeMillis();
            System.out.println("For iterator:\t" + (stop - start));
     
            start = System.currentTimeMillis();
            forSizeLoop(list1);
            stop = System.currentTimeMillis();
            System.out.println("For size:\t" + (stop - start));
        }
     
        private static void forSizeLoop(List<String> list1) {
            for (int i = 0, size = list1.size(); i < size; i++) {
                String s = list1.get(i);
            }
        }
     
        private static void forIteratorLoop(List<String> list1) {
            for (Iterator<String> it = list1.iterator(); it.hasNext();) {
                String s = it.next();
            }
        }
     
        private static void forEachLoop(List<String> list1) {
            for (String s : list1) {
     
            }
        }
     
        private static void fillList(List<String> list) {
            for (int i = 0; i < 1000000; i++) {
                list.add(Integer.toString(i));
            }
        }
     
    }

    Schaut man ins class-File:
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
    // Method descriptor #22 (Ljava/util/List;)V
      // Signature: (Ljava/util/List<Ljava/lang/String;>;)V
      // Stack: 1, Locals: 3
      private static void forIteratorLoop(java.util.List list1);
         0  aload_0[list1]
         1  invokeinterface java.util.List.iterator() : java.util.Iterator [74] [nargs: 1]
         6  astore_1 [it]
         7  goto 20
        10  aload_1 [it]
        11  invokeinterface java.util.Iterator.next() : java.lang.Object [78] [nargs: 1]
        16  checkcast java.lang.String [69]
        19  astore_2
        20  aload_1 [it]
        21  invokeinterface java.util.Iterator.hasNext() : boolean [84] [nargs: 1]
        26  ifne 10
        29  return

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
    // Method descriptor #22 (Ljava/util/List;)V
      // Signature: (Ljava/util/List<Ljava/lang/String;>;)V
      // Stack: 1, Locals: 3
      private static void forEachLoop(java.util.List list1);
         0  aload_0[list1]
         1  invokeinterface java.util.List.iterator() : java.util.Iterator [74] [nargs: 1]
         6  astore_2
         7  goto 20
        10  aload_2
        11  invokeinterface java.util.Iterator.next() : java.lang.Object [78] [nargs: 1]
        16  checkcast java.lang.String [69]
        19  astore_1
        20  aload_2
        21  invokeinterface java.util.Iterator.hasNext() : boolean [84] [nargs: 1]
        26  ifne 10
        29  return

    Sieht man dass der generierte Teil für for-each und for-iterator nun auch (nahezu) gleich sind, so wie es sein sollte.

    Ausgabe:
    Code :
    1
    2
    3
    
    For each:   55
    For iterator:   55
    For size:   19

    So kann man auch schön erkennen warum man keinen Vector nehmen sollte wenn man diesen nicht benötigt:
    Code :
    1
    2
    3
    
    For each:   143
    For iterator:   144
    For size:   72

    also ein gaaanzes Stück langsamer.
     

  9. #9
    Avatar von zerix
    zerix zerix ist offline Hausmeister
    tutorials.de Moderator
    Registriert seit
    May 2005
    Beiträge
    4.335
    Also bei mir sind die Zeiten gleich geblieben.

    Aber das ist ja erstmal egal. Ich wollte nur deutlich machen, dass die Methode ohne Iterator immer noch die schnellste ist.

    MFG

    Sascha

    EDIT:
    Dass intern ein Iterator verwendet wird, weiß ich. Nach nochmal mehrmaligem ausführen, muss ich sagen, dass sich der Iterator schon der for-each-Schleife genähert hat. Aber ich hab ja schon erwähnt worauf ich hinaus wollte.
     
    Es ist schwer Allwissend zu sein. Aber ich komme damit klar. ;-)

Ähnliche Themen

  1. Reflection - Wie kann ich Werte zu einer List<> hinzufügen?
    Von Jacky87 im Forum .NET WPF & Silverlight
    Antworten: 2
    Letzter Beitrag: 18.05.10, 18:24
  2. Einer Zip Datei ein leeres Verz. hinzufügen
    Von DarthShader im Forum Java
    Antworten: 8
    Letzter Beitrag: 24.09.09, 11:31
  3. Probleme mit entfernen von einer Datei
    Von Eddymaniac im Forum Linux & Unix
    Antworten: 2
    Letzter Beitrag: 01.10.06, 20:17
  4. allen feldern einer spalte einen string hinzufügen
    Von megatom im Forum Relationale Datenbanksysteme
    Antworten: 2
    Letzter Beitrag: 23.06.05, 13:07
  5. Antworten: 0
    Letzter Beitrag: 23.03.04, 11:35