Deklarieren Sie keine Variablen in List in Java

Deklarieren Sie keine Variablen in List in Java

//schlechtes Beispiel
List<String> list = new ArrayList<>();

//Gutes Beispiel
ArrayList<String> list = new ArrayList<>();

Bis jetzt wurde gesagt, dass Variablen im Listentyp deklariert werden sollten, der eine Schnittstelle ist, und tatsächlich habe ich auch eine große Anzahl von Variablen im Listentyp deklariert. Aber ich kam zu dem Schluss, dass es ein Fehler war. Der Grund wird unten erklärt.

Der Grund, warum gesagt wurde, dass es in Liste deklariert werden sollte

Die Schnittstelle ist die Definition der Spezifikation. Es verspricht, dass "die Klasse, die diese Schnittstelle implementiert, die in diese Schnittstelle geschriebenen Methoden haben wird". Durch die Verwendung der Implementierungsklasse über die Schnittstelle muss die Benutzerseite die Implementierung nicht kennen, und es wird eine lose Kopplung realisiert.

Um dies konkret mit einer Java-Liste zu erklären, wird durch die Deklaration von "List list = new ArrayList <> ()" die Abhängigkeit von der ArrayList-Klasse beseitigt. Selbst wenn Sie die ArrayList durch eine vorhandene LinkedList oder Ihr eigenes selbst erstelltes Saikyo Norisu ersetzen, funktioniert dies problemlos. Zukünftig können der API neue Listenklassen hinzugefügt werden, aber auch diese können leicht ersetzt werden.

Die derzeit vorherrschende Idee besteht darin, eine lose Kopplung zu erreichen, indem Implementierungsklassen über die List-Schnittstelle verarbeitet werden, wodurch das Programm in hohem Maße erweiterbar und resistent gegen Änderungen wird.

Eigentlich versuchen

Probieren wir es aus.

sample

public static void main(String[] args)
{
	List<Integer> list = getList();
	listTest(list);
}

public static List<Integer> getList()
{
	return new ArrayList<>();
}
public static void listTest(List<Integer> list)
{
	System.out.println(list.getClass());
	
	list.add(1);
	list.add(2);
	list.add(3);
	
	list.forEach(System.out::println);
}

Es ist ein Beispiel, das nur eine Liste erstellt, Zahlen einfügt und diese anzeigt. Sie können auch den Klassennamen in der Liste überprüfen.

Das Ergebnis wird natürlich so sein.

class java.util.ArrayList
1
2
3

Ersetzen wir nun die List-Klasse.

■CopyOnWriteArrayList

public static void main(String[] args)
{
	List<Integer> list = getList();
	listTest(list);
}

public static List<Integer> getList()
{
	return new CopyOnWriteArrayList<>();
}
public static void listTest(List<Integer> list)
{
	System.out.println(list.getClass());
	
	list.add(1);
	list.add(2);
	list.add(3);
	
	list.forEach(System.out::println);
}
class java.util.concurrent.CopyOnWriteArrayList
1
2
3

■LinkedList

public static void main(String[] args)
{
	List<Integer> list = getList();
	listTest(list);
}

public static List<Integer> getList()
{
	return new LinkedList<>();
}
public static void listTest(List<Integer> list)
{
	System.out.println(list.getClass());
	
	list.add(1);
	list.add(2);
	list.add(3);
	
	list.forEach(System.out::println);
}
class java.util.LinkedList
1
2
3

■ Selbst erstellte Listenklasse

public static void main(String[] args)
{
	List<Integer> list = getList();
	listTest(list);
}

public static List<Integer> getList()
{
	return new SaikyoList<>();
}
public static void listTest(List<Integer> list)
{
	System.out.println(list.getClass());
	
	list.add(1);
	list.add(2);
	list.add(3);
	
	list.forEach(System.out::println);
}

/**
 *Wenn ich darüber nachdenke
 *Das Implementieren einer Liste ist mühsam. Erweitern Sie daher eine ArrayList.
 */
public class SaikyoList<E> extends ArrayList<E>
{
	@Override
	public boolean add(E e)
	{
		//Da es ein guter Tag ist, fügen Sie doppelt so viel wie die normale Liste hinzu
		super.add(e);
		super.add(e);
		return true;
	}
}
class test.SaikyoList
1
1
2
2
3
3

■Collections.emptyList();

public static void main(String[] args)
{
	List<Integer> list = getList();
	listTest(list);
}

public static List<Integer> getList()
{
	return Collections.emptyList();
}
public static void listTest(List<Integer> list)
{
	System.out.println(list.getClass());
	
	list.add(1);
	list.add(2);
	list.add(3);
	
	list.forEach(System.out::println);
}
class java.util.Collections$EmptyList
Exception in thread "main" java.lang.UnsupportedOperationException
	at java.base/java.util.AbstractList.add(AbstractList.java:153)

Oh?

■Collections.singletonList(1);

public static void main(String[] args)
{
	List<Integer> list = getList();
	listTest(list);
}

public static List<Integer> getList()
{
	return Collections.singletonList(1);
}
public static void listTest(List<Integer> list)
{
	System.out.println(list.getClass());
	
	list.add(1);
	list.add(2);
	list.add(3);
	
	list.forEach(System.out::println);
}
class java.util.Collections$SingletonList
Exception in thread "main" java.lang.UnsupportedOperationException
	at java.base/java.util.AbstractList.add(AbstractList.java:153)

■Arrays.asList();

public static void main(String[] args)
{
	List<Integer> list = getList();
	listTest(list);
}

public static List<Integer> getList()
{
	return Arrays.asList();
}
public static void listTest(List<Integer> list)
{
	System.out.println(list.getClass());
	
	list.add(1);
	list.add(2);
	list.add(3);
	
	list.forEach(System.out::println);
}
class java.util.Arrays$ArrayList
Exception in thread "main" java.lang.UnsupportedOperationException
	at java.base/java.util.AbstractList.add(AbstractList.java:153)

■List.of();

public static void main(String[] args)
{
	List<Integer> list = getList();
	listTest(list);
}

public static List<Integer> getList()
{
	return List.of();
}
public static void listTest(List<Integer> list)
{
	System.out.println(list.getClass());
	
	list.add(1);
	list.add(2);
	list.add(3);
	
	list.forEach(System.out::println);
}
class java.util.ImmutableCollections$List0
Exception in thread "main" java.lang.UnsupportedOperationException
	at java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java:70)

■List.of(1);

public static void main(String[] args)
{
	List<Integer> list = getList();
	listTest(list);
}

public static List<Integer> getList()
{
	return List.of(1);
}
public static void listTest(List<Integer> list)
{
	System.out.println(list.getClass());
	
	list.add(1);
	list.add(2);
	list.add(3);
	
	list.forEach(System.out::println);
}
class java.util.ImmutableCollections$List1
Exception in thread "main" java.lang.UnsupportedOperationException
	at java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java:70)

■List.of(1, 2);

public static void main(String[] args)
{
	List<Integer> list = getList();
	listTest(list);
}

public static List<Integer> getList()
{
	return List.of(1, 2);
}
public static void listTest(List<Integer> list)
{
	System.out.println(list.getClass());
	
	list.add(1);
	list.add(2);
	list.add(3);
	
	list.forEach(System.out::println);
}
class java.util.ImmutableCollections$List2
Exception in thread "main" java.lang.UnsupportedOperationException
	at java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java:70)

■List.of(1, 2, 3);

public static void main(String[] args)
{
	List<Integer> list = getList();
	listTest(list);
}

public static List<Integer> getList()
{
	return List.of(1, 2, 3);
}
public static void listTest(List<Integer> list)
{
	System.out.println(list.getClass());
	
	list.add(1);
	list.add(2);
	list.add(3);
	
	list.forEach(System.out::println);
}
class java.util.ImmutableCollections$ListN
Exception in thread "main" java.lang.UnsupportedOperationException
	at java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java:70)

■Collections.unmodifiableList(new ArrayList<>());

public static void main(String[] args)
{
	List<Integer> list = getList();
	listTest(list);
}

public static List<Integer> getList()
{
	return Collections.unmodifiableList(new ArrayList<>());
}
public static void listTest(List<Integer> list)
{
	System.out.println(list.getClass());
	
	list.add(1);
	list.add(2);
	list.add(3);
	
	list.forEach(System.out::println);
}
class java.util.Collections$UnmodifiableRandomAccessList
Exception in thread "main" java.lang.UnsupportedOperationException
	at java.base/java.util.Collections$UnmodifiableCollection.add(Collections.java:1056)

UnsupportedOperationException!

UnsupportedOperationException!!

UnsupportedOperationException!!!

Ich sagte nur, dass ich add implementieren würde ...

Es war eine Lüge, wenn es Sman gab

Wie ist es passiert

Die List-Oberfläche definiert Hinzufügen, Entfernen, Festlegen usw., und es ist klar, dass wir eine Variablensammlung im Auge haben. Listen mit einer festen Anzahl von Elementen (java.util.Arrays \ $ ArrayList) und unveränderlichen Listen (java.util.Collections \ $ UnmodizableList usw.) implementieren jedoch auch die List-Schnittstelle und eine der Methoden zum Realisieren der Unveränderlichkeit. Es besteht die Form, dass nur eine "UnsupportedOperationException" für das Teil ausgelöst wird.

Mit anderen Worten, Java List verfügt über unveränderliche und variable Implementierungsklassen, obwohl es Methoden zum Ändern der Liste definiert. Daher werden die Methoden zum Ändern dieser Listen zu Methoden, die nicht verwendet werden können, ohne die Implementierungsklasse zu kennen. Es ist geschlossen. Weit davon entfernt, lose gekoppelt zu sein, funktioniert es möglicherweise nicht, wenn die Implementierungsklasse ersetzt wird. Selbst wenn die Kopplung nicht ordnungsgemäß durchgeführt wird, handelt es sich um eine falsche Kopplung.

Dies wird in der Methode "Collectors.toList" deutlich, die als Argument für stream.collect verwendet wird. Die aktuelle Implementierung gibt eine ArrayList zurück, in der Dokumentation heißt es jedoch:

Es gibt keine Garantie für den Typ, die Variabilität, die Serialisierbarkeit oder die Thread-Sicherheit der zurückgegebenen Liste. https://docs.oracle.com/javase/jp/8/docs/api/java/util/stream/Collectors.html#toList--

Ursprünglich denke ich, dass unveränderliche Sammlungen als iterierbar behandelt werden sollten. Es muss gesagt werden, dass es ein Entwurfsfehler ist, die List-Schnittstelle zu implementieren, da wir Dinge, die die Funktion nicht als Liste haben, zusammen als Liste behandeln möchten.

~~ Immerhin ist Java Scheiße ... ~~

Darüber hinaus ist es ärgerlich, dies zur Kompilierungszeit in Form von Laufzeitausnahmen zu wissen.

Was soll getan werden

Wie oben erwähnt, weisen die List-Schnittstelle und ihre Implementierungsklasse einen schwerwiegenden Fehler auf. In diesem Dokument soll daher gezeigt werden, dass add und andere Methoden gültig sind, indem Variablen als ArrayList-Typ anstelle des List-Typs deklariert werden. Tatsächlich ist eine Liste, die so unveränderlich ist, dass List <Integer> list = new ArrayList <> (Arrays.asList (1,2,3)); als Redewendung erkannt wird, nicht einfach zu verwenden und wird in eine Variable ArrayList konvertiert. Du machst es. (Ich denke, es hängt von der Anwendung ab ...)

Wenn Sie es in ArrayList wie folgt deklarieren, kann der gesamte Beispielcode von "Try it" das Problem vor der Ausführung als Kompilierungsfehler erkennen. LinkedList usw., die kein Problem haben, verursachen jedoch auch einen Kompilierungsfehler. Ich denke jedoch, dass viele Leute es begrüßen würden, wenn sie zur Kompilierungszeit einen Fehler machen würden, anstatt eine Laufzeitausnahme zu hinterlassen.

Dies scheint jedoch als Problem nicht gut erkannt zu werden. Wahrscheinlich kein großes Problem, da vernünftige Programmierer List mit Vorsicht verwenden, aber es ist in Ordnung, wenn Sie es mit Vorsicht verwenden! Wenn Sie dies tun können, benötigen Sie keine Inspektionsausnahmen oder Nullsicherheit. Persönlich bin ich der Meinung, dass eine unveränderliche Liste, die nur dann eine Ausnahme auslöst, wenn eine bestimmte Methode in Abhängigkeit von der Implementierungsklasse aufgerufen wird, beängstigender als null ist, was leicht durch "list! = Null" bestimmt werden kann.

In Anbetracht der aktuellen Situation, in der das Problem nicht als solches erkannt wird,

ArrayList<String> list = new ArrayList<>();
Iterable<Integer> iterable = getList();
ArrayList<Hoge> hogeList = new ArrayList<>(getList());

Es ist schwer zu sagen, dass das Schreiben wie dieses zu seltsamem Code führt. [^ 1]

Effektives Java empfiehlt außerdem, "ein leeres Array oder eine leere Sammlung anstelle von null zurückzugeben", sodass Sie möglicherweise eine solche Methode geschrieben haben.

public List<String> readFile(String path)
{
	File file = new File(path);
	if(!file.exists())
	{
		return Collections.emptyList();
	}

	List<String> list = new ArrayList<>();
	
	//Prozess zum Lesen von Dateien
	
	return list;
}

Diese Methode kann eine "leere unveränderliche Liste, eine leere veränderbare Liste, eine veränderbare Liste mit Elementen" zurückgeben. Ist das nicht beängstigend?

Zusammenfassung

Die Realisierung der losen Kopplung selbst ist gut. Die Liste von Java ist jedoch schlecht gestaltet. Selbst wenn Sie die List-Schnittstelle verwenden, wird sie nicht lose gekoppelt, und es besteht die Gefahr von Laufzeitausnahmen.

Die Schnittstelle ist ein Versprechen, definierte Methoden zu haben. Schreiben Sie keine vielversprechende Implementierungsklasse.

Implementieren ...! Ich werde es umsetzen ... Diesmal noch die Implementierungsmethode Nicht angegeben </ font>

Bitte auch euch Ich möchte, dass Sie sich an erinnern

Mit anderen Worten ... Wenn wir Lust dazu haben hinzufügen ist Sie können einfach eine UnsupportedOperationException auslösen Es wird möglich sein ...! </ font>

[^ 1]: Übrigens kann der Iterable-Typ den Stream mit StreamSupport.stream (iterable.spliterator (), false); abrufen. Obwohl list.stream () problematisch ist, ist es jedes Mal ...

Recommended Posts