Heim >Java >JavaBase >Notieren Sie die Fallstricke der Java-Sammlungsklassenliste

Notieren Sie die Fallstricke der Java-Sammlungsklassenliste

coldplay.xixi
coldplay.xixinach vorne
2020-12-17 17:16:143117Durchsuche

Java Basic TutorialIn der Spalte wird die Sammlungsklasse vorgestellt, die zwei Hauptkategorien umfasst: Karte und Sammlung

Notieren Sie die Fallstricke der Java-Sammlungsklassenliste

Empfohlen (kostenlos): Java Basic Tutorial

Einige fortgeschrittene Programmiersprachen ​​​​​bietet jetzt verschiedene Implementierungen einer vorgefertigten Datenstruktur, wie z. B. das Sammlungsframework der Programmiersprache Java, mit verschiedenen Implementierungen. Die Sammlungsklasse umfasst zwei Hauptkategorien: Karte und Sammlung Sammlung ist die Sammlungsklasse, die wir häufig verwenden. Erstens sind viele Geschäftscodes untrennbar damit verbunden. Werfen wir heute einen Blick auf einige Fallstricke von List.

Der erste Fallstrick: Die von der Arrays.asList-Methode zurückgegebene Liste unterstützt keine Hinzufügungs- und Löschvorgänge

Wenn wir beispielsweise den folgenden Code ausführen:

List<String> strings = Arrays.asList("m", "g");
strings.add("h");

wird eine java.lang.UnsupportedOperationException ausgelöst Code> Ausnahme. Was geht Ihnen zu diesem Zeitpunkt am Herzen? Warum können der zurückgegebenen ArrayList keine Elemente hinzugefügt werden? Können Elemente in Zukunft ordnungsgemäß hinzugefügt werden? und dann Debug entscheidend aktivieren Dafa: java.lang.UnsupportedOperationException 异常,此时你内心 OS what?明明返回的 ArrayList 为啥不能往里面增加元素,这以后还能好好的增加元素吗?,然后果断开启 Debug 大法:

Notieren Sie die Fallstricke der Java-Sammlungsklassenliste

发现返回的 ArrayList 并不是我们常用的 java.util.ArrayList,而是 Arrays 的内部类 java.util.Arrays.ArrayList。进入方法 Arrays.asList 源码如下:

public static <T> List<T> asList(T... a) {
    return new ArrayList<>(a);
}

方法返回的是 Arrays 的静态内部类 java.util.Arrays.ArrayList,该类虽然和 java.util.ArrayList 也继承自抽象类 java.util.AbstractList ,但是通过该类的源码发现它并没有对抽象父类AbstractListadd 方法默认就是抛出 java.lang.UnsupportedOperationException 异常。

Notieren Sie die Fallstricke der Java-Sammlungsklassenliste

这个坑的根本原因是我们调用返回的 stringsadd 方法是继承自抽象父类的 add 方法,而抽象父类的方法默认就是抛出 java.lang.UnsupportedOperationException 这个异常。

第二个坑,Arrays.asList 方法返回的新 List 和该方法原始入参数组修改会相互影响

Arrays.asList  方法除了上面这个 不支持增加、删除元素 这个坑之外,还有另外一个坑:

Notieren Sie die Fallstricke der Java-Sammlungsklassenliste

从以上代码可以发现,对原始数组的修改会影响我们通过 Arrays.asList方法获得的新 List,深入 java.util.Arrays.ArrayList 的源码:

private static class ArrayList<E> extends AbstractList<E>
        implements RandomAccess, java.io.Serializable
    {
        private static final long serialVersionUID = -2764017481108945198L;
        private final E[] a;

        ArrayList(E[] array) {
            a = Objects.requireNonNull(array);
        }
        
        ...
        
     }

可以发现是直接使用了原始的数组,所有当我们使用 Arrays.asList 方式获得的 List 时要特别注意,因为共享了数组,相互修改时可能产生一些意想不到的 Bug。标准的姿势之一是将其作为 ArrayList 构造方法的参数重新 new 一个 List 出来即可(e.g. List<string> stringList = new ArrayList(Arrays.asList(arrays))</string>)或者通过 Guava 库中的 Lists.newArrayList ,将返回的新 List 和原始的数组解耦,就不会再互相影响了。

第三个坑,直接遍历 List 集合删除元素会报错

在直接遍历集合元素时增加、删除元素会报错,比如执行如下代码:

List<String> stringList = Lists.newArrayList("m", "g", "h");
for (String s : stringList) {
    if (Arrays.asList("m", "h").contains(s)) {
        stringList.remove(s);
    }
}

以上代码可以正常编译通过,但是执行时会抛出 java.util.ConcurrentModificationException 异常,查看其源码可以发现,删除元素方法 remove 会使集合结构发生修改,也就是 modCount(集合实际修改的次数)会修改,在循环过程中,会比较当前 List 的集合实际修改的次数 modCount 与迭代器修改的次数 expectedModCount ,而 expectedModCount 是初始化时的 modCount, 二者不相等,就会报 ConcurrentModificationException 异常。解决方法主要有两种方式,1.使用 ArrayList 的迭代器方式遍历,然后调用其中的方法。2.在 JDK 1.8+ 可以使用 removeIf 方法进行删除操作。

最后扎心一问:调用 ArrayListremove 方法传入 int 基本类型的数字和 Integer

Notieren Sie die Fallstricke der Java-Sammlungsklassenliste🎜🎜 Es wurde festgestellt, dass die zurückgegebene ArrayList nicht unsere häufig verwendete java.util.ArrayList ist, sondern Interne Klasse java.util.Arrays.ArrayList von Arrays. Geben Sie die Methode Arrays.asList ein. Der Quellcode lautet wie folgt: Die Methode 🎜rrreee🎜 gibt die statische interne Klasse java.util.Arrays.ArrayList von Arrays zurück . Obwohl die Klasse und java.util.ArrayList auch von der abstrakten Klasse java.util.AbstractList erben, wird sie über den Quellcode dieser Klasse gefunden dass es keinen Verweis auf die abstrakte übergeordnete Klasse AbstractList hat. Die Methode add löst standardmäßig die Ausnahme java.lang.UnsupportedOperationException aus. 🎜🎜Notieren Sie die Fallstricke der Java-Sammlungsklassenliste. 🎜🎜Das Die Hauptursache für die Falle besteht darin, dass die add-Methode der von unserem Aufruf zurückgegebenen strings von der add-Methode der abstrakten übergeordneten Klasse geerbt wird und die Methode der abstrakten übergeordneten Klasse. Standardmäßig wird die Ausnahme java.lang.UnsupportedOperationException ausgelöst. 🎜🎜Die zweite Gefahr besteht darin, dass sich die neue Liste, die von der Arrays.asList-Methode zurückgegeben wird, und die Änderung der ursprünglichen Parametergruppe der Methode gegenseitig beeinflussen 🎜🎜Arrays.asList-Methode, mit Ausnahme der oben genannten 🎜Tat Das Hinzufügen oder Löschen von Elementen wird nicht unterstützt🎜 Neben dieser Grube gibt es noch eine weitere Grube: 🎜🎜Notieren Sie die Fallstricke der Java-Sammlungsklassenliste🎜🎜Aus dem obigen Code können wir erkennen, dass Änderungen am ursprünglichen Array Auswirkungen auf die neue Liste haben, die wir über die Arrays erhalten. asList-Methode. Gehen Sie tiefer: 🎜rrreee🎜Es kann festgestellt werden, dass das ursprüngliche Array direkt verwendet wird, also wenn wir den Arrays.asList-Methode zum Abrufen der Liste Bitte seien Sie besonders vorsichtig, wenn Sie sich gegenseitig ändern, da Arrays gemeinsam genutzt werden und beim gegenseitigen Ändern einige unerwartete Fehler auftreten können. Eine der Standardaktionen besteht darin, es als Parameter des ArrayList-Konstruktors zu verwenden, um eine Liste zu neu (z. B. List<string stringlist="new" arraylist>(Arrays.asList(arrays))</string>) oder über Lists.newArrayList in der Guava-Bibliothek wird der neue verwendet Der zurückgegebene Code>Liste ist vom ursprünglichen Array entkoppelt und beeinflusst sich nicht mehr gegenseitig. 🎜🎜Die dritte Gefahr besteht darin, dass beim direkten Durchlaufen der Auflistungselemente ein Fehler gemeldet wird. 🎜🎜Beim Hinzufügen oder Löschen von Elementen während der direkten Durchquerung der Auflistungselemente wird beispielsweise ein Fehler gemeldet Der folgende Code: 🎜rrreee🎜Der obige Code kann normal kompiliert werden, aber wenn er ausgeführt wird, tritt eine java.util.ConcurrentModificationException-Ausnahme auf Die Elementmethode remove ändert die Sammlungsstruktur, d. h. modCount( Die tatsächliche Anzahl der Änderungen an der Sammlung) wird während der Schleife geändert zur aktuellen List-Sammlung modCount wird mit der Anzahl der Änderungen am Iterator expectedModCount verglichen, und expectedModCount ist der modCount während der Initialisierung. Wenn die beiden nicht gleich sind, wird eine ConcurrentModificationException-Ausnahme gemeldet. Es gibt zwei Hauptlösungen: 1. Verwenden Sie zum Durchlaufen die Iteratormethode von ArrayList und rufen Sie dann die darin enthaltenen Methoden auf. 2. In JDK 1.8+ können Sie die Methode removeIf verwenden, um Löschvorgänge durchzuführen. 🎜🎜Abschließend noch eine herzzerreißende Frage: Rufen Sie die Methode remove von ArrayList auf und übergeben Sie die Basistypnummer int und Integer Sind die Ausführungsergebnisse der Verpackungstypnummern gleich? 🎜

Das obige ist der detaillierte Inhalt vonNotieren Sie die Fallstricke der Java-Sammlungsklassenliste. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:segmentfault.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen