Datenstrukturen in Java. Nützliche Hilfsklassenmethoden

Hi habr!

Ich bin Software Engineer bei EPAM. Seit mehr als 8 Jahren arbeite ich mit in Java geschriebenem Legacy-Code (im Vorgriff auf Kommentare stelle ich fest, dass das Verständnis und die Toleranz für Legacy lange vor EPAM begannen. Abschließend werden Sie die Antwort finden, warum). Oft stieß ich bei der Arbeit auf die gleichen wiederholten Mängel. Dies veranlasste mich, eine Notiz zu schreiben, und ich möchte mit den Datenstrukturen und den Hilfsklassen Collections und Arrays beginnen . Aus irgendeinem Grund vernachlässigen einige Entwickler ihre Verwendung und das vergebens

Ein Java-Entwickler muss sich häufig mit verschiedenen Datenstrukturen auseinandersetzen. Dies können Arrays, alle Arten von Sammlungen oder Implementierungen von Map sein . Es scheint, dass alles klar und verständlich ist, aber es gibt einige kleine Dinge, über die man leicht stolpern kann.

Dieser Hinweis kann sowohl für Anfänger nützlich sein, die diese Nuancen noch nicht kennen, als auch für erfahrene Entwickler, die dies möglicherweise vergessen.

Bild
Foto von ammiel jr auf Unsplash

CAT


Ich möchte sofort reservieren, dass dieses Material für Java 8 relevant ist. Es ist klar, dass einige Dinge in Java 9+ bereits besser gemacht wurden, aber die meisten großen Projekte verwenden am häufigsten die Version von Java 8 (und manchmal Java 6).

Was ist der beste Weg, um eine Array-basierte Sammlung zu erhalten?


Ich schlage vor, mit der Bildung einer Sammlung zu beginnen, die auf einem Array basiert.

Am häufigsten tritt diese Methode auf:

Integer[] someArray = {9, 10, 11, 12}; List<Integer> list = Arrays.asList(someArray); 

Es funktioniert sicherlich, aber ist alles in Ordnung damit? Und gibt es alternative Lösungen?

Zwei Minuspunkte dieses Ansatzes fallen mir gleichzeitig ein:

  • Zunächst gibt die Arrays.asList- Methode eine List zurück . Aber was ist, wenn wir eine andere Implementierung von Collection benötigen ? Arrays.asList lässt dies nicht zu, eine Alternative wird jedoch etwas weiter betrachtet.
  • Zweitens unterstützt die Liste, die durch Aufrufen von Arrays.asList abgerufen wird, keine Größenänderung. Ich denke, viele haben eine Ausnahme gemacht, die sich aus der Arbeit mit einer solchen Liste ergibt.

Auf der Collections- Oberfläche finden Sie eine Alternative zur Arrays.asList- Methode - die Collections.addAll- Methode. So verwenden Sie es:

 //      (List, Set, ...) Collection<Integer> collection = ...; Integer[] someArray = {9, 10, 8, 7}; Collections.addAll(collection, someArray); 

Oder einfach:

 Collections.addAll(collection, 11, 12, 13, 14); 

Die Collections.addAll- Methode akzeptiert ein Collection- Objekt und ein Array am Eingang. Anstelle eines Arrays können Sie auch Elemente angeben, die durch Kommas getrennt sind.

Was sind die Vorteile von Collections.addAll gegenüber Arrays.asList ?

  • Zunächst funktioniert das Erstellen von Sammlungen auf der Grundlage des Arrays Collections.addAll viel schneller als die Methode addAll der Sammlung mit der Eingabe von Arrays.asList . Dies kann im JavaDoc dieser Methode gefunden werden:
    Das Verhalten dieser Convenience-Methode ist identisch mit dem von c.addAll (Arrays.asList (elements)), jedoch wird diese Methode unter den meisten Methoden wahrscheinlich erheblich schneller ausgeführt
  • Darüber hinaus funktioniert Collections.addAll nicht nur mit List , sondern mit jeder anderen Sammlung.
  • Und wenn Sie diese Methode verwenden, gibt es kein Problem bei der Größenänderung.

Wie kann ein Array, ein mehrdimensionales Array oder eine Sammlung am einfachsten gedruckt werden?


Fahren wir mit dem Thema fort, eine gedruckte Darstellung eines Arrays und von Sammlungen zu erhalten.

Wenn wir nur System.out.println (someArray) erstellen , erhalten wir ungefähr Folgendes :
[Ljava.lang.Integer; @ 6d06d69c.
Ein ähnliches Ergebnis wird erwartet, wenn die Methode toString () für ein Array verwendet wird.
Um das Array auszugeben, hilft die Methode Arrays.toString (...) .

 Integer[] someArray = new Integer[]{1, 2, 3}; System.out.println(Arrays.toString(someArray)); 

Die Ausgabe für diese Zeile lautet:

 [1, 2, 3] 

Wenn es sich um ein mehrdimensionales Array handelt, können Sie die Methode Arrays.deeptoString verwenden .

 int[][] a = { {1, 2, 3}, {4, 5, 6} }; System.out.println(Arrays.deepToString(a)); 

Die Ausgabe dieses Snippets lautet:

  [[1, 2, 3], [4, 5, 6]] 


Es ist daher nicht erforderlich, das Array manuell durch eine Schleife zu sortieren, um seine Elemente anzuzeigen, sondern es ist ausreichend, diese Methode zu verwenden.

Bei Sammlungen oder Implementierungen von Map gibt es keine Probleme. Alle Datenstrukturen mit Ausnahme des Arrays werden normalerweise ausgegeben.

Angenommen, es gibt ein Beispiel:

 Collection<Integer> someCollection = new HashSet<>(); someCollection.add(1); someCollection.add(2); System.out.println(someCollection); Map<Integer, String> someMap = new HashMap<>(); someMap.put(1, "Some 1"); someMap.put(2, "Some 2"); System.out.println(someMap); 

Beachten Sie in der folgenden Ausgabe, dass sowohl das Set als auch die Karte in einem leicht lesbaren Format angezeigt wurden:

 [1, 2] 
 {1 = Einige 1, 2 = Einige 2} 


Wie einfach ist es, Arrays miteinander zu vergleichen?


Es gibt Situationen, in denen Sie Arrays vergleichen müssen. In der Klasse Arrays gibt es eine Methode, die einen solchen Vergleich ermöglicht. Die Methode Arrays.equals vergleicht die Anzahl der Elemente und überprüft die Äquivalenz der entsprechenden Elemente.

Angenommen, wir haben eine Elements- Klasse mit einem Feld und bestimmten Gleichungen

 private class Element { final String name; private Element(String name) { this.name = name; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Element element = (Element) o; return Objects.equals(name, element.name); } @Override public int hashCode() { return Objects.hash(name); } } 

Definieren Sie drei Arrays:

 Element[] firstElementArray = { new Element("a"), new Element("b"), new Element("c") }; Element[] secondElementArray = {new Element("c"), new Element("b"), new Element("a") }; Element[] thirdElementArray = { new Element("a"), new Element("b"), new Element("c") }; 

Beachten Sie, dass das erste und das dritte Array Elemente in derselben Reihenfolge enthalten.
Jetzt können Sie den Vergleich mit der Methode Arrays.equals durchführen .

 System.out.println("first equals to second? " + Arrays.equals(firstElementArray, secondElementArray)); System.out.println("second equals to third? " + Arrays.equals(secondElementArray, thirdElementArray)); System.out.println("first equals to third? " + Arrays.equals(firstElementArray, thirdElementArray)); 

Das Ergebnis sieht wie folgt aus:

 erste gleich zweite?  falsch 
 zweite gleich dritte?  falsch 
 erstes gleich drittes?  wahr 


Wie kopiere ich ein Array effizient?


Oft sieht man im Code das manuelle Kopieren von Arrays mit Schleifen. Es gibt jedoch eine System.arraycopy- Methode, die viel schneller kopiert.

Ich schlage einen Blick auf ein so einfaches Beispiel vor:

 Element[] elements = { new Element("a"), new Element("b"), new Element("c") }; Element[] copyOfElements = new Element[elements.length]; System.arraycopy(elements, 0, copyOfElements, 0, elements.length); System.out.println(Arrays.toString(copyOfElements)); 

Wir haben eine Reihe von Elementen. Wir erstellen ein leeres Array mit der gleichen Länge und kopieren alle Elemente von der ersten zur zweiten. Als Ergebnis erhalten wir folgende Schlussfolgerung:

 [Element {name = 'a'}, Element {name = 'b'}, Element {name = 'c'}] 


Wie sortiere ich ein Array oder eine Sammlung auf verschiedene Arten?


Arrays können mit der Methode Arrays.sort (someArray) sortiert werden. Wenn Sie das Array in umgekehrter Reihenfolge sortieren möchten, können Sie Collections.reverseOrder () als zweiten Parameter an die Eingabe dieser Methode übergeben.

Zum Beispiel gibt es ein Array, das wir direkt und dann in umgekehrter Reihenfolge sortieren:

 String[] someArray = new String[]{"b", "a", "c"}; Arrays.sort(someArray); System.out.println(Arrays.toString(someArray)); Arrays.sort(someArray, Collections.reverseOrder()); System.out.println(Arrays.toString(someArray)); 

Die Schlussfolgerung lautet wie folgt:

 [a, b, c] 
 [c, b, a] 


Neben der direkten und umgekehrten Sortierung kann es vorkommen, dass Sie ein Array von Zeichenfolgen unabhängig von der Groß- und Kleinschreibung sortieren müssen. Dies ist einfach, indem Sie String.CASE_INSENSITIVE_ORDER als zweiten Parameter an Arrays.sort übergeben .

Leider können mit Collections.sort nur List- Implementierungen sortiert werden.

Welcher Algorithmus sortiert Java?


Wenn Sie über das Sortieren in Java sprechen, müssen Sie als Letztes erwähnen, dass in Java für die einfachsten Typen "einfaches Sortieren" und für Objekte "stabiles Zusammenführen" verwendet wird. Sie sollten also keine Ressourcen für die Entwicklung Ihrer eigenen Implementierung der Sortiermethode aufwenden, bis der Profiler zeigt, dass dies erforderlich ist.

Was ist, wenn wir ein Array haben und die Methode Iterable akzeptiert?


Ich schlage jetzt vor, zu einer Frage überzugehen, bei der ein Array an eine Methode übergeben wird, für die Iterable erforderlich ist . Lassen Sie mich daran erinnern, dass Iterable eine Schnittstelle ist, die die iterator () -Methode enthält, die Iterator zurückgeben sollte.

Wenn es eine Methode gibt, die Iterable am Eingang akzeptiert, kann das Array nicht einfach so dorthin übertragen werden. Obwohl Sie ein Array in einer for- Schleife durchlaufen können , ist es nicht iterierbar .

 String[] someArray = new String[]{"a", "b", "c"}; for (String currentString : someArray) { ... } 

In diesem Beispiel ist alles in Ordnung. Aber wenn es eine Methode gibt:

 private static void someIteration(Iterable<String> iterable) { ... } 

Diese Zeile wird nicht kompiliert:

 someIteration(someArray); 

Der einzige Ausweg in dieser Situation besteht darin, das Array in eine Auflistung zu konvertieren und es bereits einer solchen Methode zuzuführen.

Kurze Beschreibung einiger nützlicher Collections-Methoden


MethodeKommentar
max (Sammlung) und max (Sammlung, Komparator)
min (Sammlung) und min (Sammlung, Komparator)
Bitte beachten Sie, dass Sie sich auf die Eingabe von Comparator beziehen können
indexOfSubList (Liste, Liste)
Findet den Index des ersten Auftretens einer Liste (zweites Argument) in einer anderen (erstes Argument)
lastIndexOfSubList (Liste, Liste)
Findet den Index des letzten Vorkommens einer Liste (zweites Argument) in einer anderen (erstes Argument)
umgekehrt (Liste)
Artikel in umgekehrter Reihenfolge nachbestellen

Was ist lesenswert?


Dies ist nur ein kleiner Teil der Tools, die dem Entwickler das Arbeiten mit Datenstrukturen erleichtern können. Viele interessante Punkte in der Arbeit der Sammlungen selbst und praktische Werkzeuge für die Arbeit mit ihnen finden Sie in Bruce Eckels Buch "Java Philosophy" (4. vollständige Ausgabe). Sie sollten jedoch vorsichtig sein, da es Situationen gibt, die auf Java 7, Java 8 und höher nicht mehr gespielt werden können. Obwohl Java 6 in diesem Buch beschrieben wird, bleibt sein Material bis heute weitgehend relevant.

Natürlich sollte die "Java-Philosophie" nicht eingeschränkt werden. Das Lesen eines dieser Bücher schadet keinem Java-Entwickler:

  • "Java. Effektive Programmierung “, erklärt Joshua Bloch.
  • „Refactoring. Das Design des vorhandenen Codes verbessern “, so Martin Fowler.
  • „Code bereinigen. Kreation, Analyse und Refactoring “, Robert Martin.
  • Frühling 5 für Profis, Julian Kozmin und andere.
  • "Test-Driven Java Development", Viktor Farcic, Alex Garcia (noch nicht in russischer Sprache veröffentlicht).

Was ist das ergebnis


Wenn Sie interessante Ideen haben, die das ergänzen könnten, was in diesem Artikel geschrieben wurde, teilen Sie sie in den Kommentaren mit.

Ich möchte auch denen, die mit dem alten Code arbeiten, viel Glück und Geduld wünschen. Die meisten Großprojekte sind Legacy-Projekte. Und ihre Bedeutung für den Kunden ist schwer zu überschätzen. Und das Gefühl des Sieges durch das Beseitigen des Fehlers, das mehr als eine Woche gedauert hat, um die Gründe zu finden, ist den Gefühlen am Ende der Implementierung eines neuen Features nicht unterlegen.

Danke für die Aufmerksamkeit. Ich würde mich freuen, wenn einer der vorgestellten nützlich wäre.
Alles Erfolg!

Source: https://habr.com/ru/post/de476098/


All Articles