Sự khác biệt giữa ArrayList.clear () và ArrayList.remove ALL () là gì?


283

Giả sử arraylistđược định nghĩa là ArrayList<String> arraylist, arraylist.removeAll(arraylist)tương đương với arraylist.clear()?

Nếu vậy, tôi có thể giả sử rằng clear()phương thức này hiệu quả hơn để làm trống danh sách mảng không?

Có bất kỳ cảnh báo trong việc sử dụng arraylist.removeAll(arraylist)thay vì arraylist.clear()?


Một hệ quả tất yếu cho câu hỏi này: Khi nào người ta có thể được sử dụng thay vì người khác?
Corey Ogburn

3
@Corey: khi nào thì ai cũng muốn sử dụng arraylist.removeAll(arraylist)? Tôi thấy hoàn toàn không có lý do để làm điều đó.
Joachim Sauer

@Joachim Sauer Đó chính xác là những gì tôi muốn xác minh. Cảm ơn +2. Nhưng sự khác biệt giữa elementData[i] = nulle.remove()đáng kể?
ateiob

Không có lý do lành mạnh để làm arrList.removeAll(arrList)thay vì arrList.clear(). arrList1.removeAll(arrList2)là một vấn đề khác
Vlad

3
Nếu chỉ bắt đầu triển khai removeAll () với dòng này, thì toàn bộ cuộc thảo luận này có thể đã thú vị hơn rất nhiều !!! if (c == this && !isEmpty()) { clear(); return true; }. Tôi sẽ phải gửi bản này cho OpenJDK dưới dạng bản vá! ;-)
Julius Musseau

Câu trả lời:


396

Mã nguồn cho clear():

public void clear() {
    modCount++;

    // Let gc do its work
    for (int i = 0; i < size; i++)
        elementData[i] = null;

    size = 0;
}

Mã nguồn cho removeAll()(Như được định nghĩa trong AbstractCollection):

public boolean removeAll(Collection<?> c) {
    boolean modified = false;
    Iterator<?> e = iterator();
    while (e.hasNext()) {
        if (c.contains(e.next())) {
            e.remove();
            modified = true;
        }
    }
    return modified;
}

clear() nhanh hơn nhiều vì nó không phải xử lý tất cả các cuộc gọi phương thức bổ sung đó.

Và như Atrey chỉ ra, c.contains(..)làm tăng độ phức tạp thời gian của removeAllO (n 2 ) so với clearO (n).


29
Một lưu ý rằng c.contains(...)bình phương độ phức tạp thời gian của hoạt động sẽ làm cho câu trả lời này hoàn thành.
Atreys

8
Nguồn này là mạnh mẽ trong cái này. (Đối với tất cả các câu trả lời khác: Sử dụng nguồn, Luke.) Lưu ý cách rõ ràng () có thể được thực hiện như chỉ một dòng, size = 0; nhưng bộ sưu tập rác sẽ không biết thu thập các phần tử trong các phần không thể truy cập của mảng.
Julius Musseau

2
e.remove () là cách phức tạp hơn! e.remove () cũng bình phương độ phức tạp, giống như c.contains (...). Trên một ArrayList, e.remove () gọi ArrayList.remove (int index), phải thay đổi phần còn lại của mảng qua một.
Julius Musseau

1
@ateiob e.remove () là hai cuộc gọi phương thức bổ sung, kiểm tra phạm vi và trả về đối tượng (nội bộ AbstractList.Itr.remove()ArrayList.remove(int)),
Atreys

2
@julius Nếu nó đã làm điều này: size = 0; elementData = new Object[10];tất cả phần còn lại sẽ là rác được thu thập, vì mảng sao lưu không có tham chiếu bên ngoài.
corsiKa

51

Sự phức tạp của thời gian ArrayList.clear()O(n)removeAllO(n^2).

Vì vậy, có, ArrayList.clearlà nhanh hơn nhiều.


15

Các clear()phương pháp loại bỏ tất cả các yếu tố của một single ArrayList. Đây là một hoạt động nhanh, vì nó chỉ đặt các phần tử mảng thành null.

Các removeAll(Collection)phương pháp, được thừa hưởng từ AbstractCollection, loại bỏ tất cả các yếu tố có trong bộ sưu tập tranh luận từ bộ sưu tập bạn gọi phương thức trên. Đây là một hoạt động tương đối chậm, vì nó phải tìm kiếm thông qua một trong các bộ sưu tập liên quan.


Tôi nghĩ rằng nó chỉ đặt tất cả, không phải là một số yếu tố thành null. Nếu không phải như vậy, làm thế nào nó quyết định thành phần nào nên được đặt thành null?
Farid

2
@Farid xin lỗi, tiếng Anh của tôi quá không chính thức ở đây. Tôi thực sự có nghĩa là nó đặt tất cả các yếu tố thành null. Tôi sẽ sửa chữa nó!
Ernest Friedman-Hill

7

Trừ khi có một tối ưu hóa cụ thể để kiểm tra xem đối số được truyền vào có phải removeAll()là chính bộ sưu tập không (và tôi rất nghi ngờ rằng có tối ưu hóa như vậy), nó sẽ chậm hơn đáng kể so với đơn giản .clear().

Ngoài ra (và ít nhất là quan trọng như nhau): arraylist.removeAll(arraylist)chỉ là mã khó hiểu, khó hiểu. Đó là một cách rất ngược để nói "xóa bộ sưu tập này". Lợi thế nào nó sẽ có hơn rất dễ hiểu arraylist.clear() ?


7

Họ phục vụ các mục đích khác nhau. clear()xóa một thể hiện của lớp, removeAll()loại bỏ tất cả các đối tượng đã cho và trả về trạng thái của hoạt động.


bạn có thể vui lòng cung cấp một tài nguyên để đọc về vấn đề trên để tham khảo thêm không
Kasun Siyambalapitiya

1
@KasunSiyambalapitiya Làm thế nào về câu trả lời được chấp nhận , trong đó có chứa mã nguồn cho hai?
Abdul

5

clear() sẽ đi qua Mảng cơ bản và đặt từng mục thành null;

removeAll(collection)sẽ đi qua kiểm tra ArrayList cho bộ sưu tập và remove(Object)nó nếu nó tồn tại.

Tôi sẽ tưởng tượng rằng đó clear()là cách nhanh hơn sau đó loại bỏ Tất cả vì nó không so sánh, v.v.


2

Xóa nhanh hơn vì nó không lặp qua các phần tử cần xóa. Phương pháp này có thể giả định rằng TẤT CẢ các yếu tố có thể bị xóa.

Remove allkhông nhất thiết có nghĩa là xóa tất cả các thành phần trong danh sách, chỉ những phần tử được cung cấp làm tham số NÊN được xóa. Do đó, cần nhiều nỗ lực hơn để giữ những thứ không nên xóa.

LÀM RÕ

Theo 'vòng lặp', tôi có nghĩa là nó không phải kiểm tra xem phần tử có nên được giữ hay không. Nó có thể đặt tham chiếu đến nullmà không cần tìm kiếm thông qua danh sách các yếu tố được cung cấp để xóa.

ClearIS nhanh hơn deleteall.


1
Tôi khá chắc chắn rằng nó ArrayList.clear()cũng phải lặp đi lặp lại.
Joachim Sauer

@JVerstry Bạn có nghĩa là Clear () không xóa các phần tử mà nó xóa khỏi ArrayList?
ateiob

1
Sai, xóa không lặp trên mảng bên trong và đặt tất cả các tham chiếu thành null để cho phép trình thu gom rác thực hiện công việc của nó.
devconsole

1
@Joachim, @devconsole: Tôi nghĩ rằng anh ta có nghĩa là nó sẽ không phải lặp / lặp qua danh sách được cung cấp dưới dạng tham số. target.removeAll(param)sẽ lặp đi lặp lại paramvà sau đó gọi target.contains(...)mà lặp đi lặp lại target.
Vlad

2
-3 là một chút khắc nghiệt. Nếu JVerstry muốn, anh ta có thể viết triển khai Java của riêng mình từ đầu mà không lặp. Clear () thể được triển khai một cách khả thi trong O (1), không có vòng lặp, trong khi remove ALL () PHẢI có một số loại thuật toán O (n), không có cách nào để thỏa mãn hợp đồng API removeAll () mà không kiểm tra tất cả các yếu tố.
Julius Musseau

1

rõ ràng () sẽ hiệu quả hơn nhiều. Nó sẽ chỉ đơn giản là loại bỏ từng mục. Sử dụng removeAll (danh sách mảng) sẽ tốn nhiều công sức hơn vì nó sẽ kiểm tra mọi mục trong danh sách mảng để xem liệu nó có tồn tại trong danh sách mảng hay không trước khi xóa nó.


-8

Mảng => một khi không gian được phân bổ cho một biến Array tại thời điểm chạy, không gian được phân bổ không thể được mở rộng hoặc loại bỏ.

ArrayList => Đây không phải là trường hợp trong danh sách mảng. ArrayList có thể phát triển và thu hẹp tại thời điểm chạy. Không gian được phân bổ có thể được thu nhỏ hoặc tối đa hóa tại thời điểm chạy.


Điều này không trả lời câu hỏi nào là sự khác biệt giữa ArrayList.clear () và ArrayList.removeAll (), không phải là sự khác biệt giữa Array và ArrayList.
Pierre

Câu trả lời này là không cần thiết. Đó không phải là những gì câu hỏi về.
Serafim Costa
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.