Java集合元素ArrayList刪除某一項問題及ArrayList總結歸納

Java中的集合框架ArrayList是我們最常用的一個類,ArrayList實現了List接口,可以重複存儲數據,可以動態的增加和刪除元素,下面介紹一下在刪除ArrayList元素問題。

ArrayList實現了List接口,內部通過Object類型的數組有序存儲數據(可重複),並且能夠根據元素數量進行擴容,實現了動態的增加和減少元素.

1.常用方法
增加元素
add()

addAll()

移除元素
remove()

removeAll()

clear()
是否包含指定元素

contains()

containsAll()

元素個數
size()

是否爲空
isEmpty()
是否爲同一個ArrayList
equals()
創建迭代器
iterator()
將元素返回指定數組
toArray()

2、關於遍歷

public class ArrayListDemo2 {  



    public static void main(String[] args) {  



        ArrayList<Integer> list = new ArrayList<>();  

        list.add(23);  

        list.add(33);  

        list.add(64);  

        list.add(33);  

        list.add(54);  

        list.add(89);  



        // 重寫了toString方法,直接打印輸出  

        System.out.println(list);  



        // 通過for循環遍歷  

        for (int i = 0, j = list.size(); i < j; i++) {  

            System.out.println(list.get(i));  

        }  



        // 通過for each遍歷  

        for (int value : list) {  

            System.out.println(value);  

        }  



        // 通過迭代器遍歷  

        Iterator<Integer> car = list.iterator();  

        while (car.hasNext()) {  

            int value = car.next();  

            System.out.println(value);  

        }  

    }  

}  

3.關於刪除

public class ArrayListDemo3 {  



    public static void main(String[] args) {  



        ArrayList<String> list = new ArrayList<>();  

        String str1 = new String("Hello");  

        String str2 = new String("Hello");  

        list.add(str1);  

        System.out.println(list.size());  

        list.remove(str2);  

        System.out.println(list.size());  

    }  

}  

運行結果:

1

0

雖然str1和str2是兩個String對象,但是list中的元素被移除了.實際上remove方法內部是通過equals方法判斷是否是同一個元素,我們用下面的代碼驗證:

public class ArrayListDemo3 {  



    public static void main(String[] args) {  



        ArrayList<Person> list = new ArrayList<>();  

        Person p1 = new Person("Hello");  

        Person p2 = new Person("World");  

        list.add(p1);  

        System.out.println(list.size());  

        list.remove(p2);  

        System.out.println(list.size());  

    }  

}  



class Person {  

    String name;  

    public Person(String name) {  

        this.name = name;  

    }  

    @Override  

    public boolean equals(Object o) {  

        System.out.println("我被執行了");  

        return true;  

    }  

}  

運行結果:

1

我被執行了

0

4.關於刪除
我們利用一個ArrayList來存儲分數,現在希望將60分以下的刪除:

public class ArrayListDemo4 {  



    public static void main(String[] args) throws Exception {  



        ArrayList<Integer> list = new ArrayList<>();  

        list.add(80);  

        list.add(54);  

        list.add(68);  

        list.add(72);  

        list.add(49);  

        list.add(51);  

        list.add(98);  

        list.add(77);  

        list.add(43);  

        list.add(50);  



        for (int i = 0; i < list.size(); i++) {  

            if (list.get(i) < 60) {  

                list.remove(i);  

            }  

        }  



        for (int value : list) {  

            System.out.println(value);  

        }  

    }  

}  

 運行結果:

80

68

72

51

98

77

50

爲什麼5150沒有for (int i = list.size() - 1; i >= 0; i--) {  

    if (list.get(i) < 60) {  

        list.remove(i);  

    }  

}  

運行結果:

80
68
72
98
77刪掉呢?實際上,ArrayList在每次刪除一個元素後,後面的元素會向前移動補位.在上述程序中,當我們刪除49後,後面的元素向前補位,下一次循環時索引加1,便跳過了51.解決方法:for循環從ArrayList尾部向前遍歷. 

5.關於刪除
在上一節中,我們能不能通過for each和Iterator進行操作呢?

// for each循環  

for (int value : list) {  

    if (value < 60) {  

        list.remove(new Integer(value));  

    }  

}  

// 迭代器  

Iterator<Integer> car = list.iterator();  

while (car.hasNext()) {  

    int value = car.next();  

    if (value < 60) {  

        list.remove(new Integer(value));  

    }  

}  

兩段代碼的運行結果一樣:java.util.ConcurrentModificationException.拋出了併發修改異常,所以當for each和iterator對一個ArrayList進行迭代時,需保證這個ArrayList不能改變,
因爲ArrayList是非線程安全的.但是
1、Iterato提供了一個remove方法,可以對ArrayList中的元素進行刪除,
2、還可以使用參考Arraylist來達到刪除效果,
3、也可使用CopyOnWriteArrayList支持併發訪問.即:

Java代碼
a、

Iterator<Integer> car = list.iterator();  

while (car.hasNext()) {  

    int value = car.next();  

    if (value < 60) {  

        car.remove();  

    }  

}  

運行結果:  
80
68
72
98
77

b、

 private void referenceRemoveMethod(List<bean> list)
    {
        List<bean> referenceList = new ArrayList<bean>();
        referenceList.addAll(list);

        for (int i = 0; i < referenceList.size(); i++)
        {
            if (referenceList.get(i).getName().equals("A"))
            {
                list.remove(referenceList.get(i));
            }
        }
    }

6.關於擴容
每一個ArrayList都有一個容量,即數組Object[] elementData的長度.利用無參構造函數創建一個ArrayList時,會使用默認容量10.當我們向其中不斷地增加元素超過容量時,ArrayList會進行擴容.ArrayList的擴容原理:新建一個Object類型的數組,長度爲原數組長度*3/2,然後將就數組的值賦給新數組,使elementData指向新數組.通過反射進行驗證:

public class ArrayListDemo6 {  



    public static void main(String[] args) throws Exception {  



        ArrayList<Integer> list = new ArrayList<>();  

        Class c = Class.forName("java.util.ArrayList");  

        Field f = c.getDeclaredField("elementData");  

        f.setAccessible(true);  

        Object[] data = null;  



        // 向list中添加50個元素,輸出每次ElementData的長度  

        for (int i = 1; i <= 50; i++) {  

            list.add(i);  

            data = (Object[]) f.get(list);  

            System.out.print(data.length + "\t");  

            if (i % 10 == 0) {  

                System.out.println();  

            }  

        }  

    }  

}  

 運行結果:

10 10 10 10 10 10 10 10 10 10 
15 15 15 15 15 22 22 22 22 22 
22 22 33 33 33 33 33 33 33 33 
33 33 33 49 49 49 49 49 49 49 
49 49 49 49 49 49 49 49 49 73

如果我們已知要存儲數據的容量,儘量在創建ArrayList時爲其指定容量,避免其多次擴容而降低性能.另外,ArrayList中還爲我們提供了兩個針對於控制容量的方法:

trimToSize() 將elementData的長度修整爲當前元素個數
ensureCapacity() 設置當前ArrayList容量

7.關於最大容量
在ArrayList中,還有一個靜態常量MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8,用來限制當前ArrayList的最大容量(理論上可以達到Integer.MAX_VALUE).在每次進行擴容時,會用一個int型數據來存儲新的容量:int newCapacity = oldCapacity + (oldCapacity >> 1);當ArrayList中的元素達到MAX_ARRAY_SIZE後再次擴充時,newCapacity經過擴容算法會溢出,導致符號位由0變1,變成負值.ArrayList中的hugeCapacity方法通過判斷newCapacity是否發生溢出,關鍵代碼:

private static int hugeCapacity(int minCapacity) {  

    if (minCapacity < 0)  

        throw new OutOfMemoryError();  

    return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE  

            : MAX_ARRAY_SIZE;  

}  

所以,當ArrayList達到極限容量時,再次擴容會拋出異常.

8.1.8版本新特性
JDK在SE1.8中新增了stream包,並且在Collection中增加了stream()方法,利用其特性我們可以用來進行過濾以及排序等.

public class ArrayListDemo8 {  



    public static void main(String[] args) {  

        ArrayList<Integer> list = new ArrayList<>();  

        Collections.addAll(list, 95, 34, 67, 89, 23, 79, 66, 12, 98);  

        list.stream().filter(e -> e > 60).sorted((i1, i2) -> i1 - i2).forEach(System.out::println);  

    }  

}  

上述代碼執行功能:過濾掉60及以下的分數→排序→打印輸出.
運行結果:
66
67
79
89
95
98

9.List的其他實現類
1)Vector

Vector是早期的collection,與ArrayList的區別主要有兩點:線程安全,擴容方式*2.

2)LinkedList

雙向循環鏈表,內部元素不是通過數組存儲的.而是把每一個元素封裝Node,每一個Node有三個屬性:

E item; 元素本身
Node next; 指向後一個Node
Node prev; 指向前一個Node
而LinkedList本身只包含兩個Node類型的屬性first和last,通過Node使元素形成鏈表,並且是雙向的,實現邏輯上的地址連續.在進行插入和刪除功能時,性能要優於ArrayList.

3)Stack

對象堆棧.遵循LIFO(Last In First Out)原則,常用方法:

empty() 測試堆棧是否爲空
peek() 查看堆棧頂部的對象,但不移除
pop() 移除堆棧頂部的對象,並返回該對象
push() 把對象壓入堆棧頂部
search() 返回對象在堆棧中的位置,以1爲基數

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章