2014-11-25 17 views
11

Tôi mới để lập trình chức năng trong java, và tự hỏi làm thế nào tôi nên mã hóa để tránh NPE trong (ví dụ) hoạt động này:.gọi suối() giảm() trên một danh sách với chỉ có một yếu tố

myList.stream() 
     .reduce((prev, curr) -> prev.getTimestamp().isAfter(curr.getTimestamp()) ? prev : curr); 
     .get().getTimestamp(); 

Mục đích của tôi ở đây là tìm dấu thời gian của đối tượng mới nhất trong danh sách. Gợi ý về cách thu thập phần tử cuối cùng tốt hơn là rất đáng hoan nghênh, nhưng câu hỏi chính của tôi ở đây thực sự là lý do tại sao nó hoạt động.

Các tài liệu nói rằng chức năng ném một NullPointerException "nếu kết quả của việc giảm là null":

http://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#reduce-java.util.function.BinaryOperator-

Đó là OK, nhưng những gì tôi không hoàn toàn hiểu là tại sao tôi don' t nhận được một NullPointerException khi mã này được chạy với một danh sách chỉ chứa một phần tử. Tôi mong đợi prev là vô giá trị trong trường hợp này. Tôi đã thử gỡ lỗi, nhưng nó dường như chỉ bước qua toàn bộ biểu thức lambda khi chỉ có một phần tử.

Trả lời

15

Như javadoc của reduce nói, giảm tương đương với:

boolean foundAny = false; 
T result = null; 
for (T element : this stream) { 
    if (!foundAny) { 
     foundAny = true; 
     result = element; 
    } 
    else 
     result = accumulator.apply(result, element); 
} 
return foundAny ? Optional.of(result) : Optional.empty(); 

Do đó, nếu Stream có một yếu tố duy nhất, chỉ có một lần lặp của vòng lặp, và các yếu tố duy nhất được tìm thấy trong lần lặp mà Được trả lại.

BinaryOperator sẽ chỉ được áp dụng nếu Stream có ít nhất hai phần tử.

1

NPE sẽ bị hủy nếu thao tác giảm thực tế dẫn đến giá trị null. Ví dụ: nếu bạn cố gắng làm stream.reduce((a,b) -> null).

Ngày lưu ý khác, để tìm dấu thời gian mới nhất, bạn có thể làm điều này:

myList.stream() 
    .map(t -> t.getTimeStamp()) 
    .max(Comparator.naturalOrder() 
    .get(); // will throw an exception if stream is empty 

Hoặc, với nhập khẩu tĩnh và giả định lớp học của bạn được gọi là Thing:

myList.stream().map(Thing::getTimeStamp).max(naturalOrder()).get(); 
+0

Lưu ý rằng thao tác này sẽ chỉ trả lại dấu thời gian mới nhất chứ không phải đối tượng có dấu thời gian mới nhất. – skiwi

+0

Cảm ơn, tôi biết điều đó và dấu thời gian là những gì tôi muốn. – aweibell

5

tốt hơn:

Optional<Thingie> max = 
     myList.stream() 
      .reduce(BinaryOperator.maxBy(comparing(Thingie::getTimeStamp)); 

Quá tải này reduce() trả về tùy chọn; một cách mù quáng giải nén nó với get là nguy hiểm, và rủi ro ném NSEE. Giải nén nó bằng một trong những nhà khai thác an toàn như orElse hoặc orElseThrow.

Nếu có cơ hội có số không trong luồng của bạn, hãy lọc trước tiên bằng .filter(t -> t != null).

+0

Cảm ơn. Tôi đã kiểm tra xem luồng có trống không và không nghĩ rằng có thể có các phần tử rỗng, nhưng tôi đoán cách tiếp cận của bạn sẽ luôn tốt hơn. Tôi sẽ xem xét nó vào ngày mai. – aweibell

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