Java 8 – Date and Time API

Da etwas in die Jahre gekommen, wurde zu java.util.Date und java.util.Calendar mit dem Release von Java 8 eine Alternative geschaffen: LocalDate & LocalTime

Da etwas in die Jahre gekommen, wurde zu java.util.Date und java.util.Calendar mit dem Release von Java 8 eine Alternative geschaffen. Zuhause im Package java.time versucht die neue Lösung sich an benutzerfreundlicheren Factorymethoden, Formatierungslösungen, Threadsicherheit durch Unveränderlichkeit.

LocalDate und LocalTime

Als für den Menschen lesbare Formate sind java.time.LocalDate und java.time.LocalTime vorgesehen (und natürlich die Kombination: java.time.LocalDateTime). Sie bieten übersichtliche Factory Methoden

LocalDateTime now= LocalDateTime.now( ); // Aktuelles Datum LocalDate.of(2013, Month.DECEMBER, 24);
LocalTime.of(12, 00); LocalTime.parse("10:15:30");

und ihre Werte können mittels Getter erfragt werden und bieten Methoden an um neue Instanzen mit anderen Werten zu generieren.

LocalDate theDate = now.toLocalDate(); Month month = timePoint.getMonth();
//Da immutable, immer neue Instanzen erzeugt
LocalDateTime before = now.withYear(2013);
LocalDateTime soon = new.plusWeeks(1);
LocalDateTime wednesday = now.with(TemporalAdjusters.previousOrSame(ChronoUnit.WEDNESDAY));

Instant

Eine andere Darstellung eines Datums ist das java.time.Instant, das die Zeit als Millisekunden seit 01.01.1970 darstellt.

Abschneiden von Werten

Das Beschneiden von Zeiten auf eine Bestimmte Einheit ist nun ebenfalls Teil der neuen API:

LocalTime truncatedTime = now.truncatedTo(ChronoUnit.SECONDS);

Zeitzonen

Zeitzonen können mittels java.time.ZoneId mit berücksichtigt werden. Die ZoneId entspricht dann entweder dem Zeitzonenkürzel (dem Offset von UTC) oder einem Ort der entsprechenden Zeitzone. Damit kann man sich nun Entsprechungen der oben genannten Zeitklassen mit dem Prefix Zoned erzeugen, die somit eindeutig auf den Gebrauch von Zeitzonen hinweisen. z.B. java.time.ZonedDateTime

ZoneId id = ZoneId.of("Europe/Vienna");
ZonedDateTime zoned = ZonedDateTime.of(dateTime, id);

Noch viel mehr

Außerdem bietet die neue Zeit API verschiedene Kalendersysteme, Zeitspannen (Periods, Durations,…) und Formatierungen mittels DateTimeFormatter.

Werft einen Blick rein! http://docs.oracle.com/javase/tutorial/datetime/TOC.html

Ähnliche Artikel:

Java 8 – Stream API

Java 8 bringt auch Neuerungen im Collections Framework. Die Stream API bietet vereinfachungen für die Verarbeitung von Sequenzen und Zähloperationen.

Java 8 bringt auch Neuerungen im Collections Framework. Es wurde mit dem Ziel erweitert eine einfache Paralellisierung durch Bulk Operations zu ermöglichen. Hierfür wurde von den neuen Möglichkeiten der Interfaces gebrauch gemacht: den default Methoden. Damit wurde zusätzlich sichergestellt, dass die Binär-Kompatiblität zu alten Java Versionen erhalten bleibt. Die so genannten Bulk Operations umfassen Funktionalität, die auf mehrere oder alle Elemente einer Collection angewandt werden können.

Bulk Operations werden dabei mit, ebenfalls in Java 8 eingeführten, Lambda-Ausdrücken oder Methodenreferenzen aufgerufen. Ein Beispiel dafür ist die mit der Stream API eingeführte Filterung

Stream<Foobar> foos = …
foos.filter(Foobar::hasFoo);

Stream API

Streams repräsentieren Sequenzen von Elementen und sind dabei die wesentliche Neuerung im Collections Framework. Ein Stream stellt eine neue Abstraktion im Collections Framwork dar und ist die zentrale Stelle in der die Bulk Operationen gesammelt sind.

Collection-basierte Streams

Dabei ist eine Collection nicht von Haus aus ein Stream sondern muss erst mittels stream() oder parallelStream() erzeugt werden. Anhand der Namen der Erzeugungsmethoden kann man schon erkennen in welche Richtung die Verarbeitung der gestellten Bulk Aufgaben zielt. Bei der Parallelisierung wird der Stream automatisch, mithilfe des in Java 7 eingeführten Fork/Join Frameworks, in kleinere Portionen aufgeteilt und in einem Thread-Pool verarbeitet.

List<String> foos = Arrays.asList(“Foo”, “Bar”, “Foobar”);
foos.parallelStream().filter(Foobar::hasFoo).forEach(System.out::println);

Da einige Stream Methoden wieder eine Instanz von Stream zurückliefern, lassen sich so Verarbeitungsketten bilden. Im Beispiel wird eine vorher gefilterte Liste ausgegeben.

Array-basierte Streams

Diese Konvertierung steht auch für Arrays zur Verfügung und wird mittels der Util Klasse Arrays.stream(array) erzeugt. Aber auch die Stream Klasse selbst bietet diverse Factorymethoden an z.B. Stream.of(“foo”, “bar”,  “foobar”);

Primitive Streams

Neben den selbst aus Objekten generierbaren Streams gibt es auch drei Arten von primitiven Streams: IntStream, LongStream und DoubleStream. Je nach Anwendungsfall kann man sich mit Ausprägungen das Autoboxing ersparen. Dabei bieten IntStream und LongStream besondere Factorymethoden an, die das Erzeugen von Zähl-Sequenzen erleichtern sollen.

// 0 bis 9
IntStream foo = IntStream.range(0,10);
// 0 bis 10
IntStream bar = IntStream.rangeClosed(0,10);

Eine weitere Möglichkeit, eine Sequenz zum Zählen zu bekommen, bietet die Stream API mittels der iterate Methode.

Stream<BigInteger> ints = Stream.iterate(BigInteger.ZERO, i->i.add(BigInteger.ONE));

Zufallszahlen per Stream

Mithilfe von java.util.SplittableRandom kann für jede Art der Primitiven Streams eine Instanz gefüllt mit Zufallszahlen erzeugt werden.

IntStream unlimited = new SplittableRandom().ints();
IntStream limited = new SplittableRandom().ints(3);

 

Weitere Infos gibt es unter anderem unter http://docs.oracle.com/javase/tutorial/collections/streams/index.html

Ähnliche Artikel:

Java 8 – Lambda Expressions

Mit Java 8 halten Lambda Expressions Einzug in die Java Welt. Ein Lambda Ausdruck umfasst dabei Funktionalität, die nicht benannt (eine eigene Methode) oder einer Klasse zugeordnet ist, sondern Code der gespeichert und ausgeführt werden kann. Dabei werden Lambdas wie Argumente an Operationen übergeben, die die Funktionalität später ausführen. Ein viel zitiertes Beispiel aus der Stream API (auch eine Neuerung in Java 8) ist:

Stream.of(1,2,3,4,5).forEach({x –> System.out.print(x)})

Dabei wendet die forEach Methode die Lambda Expression an jedem Element der Sequenz an.

x –> System.out.print(x) ist der Lambda Ausdruck. Erst hat er wie eine Methode eine Parameterliste (in diesem Falle nur x). Diese wird mit einem Pfeilsymbol –> an einen geklammerten Lambda-Body übergeben. Wie bei einer anonymen Klasse fehlt der Methodenname. Returntype und eventuelle throws Klausel deduziert der Compiler automatisch aus dem Lambda-Body.

Warum?

Das mag am Anfang etwas befremdlich aussehen. Der Vorteil erschließt sich einem jedoch, wenn man die weiteren neuen Sprachkonstrukte wie

  • default Methoden in Interfaces,
  • @FunctionalInterface
  • oder aber die neue Stream API
  • Methodenreferenzen

hinzuzieht.

Ich möchte das Anhand eines Beispiels illustrieren. Seit Java 1.5 möchte man den extended for loop nicht mehr missen um über die Elemente einer Collection zu iterieren

List<String> foobarList = Arrays.asList("foo","bar","foobar");
for (String foo : myList) {
  System.out.println(foo);
}

Eigentlich schön kurz und übersichtlich, jedoch ist die Umsetzung der Iteration an den Ort des Aufrufes gebunden. Auch kann der extended for loop nicht für eine Paralellisierung herangezogen werden. Dazu müsste man die Liste vorerst in kleinere Teillisten zerlegen und diese dann in unterschiedlichen Threads abarbeiten. Natürlich könnte man sich dafür wieder eine Util Klasse schreiben oder sich eine bereits vorhandene Lösung suchen. Aber es wäre schon schön wenn man das einfach der List überalssen könnte. Zu diesem Zweck wurden default Methoden in Interfaces eingeführt und das Iterable Interface mit einer forEach(Consumer<? superT> action) Methode erweitert.

foobarList.forEach(new Consumer<String>() {
   public void accept(String foo) {
      System.out.println(foo);
   }
});

Der Code hat dabei zwar an Länge zugelegt, aber es hat auch noch die Übersichtlichkeit darunter gelitten. Großes Plus dabei ist natürlich die saubere Trennung von Logik für die Iteration von der Logik für die Verarbeitung des einzelnen Elements. Parallelisierung wir kommen!

Aber es steckt schon eine Menge unübersichtlicher Boilerplate-Code drum herum. Verpacken wir das nun jedoch in die Lambda-Notation habe wir ein übersichtliches Stück Code:

foobarList.forEach((String foo) -> System.out.println(foo));

In diesem speziellen Fall lässt sich der Code noch auf ein Minimum reduzieren, da er nur einen einzelnen Parameter hat und wir sogenannte Methodenreferenzen nutzen können. Diese sind ebenfalls mit Java 8 und den Lambda Ausdrücken im Sprachraum Java eingeführt worden.

myList.forEach(System.out::print);

Nice!

Weiterführende Literatur

Die von Oracle angedachten Anwendungsbereiche sowie eine ausführliche Einführung findet man unter http://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html

Wer sich lieber berieseln lassen mag, dem seien die Videos der Oracle Learning Library empfohlen. Hier das kurze Teaser Video dazu:

Ähnliche Artikel:

Java 8 – Erweiterungen rund ums Interface

In Interfaces können mit Java 8 nun statische und default Methoden definiert werden. Dies hilft dabei den eigenen Code wartbarer zu gestalten.

Mit dem Release von Java 8 stehen uns Java Entwicklern wieder eine Fülle neuer Möglichkeiten ins Haus. Unter anderem wurden die Mittel, die uns bei der Nutzung eines Interface gegeben sind, erweitert.

Statische Methoden in Interfaces

In Interfaces können nun statische Methoden definiert werden. Zu sehen im JDK selbst z.B. im Comperator Interface, dass u.a. um Funktionen für besondere Reihenfolgen erweitert wurde.

Damit ist es möglich für ein Interface Foo eine Util Klasse Foos, welche unter anderen im JDK bei java.util.Collection und deren Subinterfaces üblich sind, zu vereinfachen bzw. ganz aufzulösen. Die Funktionalität kann nun einfach im Interface selbst umgesetzt werden. Perfekte Kandidaten sind dabei Methoden von z.B. Arrays

Siehe auch: http://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html#static

Default Methoden in Interfaces

Zusätzlich können Interfaces in Java 8 um Default Methoden erweitert werden. Man erschafft damit Methoden die sich die Klassen, welche das Interface beerben in voller Funktionalität aneigenen. Dies birgt den Vorteil der Single-Inheritance in Java entgegenwirken zu können. Zusätzlich kann man damit neue Funktionalität zu Intefaces hinzufügen, ohne die Binärkompatiblität mit älterem Code zu brechen.

public interface Human {  
   void eat();  
   int count(String… obj);  
   default void breathe() {  
     // ...  
   }  
 }

Jegliches weitere Interface, welches das Interfaces Human erweitert, kann nun auf 3 Arten mit der default Methode umgehen:

      1. Sie unbeachtet lassen, dabei erbt sie die Funktionalität der default Methode.
      2. Sie erneut deklarieren, so dass sie, wie die ansonsten üblichen Methoden in Interfaces abstrakt ist, und somit implementiert werden muss.
      3. Sie überschreiben mittels neuer default Methode.

Siehe auch: http://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html

Eine ausführlichere Zusammenfassung rund um das Thema Interface findet sich unter http://java-latte.blogspot.co.at/2014/01/everything-about-interface-in-java.html

Ähnliche Artikel:

Java 8 – Überblick

Heute erscheint Java in einer neuen Version! (Hoffentlich, noch ist’s nicht da). Java 8 kann mit vielen Neuerungen punkten. Eine kurze Übersicht gibts hier.

Heute erscheint Java in einer neuen Version! (Hoffentlich, noch ist’s nicht da). Java 8 kann mit vielen Neuerungen punkten. Da ich hier in meinem Blog in den nächsten Beiträgen nur ausgewählte Themen präsentieren möchte, empfehle ich die Lektüre von Fachzeitschriften und Büchern, sowie diverseste Quellen im Internet. Jaxenter.com hat heute eine Reihe von Artikeln zu dem Thema in folgendem Beitrag zusammengefasst: http://jaxenter.com/java-8-is-going-live-today-here-s-your-crib-sheet-49755.html

Die von mir in den nächsten Tagen vorgestellten Themen lauten:

Vorab auch noch gleich zwei Änderungen kurz umrissen, auf die ich mich persönlich besonders freue.

PermGen

Aus dem in der Größe beschränkten PermGen (Permanent Generation) wird nun der sogenannten MetaSpace (im Native Memory). All die Informationen über geladene Java Klassen, internalisierte Strings und statische Variablen landen nun eben nicht mehr in einem beschränkten Bereich sondern können im Umfang nun beliebig wachsen.

Bye Bye java.lang.OutOfMemoryError: PermGen space

PS: Den MetaSpace kann man in der Größe aber beschränken, wenn man unbedingt will :)

Java FX

Java FX wird nun standardmäßig mit dem JDK und dem JRE mitgeliefert. Zwar immer noch als eigene jar, aber diese ist standardmäßig im Classpath hinzugefügt und somit geladen. Es darf also nun munter drauf losgewerkt werden und die neue Oberflächen für Oberfläche genutzt werden, ohne dem Kunden/Benutzer/sich selbst zusätzliche Hürden aufzubürden.

Ähnliche Artikel: