Java-Tutorials. Vor langer Zeit mal von mir angekündigt. Dann kam zu diesem Thema wieder nichts. Habe mir bisher einfach nicht die Zeit nehmen können, mir etwas zu überlegen, was gut in diese Rubrik passen könnte. Heute möchte ich aber zumindest mit einem sehr kleinen und recht simplen Beitrag beginnen, und wer weiß, vielleicht geht es danach ja sogar weiter. Je nachdem.
Kürzlich stand ich vor einem kleinen Problem, als ich in der Situation war, Daten über Lizenzen aus einem SAP-System auszulesen. Die Information lag in Form einer Tabelle als Vector<Vector<String>> vor. Aus diesem habe ich die benötigten Spalten in zwei String-Arrays rausgeschrieben: Lizenzkennzeichnung und das Gültigkeitsdatum. Diese Einträge sollten dann nach der Datums-Spalte sortiert werden. In diesem Augenblick fiel mir auf, dass ich keine spontane Idee hatte, wie ich zwei Arrays in Abhängigkeit voneinander sortieren sollte, also zwei Spalten gleichzeitig.
Eine Lösung des Problems ist mir dann aber nach kurzem Grübeln eingefallen: Eine passende Datenstruktur musste her, die ihre eigenen Sortierkriterien mitbringt:
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 |
; html-script: false ]class LicenseEntry { private static final String DELIMITER_CHARACTER = ":"; private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); String identifier; GregorianCalendar expirationDate; public LicenseEntry(String identifierString, String expirationDateString){ this.identifier = identifierString; this.expirationDate = (GregorianCalendar) stringAsCalendar(expirationDateString); } static Comparator<LicenseEntry> licenseComparator = new Comparator<LicenseEntry>(){ @Override public int compare(LicenseEntry license1, LicenseEntry license2) { return license2.expirationDate.compareTo(license1.expirationDate); } }; public Calendar stringAsCalendar(String dateString){ GregorianCalendar resultCalendar = new GregorianCalendar(); try { resultCalendar.setTime(dateFormat.parse(dateString)); } catch (ParseException parseException){ return new GregorianCalendar(); } return resultCalendar; } public String calendarAsString(Calendar calendar){ return dateFormat.format(calendar.getTime()); } @Override public String toString(){ return this.identifier + DELIMITER_CHARACTER + calendarAsString(this.expirationDate) + "\n"; } } |
Anschließend wollte ich einfach ein Array dieser Datenstruktur erzeugen und auf diesem toString() aufrufen, damit dann rekursiv alle toString()-Methoden seiner Elemente aufgerufen werden. Ach wie doof. So funktioniert das ja gar nicht. Kurzerhand habe ich mir also etwas ausgedacht, das toString() überschreibt, wie ich das gerne hätte:
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 |
; html-script: false ]final int resultTableSize = resultTable.size(); String licenseEntryArrayString = new Object(){ LicenseEntry[] licenses = new LicenseEntry[resultTableSize]; { int licenseIndex = 0; for(Vector<String> currentRow : resultTable){ licenses[licenseIndex] = new LicenseEntry(currentRow.get(LICENSE_IDENTIFIER_COLUMN), currentRow.get(LICENSE_EXPIRATIONDATE_COLUMN)); licenseIndex++; } Arrays.sort(licenses, LicenseEntry.licenseComparator); } @Override public String toString(){ String resultString = ""; for(LicenseEntry currentLicenseEntry : licenses){ resultString += currentLicenseEntry.toString(); } return resultString; } }.toString(); |
Ich bin mir zwar relativ sicher, dass hier einige Java-Profis und Design-Pattern-Götter die Hände über dem Kopf zusammenschlagen werden, aber ich glaube ganz so unbrauchbar ist das eigentlich nicht. Und fragt mich schon gar nicht wieso ich da eine anonyme Klasse genommen habe. Vielleicht war ich einfach in der Stimmung dafür. Ich hoffe der Code ist selbsterklärend genug. Das meiste ist sowieso zu speziell, wichtig ist allein die Struktur.
Irgendwie bin ich mir grad nicht sicher ob ich dein erstes Problem richtig verstanden habe.
Also du bekommst Strings und dazugehörige Dates und willst dann nach Datum sortieren?
reicht dann nicht schon folgendes?
SortedMap map = new TreeMap();
map.put(new Date(), "Eins");
map.put(new Date(1234463454), "Zwei");
map.put(new Date(123), "Drei");
for (Date date: map.keySet()) {
System.out.println(date.toString() + " " + map.get(date));
}
ausgabe:
Thu Jan 01 01:00:00 CET 1970 Drei
Thu Jan 15 07:54:23 CET 1970 Zwei
Thu Jan 19 22:36:00 CET 2012 Eins
Jo, du hast das Problem im Prinzip richtig verstanden, bis auf die Tatsache, dass ich jeweils zwei Strings bekomme, von denen einer ein Datum repräsentiert. Nach diesem Feld soll sortiert werden – absteigend in meinem Fall. Dieser Teil des Codes fehlt bei dir: das Sortierkriterium.
Außerdem ist dein Code ja auch nur deshalb so simpel, weil es zufällig genau zwei Spalten sind – ein Key und ein dazugehöriger Wert. Wenn es jetzt drei Spalten oder mehr wären, dann müsste man da doch auch wieder irgendeine Struktur konstruieren, die dann als Wert verwendet wird.
Aber SortedMaps hätte ich mir vielleicht doch mal anschauen sollen. Warum einfach wenn es auch kompliziert geht ;)
War eben die erste Lösung, die mir eingefallen ist, ohne auf Collections zuzugreifen.
Schaut so aus als würden meine Java-Tutorials in Zukunft wieder seltener werden :D
Och nö, warum denn wieder seltener? Das war nun nicht meine Absicht. :(
Hat ja nicht direkt mit dir zu tun. Wie schon erwähnt, mir fällt für die Rubrik sowieso nichts ein. Was ich täglich so produziere ist ja nun keine Zauberei. Und wenn mal was dabei rauskommt, dann scheint es unnötig komplex zu sein. Ich muss mir da nochmal Gedanken drüber machen.
Dachte eine Diskussion darüber wäre für alle beteiligten was gutes. Die Leser können sich was abgucken, du kannst evtl. von den Kommentatoren etwas lernen und die Leser lernen evtl. noch mehr. ;-)
Kommentare im Code wären aber auch nicht verkehrt, Anfänger werden wohl generell Probleme damit haben auch einfachen Code zu lesen, und ich muss zugeben, ich tu mir immer schwer mit inneren Klassen und versteh im Detail deswegen nur die Hälfte. :(
Jo klar, Diskussionen sind immer gut. Ich bin dir auch dankbar für deinen Vorschlag. Ich hab trotzdem keine Ahnung, was ich als nächstes posten könnte ;)
Kommentare mache ich normalerweise schon, aber nie über einzelne Zeilen, sondern nur über komplette Codeblöcke. In diesem Fall sind die Codeschnipsel ja nicht besonders lang und ich habe ja schon im Text kurz angerissen, was der Teil machen soll, daher habe ich sie für überflüssig gehalten.