Java Videotraining Werbung

Videotraining Spring 3 Boot Werbung

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, wie Locale.GERMANY

  • Notwendigkeit für landestypische Formatierung erkennen können

  • temporale Datentypen LocalDate, LocalDateTime, Duration kennen

Verwendete Datentypen in diesem Kapitel:

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 kein Locale-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 mit System.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.

Apply country language specific formatting for random number

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 die String.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 Locale-Objekt als Parameter akzeptieren. Es kann sein, dass es sprachabhängige Methoden ohne Parameter zusätzlich gibt, doch das sind häufig überladene Methoden, die intern die Standardsprache erfragen, und dann an die Methode mit dem expliziten Locale-Parameter weiterleiten.

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.0

  • java.util.Calendar, java.util.GregorianCalendar, java.util.TimeZone seit Java 1.1

  • Paket java.time seit Java 8 mit Klassen wie LocalDate, 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 dem LocalDate auf; wie die Ausgabe?

  • Es gibt insgesamt vier FormatStyle-Stile — probiere alle aus. Welches Muster wird verwendet?

  • Auf dem DateTimeFormatter-Objekt kann man withLocale(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.

SirFrancisBeaufortBirthday

Aufgabe:

  • Gegeben ist ein LocalDate mit Francis’ Geburtstag:

    LocalDate beaufortBday = LocalDate.of( 1774, Month.MAY, 27 );
  • Entwickle ausgehend von beaufortBday ein neues LocalDate-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 ein Temporal-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 Duration.

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 im Optional zurückgeben.

  • Konnte kein Format geparst werden, ist die Rückgabe Optional.empty().