Stream流
一 :Stream流的介绍
stream
不存储数据,而是按照特定的规则对数据进行计算,一般会输出结果;stream
不会改变数据源,通常情况下会产生一个新的集合;stream
具有延迟执行特性,只有调用终端操作时,中间操作才会执行。- 对
stream
操作分为终端操作和中间操作,那么这两者分别代表什么呢?
终端操作:会消费流,这种操作会产生一个结果的,如果一个流被消费过了,那它就不能被重用的。
中间操作:中间操作会产生另一个流。因此中间操作可以用来创建执行一系列动作的管道。一个特别需要注意的点是:中间操作不是立即发生的。相反,当在中间操作创建的新流上执行完终端操作后,中间操作指定的操作才会发生。所以中间操作是延迟发生的,中间操作的延迟行为主要是让流API能够更加高效地执行。 stream
不可复用,对一个已经进行过终端操作的流再次调用,会抛出异常。
二: 创建流
public class Demo1 {
public static void main ( String[] args ) {
//创建stream流,通过Arrays.stream
int[] arr = {1, 2, 3};
IntStream stream = Arrays.stream(arr);
Person[] personStr = {new Person(18, "xiaoliu"), new Person(18, "xiaojing")};
Stream<Person> personStream = Arrays.stream(personStr);
// 通过stream.of
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4);
// 通过集合创建流
List<String> stringList = Arrays.asList("123", "456", "789");
// 创建普通流
Stream<String> stringStream = stringList.stream();
// 创建并行流
Stream<String> parallelStream = stringList.parallelStream();
}
}
public class Demo2 {
public static void main ( String[] args ) {
// 流的筛选
List<Integer> integerList = Arrays.asList(1, 2, 3,3, 4, 5, 6);
// 筛选出集合中数字大于4的元素
List<Integer> collect = integerList.stream().filter(x -> x > 4).collect(Collectors.toList());
System.out.println(collect); //[5, 6]
// 集合中的去重
List<Integer> collect1 = integerList.stream().distinct().collect(Collectors.toList());
System.out.println(collect1);//[1, 2, 3, 4, 5, 6]
// 获取流中的第一个元素
Optional<Integer> first = integerList.stream().filter(x -> x > 4).findFirst();
Optional<Integer> any = integerList.stream().filter(x -> x > 4).findAny();
Optional<Integer> any1 = integerList.parallelStream().filter(x -> x > 4).findAny();
System.out.println(first); //Optional[5]
System.out.println(any); //Optional[5]
System.out.println(any1); // 预期结果不稳定
}
}
三:Stream流中获取最值 max、min和count
public class Demo3 {
public static void main(String[] args) {
List<String> stringList = Arrays.asList("huainvhai", "xiaotiancai", "bennvhai");
// 获取集合中最长的字符串
Optional<String> maxString = stringList.stream().max(Comparator.comparing(String::length));
// 获取集合中最短字符串
Optional<String> minString = stringList.stream().min(Comparator.comparing(String::length));
System.out.println(maxString);
System.out.println(minString);
// 获取集合中的最大值
List<Integer> integerList = Arrays.asList(1, 2, 3);
Optional<Integer> maxInteger = integerList.stream().max((i, j) -> {
return i - j;
});
// 获取集合中的最小值
Optional<Integer> minInteger = integerList.stream().max((i, j) -> {
return j - i;
});
System.out.println(maxInteger);
System.out.println(minInteger);
// 集合泛型是个对象的最值
ArrayList<Person> personList = new ArrayList<>();
personList.add(new Person("xiao",12));
personList.add(new Person("xiao",20));
personList.add(new Person("xiao",18));
Optional<Person> max = personList.stream().max(Comparator.comparing(Person::getAge));
// 获取集合中的元素数量
long count = personList.stream().filter(p -> p.getAge() > 12).count();
System.out.println(max);
System.out.println(count);
}
}
四: 缩减
缩减:就是把一个流缩减成一个值,比如说对一个集合中求和,求乘积等
Stream流定义了三个reduce
public interface Stream<T> extends BaseStream<T, Stream<T>> {
// 方法1
T reduce(T identity, BinaryOperator<T> accumulator);
// 方法2
Optional<T> reduce(BinaryOperator<T> accumulator);
// 方法3
<U> U reduce(U identity,
BiFunction<U, ? super T, U> accumulator,
BinaryOperator<U> combiner);
}
前两种缩减方式
第一种:接收一个BinaryOperator accumulator function(二元累加计算函数)和identity(标示值)为参数,返回值是一个T类型(代表流中的元素类型)的对象。accumulator代表操作两个值并得到结果的函数。identity按照accumulator函数的规则参与计算,假如函数是求和运算,那么函数的求和结果加上identity就是最终结果,假如函数是求乘积运算,那么函数结果乘以identity就是最终结果。
第二种:不同之处是没有identity,返回值是Optional(JDK8新类,可以存放null)。
public class Demo4 {
public static void main(String[] args) {
List<Integer> integers = Arrays.asList(1, 2, 3, 4);
// 写法一 集合中的元素求和 (就是集合中的元素求和再加上1)
Integer integer = integers.stream().reduce(1, Integer::sum);
// 写法二
integers.stream().reduce(1,(x,y)->x+y);
System.out.println(integer); // 11
// 第二种缩减方式 集合中的元素求和
Optional<Integer> reduce = integers.stream().reduce(Integer::sum);
// 写法二
Optional<Integer> reduce1 = integers.stream().reduce((x, y) -> x + y);
System.out.println(reduce); //Optional[10]
System.out.println(reduce1); //Optional[10]
// 集合中使用reduce求最值问题
Optional<Integer> reduce2 = integers.stream().reduce(Integer::max);
System.out.println(reduce2);
/**
* 对象集合求和 求最值问题
*/
ArrayList<Person> personList = new ArrayList<>();
personList.add(new Person("xiao",12));
personList.add(new Person("xiao",20));
personList.add(new Person("xiao",18));
// 求集合中对象的年龄的总和
Optional<Integer> reduce3 = personList.stream().map(p -> p.getAge()).reduce(Integer::sum);
System.out.println(reduce3); //Optional[50]
// 求集合中年龄最大的对象
Optional<Person> reduce4 = personList.stream().reduce((p1, p2) -> p1.getAge() > p2.getAge() ? p1 : p2);
Optional<Person> max = personList.stream().max(Comparator.comparingInt(Person::getAge));
System.out.println(reduce4);
System.out.println(max);
}
}
五:collect
collect操作可以接受各种方法作为参数,将流中的元素汇集,
public class Demo5 {
public static void main(String[] args) {
ArrayList<Person> personList = new ArrayList<>();
personList.add(new Person("xiao",12));
personList.add(new Person("xiao",20));
personList.add(new Person("xiao",18));
// 获取平均年龄 averaging
Double collect = personList.stream().collect(Collectors.averagingInt(Person::getAge));
System.out.println(collect); //16.666666666666668
// summarizing
DoubleSummaryStatistics collect1 = personList.stream().collect(Collectors.summarizingDouble(Person::getAge));
System.out.println(collect1); // DoubleSummaryStatistics{count=3, sum=50.000000, min=12.000000, average=16.666667, max=20.000000}
//joining
String collect2 = personList.stream().map(p -> p.getName()).collect(Collectors.joining(","));
System.out.println(collect2); //xiao,xiao,xiao
// reduce
Integer collect3 = personList.stream().collect(Collectors.reducing(0, Person::getAge, (x, y) -> x + y));
Optional<Integer> reduce = personList.stream().map(Person::getAge).reduce(Integer::sum);
System.out.println(collect3); //50
System.out.println(reduce); //Optional[50]
// groupingBy
// 以名字进行分组
Map<String, List<Person>> collect4 = personList.stream().collect(Collectors.groupingBy(Person::getName));
System.out.println(collect4); //{xiao=[Person(name=xiao, age=12), Person(name=xiao, age=20), Person(name=xiao, age=18)]}
// 先以名字分组,再以年龄分组
Map<String, Map<Integer, List<Person>>> collect5 = personList.stream().collect(Collectors.groupingBy(Person::getName, Collectors.groupingBy(Person::getAge)));
System.out.println(collect5); //{xiao={18=[Person(name=xiao, age=18)], 20=[Person(name=xiao, age=20)], 12=[Person(name=xiao, age=12)]}}
// toList、toSet、toMap
Set<Person> collect6 = personList.stream().collect(Collectors.toSet());
System.out.println(collect6);//[Person(name=xiao, age=18), Person(name=xiao, age=20), Person(name=xiao, age=12)]
}
}
六:映射
Stream流中,map可以将一个流的元素按照一定的映射规则映射到另一个流中。
public class Demo6 {
public static void main(String[] args) {
String[] strArr = { "abcd", "bcdd", "defde", "ftr" };
Arrays.stream(strArr).map(x->x.toUpperCase()).forEach(System.out::print); //ABCDBCDDDEFDEFTR
List<String> collect = Arrays.stream(strArr).map(x -> x.toUpperCase()).collect(Collectors.toList());
System.out.println(collect); // [ABCD, BCDD, DEFDE, FTR]
}
}
七 排序
Sorted方法是对流进行排序,并得到一个新的stream流,是一种中间操作。Sorted方法可以使用自然排序或特定比较器。
public class Demo7 {
public static void main(String[] args) {
String[] strArr = { "ab", "bcdd", "defde", "ftr" };
// 自然排序
List<String> collect = Arrays.stream(strArr).sorted().collect(Collectors.toList());
System.out.println(collect); // [ab, bcdd, defde, ftr]
// 自定义排序
// 按照字符串的长度 长度 从小到大
List<String> collect1 = Arrays.stream(strArr).sorted(Comparator.comparing(String::length)).collect(Collectors.toList());
System.out.println(collect1); //[ab, ftr, bcdd, defde]
// 按照字符串的长度逆序排序
List<String> collect2 = Arrays.stream(strArr).sorted(Comparator.comparing(String::length).reversed()).collect(Collectors.toList());
System.out.println(collect2); //[defde, bcdd, ftr, ab]
// 首字母倒序
List<String> collect3 = Arrays.stream(strArr).sorted(Comparator.reverseOrder()).collect(Collectors.toList());
System.out.println(collect3); //[ftr, defde, bcdd, ab]
// 首字母自然排序
List<String> collect4 = Arrays.stream(strArr).sorted(Comparator.naturalOrder()).collect(Collectors.toList());
System.out.println(collect4); //[ab, bcdd, defde, ftr]
}
}
八 提取流和组合流
public class Demo8 {
public static void main(String[] args) {
String[] arr1 = {"a","b","c","d"};
String[] arr2 = {"d","e","f","g"};
String[] arr3 = {"i","j","k","l"};
Stream<String> stream1 = Arrays.stream(arr1);
Stream<String> stream2 = Arrays.stream(arr2);
Stream<String> stream3 = Arrays.stream(arr3);
// 可以把两个stream合并成一个stream(合并的stream类型必须相同),只能两两合并
// List<String> collect = Stream.concat(stream1, stream2).collect(Collectors.toList());
// System.out.println(collect); //[a, b, c, d, d, e, f, g]
// 合并去重
List<String> collect1 = Stream.concat(stream1, stream2).distinct().collect(Collectors.toList());
System.out.println(collect1); //[a, b, c, d, e, f, g]
// limit,限制从流中获得前n个数据
// List<String> collect = collect1.stream().limit(3).collect(Collectors.toList());
// System.out.println(collect); //[a, b, c]
// skip,跳过前n个数据
List<String> collect = collect1.stream().skip(1).limit(3).collect(Collectors.toList());
System.out.println(collect);//[b, c, d]
}
}