1. Raum und Zeit
In fast allen Aufgaben haben wir Bildschirmausgaben, und wer im Alltag zum Beispiel deutsch, chinesisch, spanisch oder arabisch schreibt, wird Programmausgaben vermutlich auch in dieser Sprache wünschen. Doch an einigen Stellen taucht dann immer eine »falsche« Ausgabe auf, etwa wenn Nachkommastellen bei Fließkommazahlen nicht mit Komma, sondern mit einem Punkt getrennt sind. Das Dezimaltrennzeichen ist nur eines von vielen Beispielen, wie unterschiedlich die Normen in den Ländern sind: Währungen stehen manches Mal vor und dann wieder hinter der Zahl, bei Datumsangaben lautet bei einigen Ländern das Format Jahr-Monat-Tag, bei anderen Tag-Monat-Jahr, dann wieder Monat-Tag-Jahr.
Dieses Kapitel rückt Aufgaben um Internationalisierung (wie man Programme prinzipiell sprachunabhängig macht) und Lokalisierung (Anpassung an eine konkrete Sprache) in den Mittelpunkt. Denn wenn unsere Software erfolgreich sein soll, muss sie natürlich weltweit zu jeder Tageszeit überall auf unserem Planeten laufen. Java kann problemlos viele sprachliche Besonderheiten berücksichtigen, und das wollen wir uns in den Aufgaben anschauen, sodass auch Captain CiaoCiao und Bonny Brain ihre Geschäfte überall tätigen können und jeder ihre »Sprache« versteht.
Voraussetzungen
Locale
-Klasse kennen und Konstanten, wieLocale.GERMANY
Notwendigkeit für landestypische Formatierung erkennen können
temporale Datentypen
LocalDate
,LocalDateTime
,Duration
kennen
Verwendete Datentypen in diesem Kapitel:
Noch mehr Aufgaben findest du im Buch: ›Captain CiaoCiao erobert Java: Das Trainingsbuch für besseres Java. 300 Java-Workshops, Aufgaben und Übungen mit kommentierten Lösungen‹
1.1. Sprachen und Länder
Damit die Java-Bibliothek Fließkommazahlen und Datum parsen und formatieren sowie Texte übersetzen kann, existiert der Datentyp Locale
, der eine Sprache mit einer optionalen Region repräsentiert. Wir wollen mit diesem Datentyp einige Aufgaben lösen, die gut zeigen, an welcher Stelle Locale
überall vorkommt.
1.1.1. Landes-/Sprachtypische Formatierungen für Zufallszahl anwenden ⭐
Bonny Brain bereitet einen neuen E-Mail-Scam vor: Bitcoins sollen deutlich unter dem Preis »verkauft« werden. Sie bereitet dafür die Betreffzeilen vor, die zum Beispiel so aussehen
Buy 𝑩𝒊𝒕𝒄𝒐𝒊𝒏 for just $11,937.70 💰
Natürlich plant die Crew einen weltweiten Betrug, und da ist es wichtig, die Zahl nach den Regeln der verschiedenen Länder zu formatieren.
Die printf(…)
-Methode ist überladen, so wie es auch String.format(…)
ist:
Mit
Locale
als erstem Parameter.Ohne
Locale
. Wird keinLocale
-Objekt übergeben, gilt die Default-Locale. Das führt dazu, dass die Java Virtual Machine unter einem deutschsprachigen Betriebssystem, diese Sprache übernimmt und bei der Ausgabe mitSystem.out.printf(…)
und einer Fließkommazahl standardmäßig ein Komma als Dezimaltrenner verwendet. Hat man ein englischsprachiges Betriebssystem, wird standardmäßig der Punkt als Trennzeichen verwendet, weil eben im englischsprachigen Raum Nachkommastellen mit einem Punkt abgetrennt werden.
Aufgabe:
Erzeuge eine Zufallszahl vom Typ
double
zwischen 10 000 (inklusive) und 12 000 (exklusive); Nachkommastellen sind erwünscht.Nutze die Methode
String.format(String format, Object... args)
, um eine Fließkommazahl mit zwei Nachkommastellen zu formatieren. Es soll ein Tausendertrennzeichen geben.Erfrage alle
Locale
-Objekte des Systems, und nutze sie als Argument für dieString.format(Locale l, String format, Object... args)
-Methode, sodass die Fließkommazahl jeweils »lokal« formatiert wird. Gib den String aus.
Im Allgemeinen kann man festhalten, dass alle Methoden, die eine sprachabhängige Formatierung realisieren, oder Strings parsen, üblicherweise ein |
1.2. Datum und Zeit-Klassen
Auf den ersten Blick sieht es so aus, als ob das Datum nur aus Jahr, Monat und Tag besteht. Allerdings erwartet man von einer API, dass sie noch mehr Fragen beantworten kann: Ist ein Tag ein Mittwoch? Wenn am 27. Februar eine Party drei Tage geht, wann endet sie? Wann fängt die KW 12 an? Wenn ich am 31. Dezember 2021 um 09:30 in Deutschland losfliege und nach 11 Stunden in Miami ankomme, wie spät ist es dann dort?
Die Java-Bibliothek hat sich im Laufe der Jahre immer weiterentwickelt, und so gibt es auch für die Datum- und Zeitrechnung diverse Typen:
java.util.Date
seit Java 1.0java.util.Calendar
,java.util.GregorianCalendar
,java.util.TimeZone
seit Java 1.1Paket
java.time
seit Java 8 mit Klassen wieLocalDate
,LocalTime
,LocalDateTime
,Duration
Für ein Datum mit Zeitanteil gibt es gleich drei Möglichkeiten; allerdings sind Date
und Calendar
seit Java 8 nicht mehr angesagt, denn sie bringen eine Reihe von Problemen mit sich. Die Datentypen finden sich jedoch immer noch in vielen Beispielen, insbesondere online. Wir sollten von diesen »alten« Typen Abstand davon nehmen, und daher trainiert dieser Abschnitt ganz gezielt den Umgang mit den aktuellen Datentypen aus java.time
.
1.2.1. Datumsausgabe in verschiedenen Sprachen formatieren ⭐
Am 19. September wird wieder der Sprich-wie-ein-Pirat-Tag (International Talk Like a Pirate Day) gefeiert. Bonny Brain plant ein Fest und bereitet Einladungen vor, und das Datum soll für die Sprachen Locale.CHINESE
, Locale.ITALIAN
und new Locale("th")
formatiert werden; Deutsche schreiben zum Beispiel Tag.Monat.Jahr
, aber wie ist das in den anderen Sprachen?
Aufgabe:
Erzeuge ein
LocalDate
-Objekt für den 19. September:LocalDate now = LocalDate.of( Year.now().getValue(), Month.SEPTEMBER, 19 );
Rufe die
toString()
-Methode auf; wie ist die Ausgabe?Rufe
format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM))
auf demLocalDate
auf; wie die Ausgabe?Es gibt insgesamt vier
FormatStyle
-Stile — probiere alle aus. Welches Muster wird verwendet?Auf dem
DateTimeFormatter
-Objekt kann manwithLocale(Locale)
aufrufen und die Sprache ändern; probiere das für verschiedene Sprachen aus.
1.2.2. An welchem Tag feiert Sir Francis Beaufort Geburtstag? ⭐
Captain CiaoCiao feiert jedes Jahr den Geburtstag von Sir Francis Beaufort, der am 27. Mai 1774 geboren wurde.
Aufgabe:
Gegeben ist ein
LocalDate
mit Francis’ Geburtstag:LocalDate beaufortBday = LocalDate.of( 1774, Month.MAY, 27 );
Entwickle ausgehend von
beaufortBday
ein neuesLocalDate
-Objekt mit dem aktuellen Jahr, wobei das jetzige Jahr nicht hart einkodiert, sondern dynamisch vom System stammen soll.Erzeuge eine Ausgabe, an welchem Wochentag in diesem Jahr Francis Geburtstag feiert. In welcher Form der Wochentag ausgegeben wird, also Zahl oder String oder welche Sprache, ist egal.
Beispiel:
Für das Jahr 2020 könnte die Ausgabe lauten:
WEDNESDAY 3 Mittwoch
1.2.3. Finde alle Freitag der 13. ⭐
Jeden Freitag den 13. fühlt sich Captain CiaoCiao unwohl zu segeln. An solchen Tagen sticht er nicht in See und schickt stattdessen Bravius Gritty.
Aufgabe:
Schreibe ein Programm, das für ein gegebenes Jahr alle Freitage auflistet, die auf den 13. fallen.
Bonus: Schreibe dafür einen
TemporalAdjuster
, der für einTemporal
-Objekt den nächsten Freitag, den 13. liefert.
Beispiele:
Für das Jahr 1925 kann die Ausgabe so aussehen:
1925-02-13 1925-03-13 1925-11-13
Für 2024:
2024-09-13 2024-12-13
1.2.4. Durchschnittliche Dauer der Karaoke-Nächte ermitteln ⭐
Karaoke-Abende mit Rum, Tanz und Gesang sind bei der Crew beliebt. Oft gehen die Feiern bis zum Morgengrauen, und das stört Bonny Brain, weil die Crew dann am nächsten Tag dösig ist.
Um herauszufinden, wie viele Stunden die Exzesse im Schnitt gehen, will Bonny Brain eine Statistik aufstellen. Sie schreibt die Start- und Endzeiten auf und kann später den Durchschnitt berechnen. Auf den Notizblättern steht zum Beispiel: »2022-03-12, 20:20 - 2022-03-12, 23:50«.
Aufgabe:
Schreibe ein Programm, das einen String im oberen Format auswertet, die durchschnittliche Partydauer ermittelt und ausgibt.
Bei dem Programm müssen keine Zeitzonen, Schaltsekunden oder sonstige Sonderfälle berücksichtigt werden — ein Tag kann exakt 24 Stunden lang sein.
Beispiel:
Für den String
2022-03-12, 20:20 - 2022-03-12, 23:50 2022-04-01, 21:30 - 2022-04-02, 01:20
soll die Ausgabe so aussehen:
3 h 40 m
Bei Zeitdifferenzen hilft die Klasse |
1.2.5. Verschiedene Datumsformate parsen ⭐⭐⭐
Ein Datum kann absolut oder relativ spezifiziert werden, und es gibt mehrere Möglichkeiten zur Datumsangabe. Ein paar Beispiele:
2020-10-10 2020-12-2 1/3/1976 1/3/20 tomorrow today yesterday 1 day ago 2234 days ago
Aufgabe:
Schreibe eine Methode
Optional<LocalDate> parseDate(String string)
, die die oben genannten Formate erkennt.Wenn der String in einem der Formate vorliegt, soll die Methode den String parsen, in ein
LocalDate
konvertieren und imOptional
zurückgeben.Konnte kein Format geparst werden, ist die Rückgabe
Optional.empty().
Noch mehr Aufgaben findest du im Buch: ›Captain CiaoCiao erobert Java: Das Trainingsbuch für besseres Java. 300 Java-Workshops, Aufgaben und Übungen mit kommentierten Lösungen‹