2012-10-17 29 views
12

Trong ổi, có cách hiệu quả để thêm hoặc xóa các mục vào một số ImmutableList (tạo Danh sách mới trong tiến trình).Thêm và xóa các mục vào một danh sách không cần thiết của Guava ImmutableList

Cách đơn giản nhất tôi có thể đưa ra là thế này:

private ImmutableList<String> foos = ImmutableList.of(); 

public void addFoo(final String foo) { 
    if (this.foos.isEmpty()) { 
     foos = ImmutableList.of(foo); 
    } else { 
     foos = ImmutableList.<String>builder().addAll(foos).add(foo).build(); 
    } 
} 

public void removeFoo(final String foo) { 
    final int index = this.foos.indexOf(foo); 
    if (index > -1) { 
     final Builder<String> builder = ImmutableList.<String>builder(); 
     if (index > 0) builder.addAll(this.foos.subList(0, index)); 
     final int size = this.foos.size(); 
     if (index < size - 1) builder.addAll(this.foos.subList(index+1, size)); 
     this.foos = builder.build(); 
    } 
} 

Những gì tôi muốn tránh làm là thế này:

public void removeFoo(final String foo) { 
    final ArrayList<String> tmpList = Lists.newArrayList(this.foos); 
    if(tmpList.remove(foo))this.foos=ImmutableList.copyOf(tmpList); 
} 

Nhưng tiếc là nó là như vậy đơn giản hơn nhiều so với bất kỳ Guava- chỉ có phương pháp tôi có thể nghĩ đến. Tôi đã bỏ lỡ một cái gì đó?

+4

Bạn đang cố giải quyết vấn đề cấp cao hơn nào? Có lẽ bạn không nên đối phó với danh sách bất biến nếu bạn cần thay đổi chúng. – sjr

+0

Tại sao bạn muốn tránh nó? –

+0

Tôi biết tôi có thể giải quyết vấn đề một cách dễ dàng khi sử dụng Danh sách có thể thay đổi được như dữ liệu giữa các chủ sở hữu dữ liệu nhưng a) Tôi phải tạo các bộ sưu tập trung gian thừa và b) Tôi phải trộn bộ sưu tập java.util với guava ImmutableCollections, trong khi tôi muốn gắn với một mô hình. Và tôi muốn sử dụng một ImmutableList vì tôi muốn trao nó cho các máy khách trong phương thức 'getFoos()' mà không mất quyền kiểm soát hoặc phải tạo ra nhiều đối tượng bao bọc Collections.unmodifiableList. –

Trả lời

7

ConcurrentModificationException không thực sự liên quan đến đồng thời và đồng bộ hóa. Truy cập List có thể thay đổi đồng thời có thể làm hỏng và/hoặc ném ngoại lệ (được chuẩn bị cho cả 3 khả năng). Bạn mã không thể thất bại theo cách này, nhưng với đa luồng nó không hoạt động hoặc là:

  • Nếu không đồng bộ và không foosvolatile, không có gì bảo đảm rằng thread khác bao giờ sẽ thấy những thay đổi mà bạn đã thực hiện.
  • Ngay cả với volatile, có thể xảy ra một số thay đổi bị mất, ví dụ: khi hai chủ đề thêm mục vào foos, cả hai có thể bắt đầu bằng giá trị ban đầu và sau đó viết một lần cuối cùng.).

Mã bạn đang cố gắng tránh là không có gì để tránh.

  • "Tôi phải tạo bộ sưu tập trung thừa" - vâng, nhưng không có bữa ăn trưa miễn phí:
    • xác định kích thước của kết quả trước, có nghĩa là một sự lặp lại bổ sung thông qua toàn bộ danh sách
    • hoặc phân bổ một mảng đủ lớn và sao chép phạm vi cần thiết trong danh sách kết quả
    • hoặc phân bổ một mảng đủ lớn và chỉ sử dụng một phần của nó (tiết kiệm thời gian và lãng phí bộ nhớ)
    • hoặc tạo chế độ xem không thay đổi (tiết kiệm cả thời gian và bộ nhớ, nhưng có thể mất thời gian sau)
  • AFAIK Câu trả lời của Frank thực hiện khả năng đầu tiên, tốt nếu vị từ nhanh.
  • "Tôi phải kết hợp bộ sưu tập java.util với ổi ImmutableCollections, trong khi tôi muốn gắn bó với một mô hình." - vâng, nhưng để tắt bộ sưu tập thì cần thu thập bộ sưu tập có thể thay đổi. Các ImmutableList.Builder chỉ bao gồm các trường hợp phổ biến nhất cho phép để xử lý chúng một cách nhỏ gọn.

Bạn có thể muốn xem persistent collections, được tối ưu hóa cho các hoạt động như vậy. Tuy nhiên, bạn không nên mong đợi ví dụ: danh sách liên tục nhanh như ArrayList hoặc ImmutableList.

+0

OK, tôi chưa thêm đồng bộ hóa vào ví dụ trên vì nó đã đủ phức tạp, nhưng sẽ dễ dàng hơn để thêm đồng bộ hóa hơn khi sử dụng ví dụ: Lập danh sách. Vẫn: +1 cho đề xuất bộ sưu tập liên tục. Có lẽ ổi không phải là nơi thích hợp để tìm kiếm chức năng như vậy. –

+1

@SeanPatrickFloyd: Nhóm người Guava từ chối sao chép những thứ hiện có và họ nói rằng bộ sưu tập liên tục [không thực sự phù hợp] (https://groups.google.com/d/msg/guava-discuss/G4E_Hg9GGv0/YFfQf3-AD3IJ). – maaartinus

+0

@maaartinus Tôi có một [câu hỏi] (http://stackoverflow.com/questions/41925494/how-to-keep-retrying-block-machine-every-x-interval-until-url-is-executed-succes) trong đó tôi đang sử dụng ổi thử lại và muốn kiểm tra với bạn nếu mã của tôi là thread an toàn và những gì tôi đang làm là đúng cách? Chưa có câu trả lời nào nên hãy kiểm tra với bạn. – john

13

Bạn có thể loại bỏ bằng cách lọc, mà không tạo ra một trung gian ArrayList hoặc người xây dựng, và chỉ đi qua danh sách một lần:

public void removeFoo(final String foo) { 
    foos = ImmutableList.copyOf(Collections2.filter(foos, 
      Predicates.not(Predicates.equalTo(foo))); 
} 

Để thêm, tôi không thấy một giải pháp tốt hơn.

+0

Tôi đã nghĩ về điều này, tất nhiên (xin lỗi vì không đề cập đến). Vấn đề là: nó loại bỏ mọi sự xuất hiện, trong khi List.remove() chỉ loại bỏ sự xuất hiện đầu tiên, và tôi đang tìm kiếm chức năng đó. Tuy nhiên: +1 –

+0

Sau đó, tôi đoán một trong hai triển khai hiện tại của bạn là tốt như nó được (bạn có thể loại bỏ 'if (index> 0)' và 'if (index

Các vấn đề liên quan