這三個方法也是非常簡單 anyMatch、allMatch 、 noneMatch 方法的簽名如下:
boolean anyMatch(Predicate<? super T> predicate)
boolean allMatch(Predicate<? super T> predicate)
boolean noneMatch(Predicate<? super T> predicate)
直接來看幾個例子:
public class Primes {
public boolean isPrime(int num) {
int limit = (int) (Math.sqrt(num) + 1);
return num == 2 || num > 1 && IntStream.range(2, limit)
.noneMatch(divisor -> num % divisor == 0);
}
}
IntStream.of(2, 3, 5, 7, 11, 13, 17, 19)
.allMatch(calculator::isPrime)); //true
Stream.of(4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20)
.anyMatch(calculator::isPrime));// false
如果是空的串流,對於 allMatch、noneMatch 都是 true:
Stream.empty().allMatch(e -> false); //true
Stream.empty().noneMatch(e -> true); //true
Stream.empty().anyMatch(e -> true); //false
先看這兩個方法的簽章
<R> Stream<R> map(Function<? super T,? extends R> mapper)
<R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper)
map 沒啥問題,已經用很多了,flatMap 主要用在串流物件裡面還有 nested object list 的時候,我們可以利用 flatMap 一次拿到所有串流物件的 nested object list ,是個實用的方法
public class Customer {
private String name;
private List<Order> orders = new ArrayList<>();
public Customer(String name) {
this.name = name;
}
public String getName() { return name; }
public List<Order> getOrders() { return orders; }
public Customer addOrder(Order order) {
orders.add(order);
return this;
}
}
public class Order {
private int id;
public Order(int id) {
this.id = id;
}
public int getId() { return id; }
}
//init data
Customer sheridan = new Customer("Sheridan");
Customer ivanova = new Customer("Ivanova");
Customer garibaldi = new Customer("Garibaldi");
sheridan.addOrder(new Order(1))
.addOrder(new Order(2))
.addOrder(new Order(3));
ivanova.addOrder(new Order(4))
.addOrder(new Order(5));
List<Customer> customers = Arrays.asList(sheridan, ivanova, garibaldi);
Stream<List<Order>> streamListOrders
= customers.stream()
.map(customer -> customer.getOrders().stream());
streamListOrders.forEach(System.out::println);
Stream<Order> streamOrders
= customers.stream()
.flatMap(customer -> customer.getOrders().stream());
streamOrders.forEach(System.out::println);
//output:
java.util.stream.ReferencePipeline$Head@2a3046da
java.util.stream.ReferencePipeline$Head@5cbc508c
java.util.stream.ReferencePipeline$Head@3419866c
Order{id=1}
Order{id=2}
Order{id=3}
Order{id=4}
Order{id=5}
如果只是使用 map 沒辦法直接得到 List
我們可以使用 Stream interface 定義的 concat 方法來實現流的串接,簽章如下:
static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)
範例:
Stream<String> first = Stream.of("a", "b", "c").parallel();
Stream<String> second = Stream.of("X", "Y", "Z");
List<String> strings = Stream.concat(first, second) ➊
.collect(Collectors.toList());
System.out.println(strings);
//output:
[a, b, c, X, Y, Z]
串流是惰性的,在達到終止條件前不會處理元素,達到終止條件後才透過管線逐一處理每個元素。
下面這個例子特別從 100 開始產生無限串流,findFirst() 是終止條件
example 1: 輸出過程訊息,是個串流的過程 & 第一個被三整除的數: 204
example 2: 拿掉 findFirst() 後沒有任何輸出
int multByTwo(int n) {
System.out.printf("Inside multByTwo with arg %d%n", n);
return n * 2;
}
boolean divByThree(int n) {
System.out.printf("Inside divByThree with arg %d%n", n);
return n % 3 == 0;
}
//example 1
Optional<Integer> result = Stream.iterate(100, i -> i + 2)
.map(this::multByTwo)
.filter(this::divByThree)
.findFirst();
System.out.println(result);
//output:
Inside multByTwo with arg 100
Inside divByThree with arg 200
Inside multByTwo with arg 102
Inside divByThree with arg 204
Optional[204]
Stream.iterate(100, i -> i + 2)
.map(this::multByTwo)
.filter(this::divByThree);
//output:
(empty)
串流操作與以往的集合式編程很不一樣,使用起來還是有那麼一些不習慣,我們可以藉由大量練習 & 實作來熟悉這個強大的工具,不僅僅是語法上的進步,在觀念以及執行效能上也可能帶來影響
Java 8 - 輕鬆解決 8 與 9 的難題(O’REILLY)
https://geek-docs.com/java/java-examples/java-inert-flow.html