Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

 
Inhaltsverzeichnis
Vorwort
1 Java ist auch eine Sprache
2 Imperative Sprachkonzepte
3 Klassen und Objekte
4 Der Umgang mit Zeichenketten
5 Eigene Klassen schreiben
6 Objektorientierte Beziehungsfragen
7 Ausnahmen müssen sein
8 Äußere.innere Klassen
9 Besondere Typen der Java SE
10 Generics<T>
11 Lambda-Ausdrücke und funktionale Programmierung
12 Architektur, Design und angewandte Objektorientierung
13 Komponenten, JavaBeans und Module
14 Die Klassenbibliothek
15 Einführung in die nebenläufige Programmierung
16 Einführung in Datenstrukturen und Algorithmen
17 Einführung in grafische Oberflächen
18 Einführung in Dateien und Datenströme
19 Einführung ins Datenbankmanagement mit JDBC
20 Einführung in <XML>
21 Testen mit JUnit
22 Bits und Bytes und Mathematisches
23 Die Werkzeuge des JDK
A Java SE-Paketübersicht
Stichwortverzeichnis


Download:

- Beispielprogramme, ca. 35,4 MB


Buch bestellen
Ihre Meinung?



Spacer
<< zurück
Java ist auch eine Insel von Christian Ullenboom

Einführung, Ausbildung, Praxis
Buch: Java ist auch eine Insel


Java ist auch eine Insel

Pfeil 9 Besondere Typen der Java SE
Pfeil 9.1 Object ist die Mutter aller Klassen
Pfeil 9.1.1 Klassenobjekte
Pfeil 9.1.2 Objektidentifikation mit toString()
Pfeil 9.1.3 Objektgleichheit mit equals(…) und Identität
Pfeil 9.1.4 Klonen eines Objekts mit clone() *
Pfeil 9.1.5 Hashwerte über hashCode() liefern *
Pfeil 9.1.6 System.identityHashCode(…) und das Problem der nicht eindeutigen Objektverweise *
Pfeil 9.1.7 Aufräumen mit finalize() *
Pfeil 9.1.8 Synchronisation *
Pfeil 9.2 Die Utility-Klasse java.util.Objects
Pfeil 9.3 Vergleichen von Objekten
Pfeil 9.3.1 Natürlich geordnet oder nicht?
Pfeil 9.3.2 Die Schnittstelle Comparable
Pfeil 9.3.3 Die Schnittstelle Comparator
Pfeil 9.3.4 Rückgabewerte kodieren die Ordnung
Pfeil 9.3.5 Statische und Default-Methoden in Comparator
Pfeil 9.4 Wrapper-Klassen und Autoboxing
Pfeil 9.4.1 Wrapper-Objekte erzeugen
Pfeil 9.4.2 Konvertierungen in eine String-Repräsentation
Pfeil 9.4.3 Von einer String-Repräsentation parsen
Pfeil 9.4.4 Die Basisklasse Number für numerische Wrapper-Objekte
Pfeil 9.4.5 Vergleiche durchführen mit compare(…), compareTo(…), equals(…) und Hashwerten
Pfeil 9.4.6 Statische Reduzierungsmethoden in Wrapper-Klassen
Pfeil 9.4.7 Die Größe eines primitiven Typs in den Wrapper-Konstanten SIZE und BYTES
Pfeil 9.4.8 Behandeln von vorzeichenlosen Zahlen *
Pfeil 9.4.9 Die Klasse Integer
Pfeil 9.4.10 Die Klassen Double und Float für Fließkommazahlen
Pfeil 9.4.11 Die Long-Klasse
Pfeil 9.4.12 Die Boolean-Klasse
Pfeil 9.4.13 Autoboxing: Boxing und Unboxing
Pfeil 9.5 Iterator, Iterable *
Pfeil 9.5.1 Die Schnittstelle Iterator
Pfeil 9.5.2 Wer den Iterator liefert
Pfeil 9.5.3 Die Schnittstelle Iterable
Pfeil 9.5.4 Erweitertes for und Iterable
Pfeil 9.5.5 Interne Iteration
Pfeil 9.5.6 Einen eigenen Iterable implementieren *
Pfeil 9.6 Die Spezial-Oberklasse Enum
Pfeil 9.6.1 Methoden auf Enum-Objekten
Pfeil 9.6.2 Aufzählungen mit eigenen Methoden und Initialisierern *
Pfeil 9.6.3 enum mit eigenen Konstruktoren *
Pfeil 9.7 Zum Weiterlesen
 

Zum Seitenanfang

9.3Vergleichen von Objekten Zur vorigen ÜberschriftZur nächsten Überschrift

Die Object-Methode equals(Object) gibt Auskunft darüber, ob zwei Objekte die gleichen Eigenschaften haben, es sagt aber nichts darüber aus, welches Objekt »größer« oder »kleiner« ist. Doch in vielen Anwendungen spielt die Ordnung von Objekten eine Rolle. Offensichtlich ist das bei der Sortierung, aber auch bei einfacheren Fragen, wie der nach dem größten oder kleinsten Element einer Sammlung. Sollen Objekte in Java verglichen werden, muss es immer eine Ordnung dieser Objekte geben. Das System wird nie selbstständig entscheiden können, und oftmals gibt es mehrere Kriterien. Warum ist zum Beispiel eine Person kleiner als eine andere Person? Weil die eine Person 1,50 Meter groß ist, die andere aber 1,80 Meter, oder weil es die eine Person beim Dschungelcamp bis ins Finale geschafft hat?[ 187 ](Im 10. Jahrhundert lebte der Großwesir Abdul Kassem Ismael, der immer seine gesamte Bibliothek mit 117.000 Bänden mitführte. Die trainierten 400 Kamele transportierten die Werke in alphabetischer Reihenfolge. )

 

Zum Seitenanfang

9.3.1Natürlich geordnet oder nicht? Zur vorigen ÜberschriftZur nächsten Überschrift

In Java gibt es zwei unterschiedliche funktionale Schnittstellen (in zwei unterschiedlichen Paketen) zur Bestimmung der Ordnung:

  • Comparable: Implementiert eine Klasse Comparable, so können sich die Objekte selbst mit anderen Objekten vergleichen. Da die Klassen im Allgemeinen nur ein Sortierkriterium implementieren, wird hierüber eine so genannte natürliche Ordnung (engl. natural ordering) realisiert.

  • Comparator: Eine implementierende Klasse, die sich Comparator nennt, nimmt zwei Objekte an und vergleicht sie. Ein Comparator für Räume könnte zum Beispiel nach der Anzahl der Personen oder auch nach der Größe in Quadratmetern vergleichen; die Implementierung von Comparable wäre nicht sinnvoll, weil hier nur ein Kriterium natürlich umgesetzt werden kann, ein Raum aber nicht die Ordnung hat.

Zusammenfassend lässt sich sagen: Während Comparable üblicherweise nur ein Sortierkriterium umsetzt, kann es viele Extraklassen vom Typ Comparator geben, die jeweils unterschiedliche Ordnungen definieren.

Comparable und Comparator in der Java-API

Eine Implementierung von Comparable findet sich genau dort, wo eine natürliche Ordnung naheliegt, etwa bei:

  • BigDecimal, BigInteger, Byte, Character, Double, Float, Integer, Long, Short

  • Date, Calendar, LocalTime, LocalDate

  • String

  • File, URI

  • Enum

  • TimeUnit

Von Comparator finden wir in der API-Dokumentation nur java.text.Collator (und seine Unterklasse) vermerkt.

Vereinfachtes UML-Diagramm von Comparator und Comparable

Abbildung 9.3Vereinfachtes UML-Diagramm von Comparator und Comparable

 

Zum Seitenanfang

9.3.2Die Schnittstelle Comparable Zur vorigen ÜberschriftZur nächsten Überschrift

Die funktionale Schnittstelle Comparable kommt aus dem java.lang-Paket und deklariert eine Methode compareTo(…):

[zB]Beispiel

LocalTime implementiert Comparable:

LocalTime elevenses = LocalTime.of( 11, 0 );

LocalTime lunchtime = LocalTime.of( 12, 0 );

System.out.println( elevenses.compareTo( lunchtime ) ); // -1

System.out.println( lunchtime.compareTo( elevenses ) ); // 1
interface java.lang.Comparable<T>
  • int compareTo(T o)

    Vergleicht sich mit einem anderen Objekt.

[»]Hinweis

Wichtig ist neben einer Implementierung von compareTo(…) auch die passende Realisierung in equals(…). Sie ist erst dann konsistent, wenn e1.compareTo(e2) == 0 das gleiche Ergebnis wie e1.equals(e2) liefert, wobei e1 und e2 den gleichen Typ besitzen. Ein Verstoß gegen diese Regel kann bei sortierten Mengen schnell Probleme bereiten; ein Beispiel nennt die API-Dokumentation. Auch sollte die hashCode()-Methode korrekt realisiert sein, denn sind Objekte gleich, müssen auch die Hashwerte gleich sein. Und die Gleichheit bestimmen eben equals(…)/compareTo(…).

e.compareTo(null) sollte eine NullPointerException auslösen, auch wenn e.equals(null) die Rückgabe false liefert. null ist in der Regel nicht größer/kleiner/gleich einem anderen mit compareTo(…) verglichenem Wert, daher ist eine Ausnahme die einzig vernünftige Reaktion.

 

Zum Seitenanfang

9.3.3Die Schnittstelle Comparator Zur vorigen ÜberschriftZur nächsten Überschrift

Die funktionale Schnittstelle Comparator kommt aus dem Paket java.util (nicht wie Comparable aus java.lang) und deklariert eine zwingend zu implementierende Methode:

interface java.util.Comparator<T>
  • int compare(T o1, T o2)

    Vergleicht zwei Argumente auf ihre Ordnung.

[»]Hinweis *

Neben compare(…) deklariert Comparator auch das aus Object bekannte boolean equals(Object obj). Die Methode muss nicht zwingend implementiert werden, da Object ja schon eine Implementierung bereitstellt. Die Methode steht nur deshalb in der Schnittstelle, damit eine API-Dokumentation erklärt, dass equals(…) nur testet, ob zwei Comparator-Objekte gleich sind.

 

Zum Seitenanfang

9.3.4Rückgabewerte kodieren die Ordnung Zur vorigen ÜberschriftZur nächsten Überschrift

Der Rückgabewert von compare(…) beim Comparator bzw. compareTo(…) bei Comparable ist <0, =0 oder >0 und bestimmt so die Ordnung der Objekte – das wird auch Drei-Wege-Vergleich (engl. three-way comparison) genannt.[ 188 ](Programmiersprachen wie Perl, Groovy und Facebooks PHP-Dialekt Hack haben hierfür einen <=>-Operator. Da der wie ein Raumschiff aussieht, heißt er auch spaceship operator. ) Nehmen wir zwei Objekte o1 und o2 an, deren Klassen Comparable implementieren. Dann gilt folgende Übereinkunft:

o1.compareTo( o2 ) < 0

o1 ist »kleiner als« o2.

o1.compareTo( o2 ) == 0

o1 ist »gleich« o2.

o1.compareTo( o2 ) > 0

o1 ist »größer als« o2.

Ein externer Comparator (symbolisch comp genannt) verhält sich ähnlich:

comp.compare( o1, o2 ) < 0

o1 ist »kleiner als« o2.

comp.compare( o1, o2 ) == 0

o1 ist »gleich« o2.

comp.compare( o1, o2 ) > 0

o1 ist »größer als« o2.

[+]Tipp

Sollen Objekte mit einem Comparator verglichen werden, aber null-Werte vorher aussortiert werden, so ist die statische Methode int compare(T a, T b, Comparator<? super T> c) aus der Klasse Objects nützlich. Die Methode liefert 0, wenn a und b beide entweder null sind oder der Comparator die Objekte a und b für gleich erklärt. Sind a und b beide ungleich null, so ist die Rückgabe c.compare(a, b). Ist nur a oder b gleich null, so hängt es vom Comparator und der Reihenfolge der Parameter ab.

Den kleinsten Raum einer Sammlung finden

Wir wollen Räume ihrer Größe nach sortieren und müssen dafür einen Comparator schreiben (dass Räume Comparable sind, ist nicht angebracht, da es keine natürliche Ordnung für Räume gibt). Daher soll ein externes Comparator-Objekt entscheiden, welches Raum-Objekt nach der Anzahl seiner Quadratmeter größer ist; weniger Quadratmeter bedeuten, der Raum ist kleiner.

Die Raum-Klasse enthält für das kleine Demoprogramm einen parametrisierten Konstruktor, der sich die Quadratmeter merkt, und einen Getter.

Listing 9.20com/tutego/insel/util/Room.java, Room

public class Room {

private int sqm;

public Room( int sqm ) {

this.sqm = sqm;

}

public int getSqm() {

return sqm;

}

}

Ein Raum, aufgebaut durch new Room(100), soll kleiner sein als new Room(1123). Dazu muss der Raum-Comparator auf die Quadratmeter zurückgreifen, andere Kriterien gibt es nicht:

Listing 9.21com/tutego/insel/util/RoomComparatorDemo.java, RoomComparator

class RoomComparator implements Comparator<Room> {

@Override public int compare( Room room1, Room room2 ) {

return Integer.compare( room1.getSqm(), room2.getSqm() );

}

}
Der eigene Comparator muss nur compare(…) von der Schnittstelle überschreiben.

Abbildung 9.4Der eigene Comparator muss nur compare(…) von der Schnittstelle überschreiben.

Die Methode Integer.compare(…) bietet sich für den Vergleich an, alternativ kann auch die Differenz room1.sm room2.sm der Raumgrößen für eine Vergleichsrückgabe <0, =0 oder >0 eingesetzt werden. Bei Fließkommazahlen funktioniert das nicht, denn (int)(0.10.0), (int)(0.0 0.1) und (int)(0.0 0.0) ergeben alle 0, wären also gleich – bei Ganzzahlen ist der Vergleich aber in Ordnung. Daher ist die compare(…)-Methode der Wrapper-Klassen eine gute und universelle Wahl.

[+]Designtipp

Ein zustandsloser Comparator kann gut mit einem enum programmiert werden.

Mit dem Comparator-Objekt lässt sich ein Array mit Räumen sortieren, vorne steht dann der kleinste Raum:

Listing 9.22com/tutego/insel/util/RoomComparatorDemo.java, RoomComparatorDemo main()

Room[] rooms = { new Room(1123), new Room(100), new Room(123) };

Arrays.sort( rooms, new RoomComparator() );

System.out.println( rooms[0].getSqm() ); // 100

[»]Hinweis

Ist ein Comparator mit einer Datenstruktur – wie dem TreeSet oder der TreeMap – verbunden, muss die Comparator-Klasse Serializable (siehe Kapitel 18, »Einführung in Dateien und Datenströme«) implementieren, wenn auch die Datenstruktur serialisiert werden soll.

 

Zum Seitenanfang

9.3.5Statische und Default-Methoden in Comparator Zur vorigen ÜberschriftZur nächsten Überschrift

Die Schnittstelle Comparator bietet eine ganze Reihe von statischen und Default-Methoden. (In Comparable gibt es übrigens keine statischen oder Default-Methoden.) Besonders interessant sind die Möglichkeiten, mehrere Comparatoren zusammenzubinden.

Beginnen wir mit den einfach zu verstehenden Methoden:

interface java.util.Comparator<T>
  • static <T extends Comparable<? super T>> Comparator<T> reverseOrder()

    Liefert einen neuen Comparator, der die natürliche Sortierreihenfolge umdreht. Entspricht Collections.reverseOrder(). Im Grunde ein Comparator mit einer compare(Comparable<Object> c1, Comparable<Object> c2)-Methode, die c2.compareTo(c1) liefert.

  • default Comparator<T> reversed()

    Liefert für diesen aktuellen Comparator einen, der die Sortierreihenfolge umdreht. Entspricht Collections.reverseOrder(this).

  • static <T extends Comparable<? super T>> Comparator<T> naturalOrder()

    Liefert einen Comparator, der die natürliche Ordnung von Objekten verwendet, sprich, int compare(Comparable<Object> c1, Comparable<Object> c2) ist implementiert als return c1.compareTo(c2);

  • static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator)

  • static <T> Comparator<T> nullsLast(Comparator<? super T> comparator)

    Liefert für einen gegebenen comparator einen neuen Comparator, der Vergleiche mit null erlaubt und null von der Ordnung her entweder vor oder hinter die anderen Werte setzt.

Aneinanderreihung von Comparatoren

Oftmals ist das Ordnungskriterium aus mehreren Bedingungen zusammengesetzt, wie die Sortierung in einem Telefonbuch zeigt. Erst gibt es eine Sortierung nach dem Nachnamen, dann folgt der Vorname. Um dies mit einem Comparator-Objekt zu lösen, müssen entweder alle Einzelvergleiche in ein neues Comparator-Objekt verpackt werden oder einzelne Comparatoren zu einem »Super«-Comparator zusammengebunden werden. Die zweite Lösung ist natürlich schöner, weil sie die Wiederverwendbarkeit erhöht, denn einzelne Comparatoren können dann leicht für andere Zusammenhänge genutzt werden. Genau für so eine Aneinanderreihung gibt es in Comparator eine nützliche Methode:

interface java.util.Comparator<T>
  • default Comparator<T> thenComparing(Comparator<? super T> other)

    Wendet erst den eigenen Comparator an, dann den anderen other.

Wir wollen diese thenComparing(…)-Methoden aus Comparator für ein Beispiel nutzen, das eine Liste nach Nach- und Vornamen sortiert. Die Comparatoren sind in der Lambda-Schreibweise von Java 8 formuliert.

Listing 9.23com/tutego/insel/util/ComparatorThenComparingDemo.java

package com.tutego.insel.util;



import java.util.*;



public class ComparatorThenComparingDemo {



public static class Person {



public String firstname, lastname;



public Person( String firstname, String lastname ) {

this.firstname = firstname;

this.lastname = lastname;

}



@Override public String toString() {

return firstname + " " + lastname;

}

}



public final static Comparator<Person> PERSON_FIRSTNAME_COMPARATOR =

(p1, p2) -> p1.firstname.compareTo( p2.firstname );



public final static Comparator<Person> PERSON_LASTNAME_COMPARATOR =

(p1, p2) -> p1.lastname.compareTo( p2.lastname );



public static void main( String[] args ) {

List<Person> persons = Arrays.asList(

new Person( "Onkel", "Ogar" ), new Person( "Olga", "Ogar" ),

new Person( "Peter", "Lustig" ), new Person( "Lara", "Lustig" ) );



persons.sort( PERSON_LASTNAME_COMPARATOR );

System.out.println( persons );

persons.sort( PERSON_FIRSTNAME_COMPARATOR );

System.out.println( persons );

persons.sort( PERSON_LASTNAME_COMPARATOR.thenComparing(

PERSON_FIRSTNAME_COMPARATOR ) );

System.out.println( persons );

}

}

Die Ausgabe ist:

[Peter Lustig, Lara Lustig, Onkel Ogar, Olga Ogar]

[Lara Lustig, Olga Ogar, Onkel Ogar, Peter Lustig]

[Lara Lustig, Peter Lustig, Olga Ogar, Onkel Ogar]

Vergleichswert extrahieren und Vergleiche anstellen *

Die verbleibenden Methoden in Comparator bieten alle die Spezialität, dass sie besondere Funktionsobjekte annehmen, die den »Schlüssel« für die Vergleiche extrahieren und dann für den Vergleich heranziehen. Mit der Syntax der Methodenreferenzen lassen sich sehr kompakte Comparator-Objekte formulieren.

Zu den Methoden:

interface java.util.Comparator<T>
  • static <T,U> Comparator<T> comparing(Function<? super T,? extends U> keyExtractor, Comparator<? super U> keyComparator)

  • static <T,U extends Comparable<? super U>> Comparator<T> comparing(Function<? super T,? extends U> keyExtractor)

  • static <T> Comparator<T> comparingInt(ToIntFunction<? super T> keyExtractor)

  • static <T> Comparator<T> comparingLong(ToLongFunction<? super T> keyExtractor)

  • static<T> Comparator<T> comparingDouble(ToDoubleFunction<? super T> keyExtractor)

  • default <U extends Comparable<? super U>> Comparator<T> thenComparing(Function<? super T,? extends U> keyExtractor)

  • default <U> Comparator<T> thenComparing(Function<? super T,? extends U>

    keyExtractor, Comparator<? super U> keyComparator)

  • default Comparator<T> thenComparingDouble(ToDoubleFunction<? super T> keyExtractor)

  • default Comparator<T> thenComparingInt(ToIntFunction<? super T> keyExtractor)

  • default Comparator<T> thenComparingLong(ToLongFunction<? super T> keyExtractor)

[zB]Beispiel

Das Beispiel mit den Raumvergleichen alternativ formuliert (wir greifen auf eine kompakte Syntax zu, die Methodenreferenz heißt; wir kommen in späteren Kapiteln noch einmal detailliert darauf zurück):

Listing 9.24com/tutego/insel/util/ComparatorDemo.java, Ausschnitt

Comparator<Room> comp = Comparator.comparingInt( Room::getSqm );

// kurz für Comparator.comparingInt( (Room r) -> r.getSqm() );

list.sort( comp );

Komplett ohne Implementierung eigener Comparator-Klassen kann dieser Einzeiler mithilfe der Extraktionsfunktionen nach Vor-/Nachnamen sortieren, unter der Voraussetzung, dass es zwei Getter gibt:

persons.sort( Comparator.comparing( Person::getLastname )

.thenComparing( Person::getFirstname ) );

 


Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.

>> Zum Feedback-Formular
<< zurück
 Zum Katalog
Zum Katalog: Java ist auch eine Insel Java ist auch eine Insel

Jetzt bestellen


 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?

Ihre Meinung



 Buchempfehlungen
Zum Katalog: Java ist auch eine Insel

Java ist auch eine Insel




Zum Katalog: Java SE 9-Standard-Bibliothek

Java SE 9-Standard-Bibliothek




Zum Katalog: Professionell entwickeln mit Java EE 8

Professionell entwickeln mit Java EE 8




Zum Katalog: Entwurfsmuster

Entwurfsmuster




Zum Katalog: IT-Projektmanagement

IT-Projektmanagement




 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich

InfoInfo



 

 


Copyright © Rheinwerk Verlag GmbH 2017

Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

 

[Rheinwerk Computing]



Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de