第五章(3)查詢和匹配
另一個常見的資料處理套路是看看資料集中的某些元素是否匹配一個給定的屬性。Stream API通過allMatch、anyMatch、noneMatch、findFirst和findAny方法提供了這樣的工具。
1.檢查謂詞是否至少匹配一個元素anyMatch
檢查謂詞是否至少匹配一個元素anyMatch方法可以回答“流中是否有一個元素能匹配給定的謂詞”。比如,你可以用它來看看選單裡面是否有素食可選擇:
List<Dish> menu = Arrays.asList( new Dish("pork", false, 800, Dish.Type.MEAT), new Dish("beef", false, 700, Dish.Type.MEAT), new Dish("chicken", false, 400, Dish.Type.MEAT), new Dish("french fries", true, 530, Dish.Type.OTHER), new Dish("rice", true, 350, Dish.Type.OTHER), new Dish("season fruit", true, 120, Dish.Type.OTHER), new Dish("pizza", true, 550, Dish.Type.OTHER), new Dish("prawns", false, 300, Dish.Type.FISH), new Dish("salmon", false, 450, Dish.Type.FISH) ); Boolean boolean1 = menu.parallelStream().anyMatch(Dish::isVegetarian); System.out.println(boolean1);//true
2.檢查謂詞是否匹配所有元素allMatch
檢查謂詞是否匹配所有元素allMatch方法的工作原理和anyMatch類似,但它會看看流中的元素是否都能匹配給定的謂詞。比如,你可以用它來看看菜品是否有利健康(即所有菜的熱量都低於500卡路里):
Boolean boolean1 = menu.parallelStream().allMatch(d->d.getCalories()<500);
System.out.println(boolean1);//false
3.檢查謂詞是否都不匹配所有元素noneMatch
Boolean boolean1 = menu.parallelStream().noneMatch(d->d.getCalories()>1000);
System.out.println(boolean1);//true
anyMatch、allMatch和noneMatch這三個操作都用到了我們所謂的短路,這就是大家熟悉的Java中&&和||運算子短路在流中的版本。
4.查詢元素findAny
findAny方法將返回當前流中的任意元素。它可以與其他流操作結合使用。比如,你可能想找到一道素食菜餚。你可以結合使用filter和findAny方法來實現這個查詢:
Optional<Dish> dish = menu.parallelStream().filter(Dish::isVegetarian).findAny();
流水線將在後臺進行優化使其只需走一遍,並在利用短路找到結果時立即結束。但是你可能會疑惑,Optional是個什麼玩意?
你現在只需知道Optional<T>類(java.util.Optional)是一個容器類,代表一個值存在或不存在。在上面的程式碼中,findAny可能什麼元素都沒找到。Java 8的庫設計人員引入了Optional<T>,這樣就不用返回眾所周知容易出問題的null了。
我們在這裡簡單的瞭解一下其擁有的一些實用方法,在後面我們會有詳細的介紹:
1.isPresent()將在Optional包含值的時候返回true, 否則返回false。
Optional<Dish> dish = menu.parallelStream().filter(Dish::isVegetarian).findAny();
System.out.println(dish.isPresent());//true
2.ifPresent(Consumer<T> block)會在值存在的時候執行給定的程式碼塊。我們在第3章介紹了Consumer函式式介面;它讓你傳遞一個接收T型別引數,並返回void的Lambda表示式。
Optional<Dish> dish = menu.parallelStream().filter(Dish::isVegetarian).findAny();
dish.ifPresent(dish2 -> System.out.println(dish2.getName()));
3.T get()會在值存在時返回值,否則丟擲一個NoSuchElement異常。
4.T orElse(T other)會在值存在時返回值,否則返回一個預設值。
5.查詢第一個元素findFrist
有些流有一個出現順序(encounter order)來指定流中專案出現的邏輯順序(比如由List或排序好的資料列生成的流)。對於這種流,你可能想要找到第一個元素。為此有一個findFirst方法,它的工作方式類似於findany。例如,給定一個數字列表,下面的程式碼能找出第一個平方能被3整除的數:
Optional<Integer> optional = someNumbers.parallelStream().filter(i->i*i%3==0).findFirst();
System.out.println(optional.get());//3
何時使用findFirst和findAny你可能會想,為什麼會同時有findFirst和find-Any呢?答案是並行。找到第一個元素在並行上限制更多。如果你不關心返回的元素是哪個,請使用find-Any,因為它在使用並行流時限制較少。