2012-04-03 44 views
5

Gần đây tôi có cần phải thực hiện trường hợp 'trường hợp đặc biệt' nếu chỉ có một phần tử trong bộ sưu tập. Kiểm tra ...size() == 1 và lấy bằng ...iterator.next() trông có vẻ xấu xí vì vậy tôi đã tạo ra hai phương pháp trong nhà brew Collections lớp:Kiểm tra xem chỉ có một phần tử tồn tại bằng cách sử dụng Guava

public class Collections { 
    public static <T> boolean isSingleValue(Collection<T> values) { 
     return values.size() == 1; 
    } 

    public static <T> T singleValue(Collection<T> values) { 
     Assert.isTrue(isSingleValue(values)); 
     return values.iterator().next(); 
    } 
} 

Vài ngày trước, tôi phát hiện ra rằng ổi có phương pháp gọi là Iterables.getOnlyElement. Nó bao gồm nhu cầu của tôi và thay thế singleValue, nhưng tôi không thể tìm thấy kết quả phù hợp cho isSingleValue. Đó có phải là do thiết kế? Có đáng để đặt yêu cầu tính năng để có phương thức Iterables.isOnlyElement không?

CHỈNH SỬA: Vì có vài upvotes tôi quyết định mở nâng cao trên ổi - issue 957. Độ phân giải cuối cùng - 'WontFix'. Các lập luận rất giống với những gì Thomas/Xaerxess cung cấp.

Trả lời

10

Vâng, bạn sẽ không đạt được nhiều bằng cách thay thế values.size() == 1 bằng một phương pháp, ngoại trừ bạn có thể kiểm tra giá trị rỗng. Tuy nhiên, có những phương pháp trong Bộ sưu tập Apache Commons (cũng như trong ổi, tôi giả định) để làm điều đó.

Tôi thà viết if(values.size() == 1) hoặc if(SomeHelper.size(values) == 1)
hơn if(SomeHelper.isSingleValue(values)) - mục đích là rõ ràng hơn nhiều trong hai phương pháp đầu tiên và nó càng nhiều mã để viết như với cách tiếp cận thứ ba.

6

Chỉ cần thêm vào câu trả lời khác (tôi sẽ viết một cái gì đó giống như @daveb người xóa một mình: Nếu không có đúng một phần tử, sau đó Iterables#getOnlyElement sẽ ném một IllegalArgumentException hoặc NoSuchElementException) - một câu trả lời cho câu hỏi tại sao không có bất kỳ Iterables.isSingleValue(Iterable) trong ổi.

Tôi nghĩ bạn đang làm sai điều này. Nếu:

  • phương pháp invokation không thay đổi trạng thái (không giống như next() trong iterator, đó là lý do tại sao hasNext() tồn tại)
  • và bạn rõ ràng và exlicitly có thể nói rằng giá trị trả về không phải là trường hợp ngoại lệ (không giống như null trở về từ Map#get(Object) - nó có thể là giá trị null hoặc nó có thể có nghĩa là khóa đó không được tìm thấy trong bản đồ)

không cần kiểm tra phương pháp nếu điều kiện là đúng và sau đó thực hiện một số thao tác (với xác nhận trong đó!) như trong mã mẫu của bạn.

Nếu bạn hoàn toàn chắc chắn rằng có thể lặp lại tại địa điểm này không thể có kích thước khác 1, hơn kiểm tra điều kiện là dự phòng (trường hợp ngoại lệ được ném trong các trường hợp khác).
Nếu bạn chỉ muốn lấy phần tử đầu tiên trong bộ sưu tập không trống - collection.iterator.next() là hoàn toàn OK (NoSuchElementException bị ném nếu bộ sưu tập trống).
Nếu bạn không biết gì về kích thước của bộ sưu tập hơn Iterables.getFirst(iterable, default) là dành cho bạn.

P.S. Nếu Collections#isSingleValue của bạn chỉ được sử dụng cục bộ tại đây (do đó có thể là riêng tư) thực sự có nghĩa là bạn không cần séc đó trước khi gọi Iterables#getOnlyValue.

P.P.S.Một câu trả lời khác cho câu hỏi của bạn về thiết kế của Guava có thể là Item 57 của Joshua Bloch Hiệu quả Java - có rất ít phương pháp trợ giúp khác nhau trong ổi mà tôi đã đề cập trước đó, một cách rõ ràng nói trường hợp ngoại lệ là gì; kiểm tra boolean đã không được thêm vào bởi vì giữ API càng nhỏ càng tốt.

0

Hiện tại tôi đang gặp vấn đề tương tự.

tôi sẽ giải quyết với mã này:

public static <T> void hasJustOne(T... values) { 
    hasJustOne(Predicates.notNull(), values); 
} 

public static <T> void hasJustOne(Predicate<T> predicate, T... values) { 
    Collection<T> filtred = Collections2.filter(Arrays.asList(values),predicate); 
    Preconditions.checkArgument(filtred.size() == 1); 
} 
+0

Đây không phải là rõ ràng, những gì "Tôi sẽ để giải quyết" nghĩa là gì? Bạn đang nói rằng đây là một giải pháp, hoặc rằng bạn đang làm việc về vấn đề này? –

+0

Đây là giải pháp, đối với tôi. – Falci

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