Операции сведения представляют терминальные операции, которые возвращают некоторое значение - результат операции. В Stream API есть ряд операций сведения.
Метод count() возвращает количество элементов в потоке данных:
import java.util.stream.Stream;
import java.util.Optional;
import java.util.*;
public class Program {
public static void main(String[] args) {
ArrayList<String> names = new ArrayList<String>();
names.addAll(Arrays.asList(new String[]{"Tom", "Sam", "Bob", "Alice"}));
System.out.println(names.stream().count()); // 4
// количество элементов с длиной не больше 3 символов
System.out.println(names.stream().filter(n->n.length()<=3).count()); // 3
}
}
Метод findFirst() извлекает из потока первый элемент, а findAny() извлекает случайный объект из потока (нередко так же первый):
ArrayList<String> names = new ArrayList<String>();
names.addAll(Arrays.asList(new String[]{"Tom", "Sam", "Bob", "Alice"}));
Optional<String> first = names.stream().findFirst();
System.out.println(first.get()); // Tom
Optional<String> any = names.stream().findAny();
System.out.println(first.get()); // Tom
Еще одна группа операций сведения возвращает логическое значение true или false:
boolean allMatch(Predicate<? super T> predicate): возвращает true, если все элементы потока удовлетворяют условию в предикате
boolean anyMatch(Predicate<? super T> predicate): возвращает true, если хоть один элемент потока удовлетворяют условию в предикате
boolean noneMatch(Predicate<? super T> predicate): возвращает true, если ни один из элементов в потоке не удовлетворяет условию в предикате
Пример использования функций:
import java.util.stream.Stream;
import java.util.Optional;
import java.util.ArrayList;
import java.util.Arrays;
public class Program {
public static void main(String[] args) {
ArrayList<String> names = new ArrayList<String>();
names.addAll(Arrays.asList(new String[]{"Tom", "Sam", "Bob", "Alice"}));
// есть ли в потоке строка, длина которой больше 3
boolean any = names.stream().anyMatch(s->s.length()>3);
System.out.println(any); // true
// все ли строки имеют длину в 3 символа
boolean all = names.stream().allMatch(s->s.length()==3);
System.out.println(all); // false
// НЕТ ЛИ в потоке строки "Bill". Если нет, то true, если есть, то false
boolean none = names.stream().noneMatch(s->s=="Bill");
System.out.println(none); // true
}
}
Методы min() и max() возвращают соответственно минимальное и максимальное значение. Поскольку данные в потоке могут представлять различные типы, в том числе сложные классы, то в качестве параметра в эти методы передается объект интерфейса Comparator, который указывает, как сравнивать объекты:
Optional<T> min(Comparator<? super T> comparator) Optional<T> max(Comparator<? super T> comparator)
Оба метода возвращают элемент потока (минимальный или максимальный), обернутый в объект Optional.
Например, найдем минимальное и максимальное число в числовом потоке:
import java.util.stream.Stream;
import java.util.Optional;
import java.util.ArrayList;
import java.util.Arrays;
public class Program {
public static void main(String[] args) {
ArrayList<Integer> numbers = new ArrayList<Integer>();
numbers.addAll(Arrays.asList(new Integer[]{1,2,3,4,5,6,7,8,9}));
Optional<Integer> min = numbers.stream().min(Integer::compare);
Optional<Integer> max = numbers.stream().max(Integer::compare);
System.out.println(min.get()); // 1
System.out.println(max.get()); // 9
}
}
Интерфейс Comparator - это функциональный интерфейс, который определяет один метод compare, принимающий два сравниваемых объекта и возвращающий число (если первый объект больше, возвращается положительное число, иначе
возвращается отрицательное число). Поэтому вместо конкретной реализации компаратора мы можем передать лямбда-выражение или метод, который соответствует методу
compare интерфейса Comparator. Поскольку сравниваются числа, то в метод передается в качестве компаратора статический метод Integer.compare().
При этом методы min и max возвращают именно Optional, и чтобы получить непосредственно результат операции из Optional, необходимо вызвать метод get().
Рассмотрим более сложный случай, когда нам надо сравнивать более сложные объекты:
import java.util.stream.Stream;
import java.util.Optional;
import java.util.ArrayList;
import java.util.Arrays;
public class Program {
public static void main(String[] args) {
ArrayList<Phone> phones = new ArrayList<Phone>();
phones.addAll(Arrays.asList(new Phone[]{
new Phone("iPhone 8", 52000),
new Phone("Nokia 9", 35000),
new Phone("Samsung Galaxy S9", 48000),
new Phone("HTC U12", 36000)
}));
Phone min = phones.stream().min(Phone::compare).get();
Phone max = phones.stream().max(Phone::compare).get();
System.out.printf("MIN Name: %s Price: %d \n", min.getName(), min.getPrice());
System.out.printf("MAX Name: %s Price: %d \n", max.getName(), max.getPrice());
}
}
class Phone{
private String name;
private int price;
public Phone(String name, int price){
this.name=name;
this.price=price;
}
public static int compare (Phone p1, Phone p2){
if(p1.getPrice() > p2.getPrice())
return 1;
return -1;
}
public String getName() { return name; }
public int getPrice() { return price;}
}
В данном случае мы находим минимальный и максимальный объект Phone: фактически объекты с максимальной и минимальной ценой. Для определения функциональности
сравнения в классе Phone реализован статический метод compare, который соответствует сигнатуре метода compare интерфейса Comparator.
И в методах min и max применяем этот статический метод для сравнения объектов.
Консольный вывод:
MIN Name: Nokia 9 Price: 35000 MAX Name: iPhone 8 Price: 52000