Tại sao Stream.allMatch () trả về true cho một luồng trống?


84

Đồng nghiệp của tôi và tôi đã gặp lỗi do chúng tôi cho rằng một cuộc gọi luồng trống allMatch()sẽ quay trở lại false.

if (myItems.allMatch(i -> i.isValid()) { 
    //do something
}

Tất nhiên, đó là lỗi của chúng tôi khi giả sử và không đọc tài liệu. Nhưng điều tôi không hiểu là tại sao allMatch()hành vi mặc định cho một luồng trống lại trả về true. Lý do cho điều này là gì? Giống như anyMatch()(trái ngược với trả về false), thao tác này được sử dụng theo cách bắt buộc rời khỏi đơn nguyên và có thể được sử dụng trong một ifcâu lệnh. Xem xét những thực tế đó, có lý do gì tại sao việc allMatch()mặc định truetrên một luồng trống lại được mong muốn cho phần lớn các mục đích sử dụng?


4
Đó là một chút kỳ lạ. Chúng tôi mong đợi rằng nếu allMatchtrả về true thì đúng như vậy anyMatch. Ngoài ra, đối với trường hợp trống, allMatch(...) == noneMatch(...)điều này cũng rất lạ.
Radiodef


Chỉ cần nói sơ qua về cú pháp: thay vì viết vị ngữ của bạn là i -> i.isValid(), bạn có thể viết Foo::isValid(tất nhiên Foolà bạn đang phát trực tuyến ở đâu)
MattPutnam

2
"Hoạt động này được sử dụng theo cách bắt buộc phải rời khỏi đơn nguyên" - Tôi nghi ngờ yếu tố này vào bất kỳ quyết định nào.
user253751

Câu trả lời:


115

Đây được gọi là sự thật trống rỗng . Tất cả các thành viên của bộ sưu tập trống đều đáp ứng điều kiện của bạn; Rốt cuộc, bạn có thể chỉ ra một cái không?

Tương tự, anyMatchtrả về false, bởi vì bạn không thể tìm thấy một phần tử trong bộ sưu tập của mình phù hợp với điều kiện. Điều này gây nhầm lẫn cho rất nhiều người, nhưng nó lại là cách hữu ích và nhất quán nhất để xác định "bất kỳ" và "tất cả" cho các tập hợp trống.


3
Geez, tôi ghét logic boolean. Tôi nghĩ rằng tôi hiểu những gì bạn đang nói. Sự vắng mặt của phủ định là một tích cực, nhưng thiếu tích cực không phải là tiêu cực.
tmn

13
@ThomasN. Theo cách tương tự, giá trị của tích của một tập hợp số trống là 1trong khi tổng của một tập hợp số rỗng là 0. Chúng là các yếu tố trung lập cho phép nhân / phép cộng. Trong trường hợp các phép toán luận bạn đã có True and x = xFalse or x = xvì thế nếu bạn khái quát andorđể chuỗi (đó là những gì allanyđang) bạn kết thúc với TrueFalseđối với trường hợp rỗng, tức là họ yếu tố trung lập tương ứng.
Bakuriu

9
@ThomasN. anyMatchkiểm tra sự không có dương tính, allMatchthử nghiệm về sự không có âm tính.
user253751

3
Lưu ý rằng bằng cách này, bạn có thể thực hiện những điều tốt đẹp như định luật De Morgan: stream.allMatch (vị từ) cũng giống như! Stream.anyMatch (predicate.negate ()). Tương tự,! Stream.allMatch (predicate.negate ()) cũng giống như stream.anyMatch (vị từ).
Hans

1
@PatrickBard: Bạn có thể nói "bạn có thể chỉ vào một cái đó không", và điều đó hoàn toàn hợp lệ , nhưng điều đó có nghĩa là tất cả các thành viên của bộ sưu tập không thỏa mãn điều kiện. Tất cả các thành viên của bộ sưu tập đáp ứng điều kiện, và tất cả các thành viên của bộ sưu tập không đáp ứng điều kiện. Đây là những tuyên bố khác với "sai khi tất cả các thành viên của tập hợp thỏa mãn điều kiện". Như tôi đã nói, thật khó hiểu.
user2357112 hỗ trợ Monica

10

Đây là một cách khác để nghĩ về điều này:

allMatch()&&những gì sum()+

Hãy xem xét các phát biểu hợp lý sau:

IntStream.of(1, 2).sum() + 3 == IntStream.of(1, 2, 3).sum()
IntStream.of(1).sum() + 2 == IntStream.of(1, 2).sum()

Điều này có ý nghĩa bởi vì sum()chỉ là một khái quát của +. Tuy nhiên, điều gì sẽ xảy ra khi bạn loại bỏ thêm một phần tử nữa?

IntStream.of().sum() + 1 == IntStream.of(1).sum()

Chúng ta có thể thấy rằng việc xác định IntStream.of().sum(), hoặc tổng của một dãy số rỗng, theo một cách cụ thể là rất hợp lý. Điều này cung cấp cho chúng tôi "yếu tố nhận dạng" của tổng kết, hoặc giá trị mà khi được thêm vào một cái gì đó, không có tác dụng ( 0).

Chúng ta có thể áp dụng logic tương tự cho Booleanđại số.

Stream.of(true, true).allMatch(it -> it) == Stream.of(true).allMatch(it -> it) && true

Nói chung hơn:

stream.concat(Stream.of(thing)).allMatch(it -> it) == stream.allMatch(it -> it) && thing

Nếu stream = Stream.of()sau đó quy tắc này vẫn cần áp dụng. Chúng ta có thể sử dụng "yếu tố nhận dạng" của && để giải quyết vấn đề này. true && thing == thing, vì vậy Stream.of().allMatch(it -> it) == true.


6

Khi tôi gọi list.allMatch(hoặc các từ tương tự của nó bằng các ngôn ngữ khác), tôi muốn phát hiện xem có mục nào listkhông khớp với vị từ hay không. Nếu không có mục nào, không có mục nào có thể không khớp. Logic sau đây của tôi sẽ chọn các mục và mong đợi chúng khớp với vị từ. Đối với một danh sách trống, tôi sẽ không chọn mục nào và logic vẫn sẽ ổn.

Điều gì sẽ xảy ra nếu allMatchtrả về falsecho một danh sách trống?

Logic đơn giản của tôi sẽ thất bại:

 if (!myList.allMatch(predicate)) {
   throw new InvalidDataException("Some of the items failed to match!");
 }
 for (Item item : myList) { ... }

Tôi cần nhớ thay séc bằng !myList.empty() && !myList.allMatch().

Tóm allMatchlại , việc trả về truecho một danh sách trống không chỉ hợp lý về mặt logic, mà nó còn nằm trên con đường thực thi tốt, yêu cầu ít kiểm tra hơn.


có thể bạn muốn nóiif (!allMatch)
assylias

3

Có vẻ như cơ sở của nó là quy nạp toán học. Đối với khoa học máy tính, một ứng dụng của điều này có thể là một trường hợp cơ bản của một thuật toán đệ quy.

Nếu luồng trống, định lượng được cho là thỏa mãn trống và luôn đúng. Oracle Docs: Luồng hoạt động và đường ống

Mấu chốt ở đây là nó được "thỏa mãn trống rỗng", về bản chất, có phần sai lệch. Wikipedia có một cuộc thảo luận khá về nó.

Trong toán học thuần túy, các phát biểu đúng sai thường không được quan tâm, nhưng chúng thường xuất hiện như trường hợp cơ bản của chứng minh bằng quy nạp toán học. Wikipedia: Sự thật trống rỗng


1

Mặc dù câu hỏi này đã được trả lời chính xác nhân số lần, tôi muốn đưa ra một cách tiếp cận toán học hơn.

Vì vậy, tôi muốn coi luồng như một Tập hợp (theo nghĩa toán học). Sau đó

emptyStream.allMatch(x-> p(x))

tương ứng với nhập mô tả hình ảnh ở đâytrong khi

emtpyStream.anyMatch(x -> p(x))

tương ứng với nhập mô tả hình ảnh ở đây.

Rằng phần thứ hai là sai là khá rõ ràng vì không có phần tử nào trong tập hợp trống. Đầu tiên là một chút khó khăn hơn. Bạn có thể chấp nhận nó là đúng theo định nghĩa hoặc xem xét các câu trả lời khác để biết một số lý do tại sao nó phải như vậy.

Một ví dụ để minh họa sự khác biệt này là các mệnh đề như "Tất cả con người sống trên sao Hỏa đều có 3 chân" (đúng) và "Có một người sống trên sao Hỏa có 3 chân" (sai)

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.