是什么?
流,支持顺序和并行聚合操作的一系列元素。是一个操作,一个动作action。
有什么用?
对数据源(数组或集合)进行操作,产生新的数据。能高效便利的操作集合(collection)对象。适用于操作大批量数据。
怎么用?
1. 创建Stream
//collection流,通过Collection的stream()获得
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream();
//数组流,通过Arrays.stream()静态方法获得
int[] count = new int[10];
count[0] = 1;
count[1] = 2;
count[3] = 3;
count[2] = 4;
count[4] = 5;
count[5] = 6;
IntStream stream1 = Arrays.stream(count);
IntStream stream2 = Arrays.stream(count, 1, 5);
stream2.forEach(System.out::println);
//Stream.of()静态方法获得
Stream<String> stringStream = Stream.of("abc");
Stream<String> stringStream1 = Stream.of("abc", "def");
stringStream1.forEach(System.out::println);
//该方法调用Arrays.stream("abc", "def");
//无限流,Stream.iterate()静态方法获得,
Stream<String> stream3 = Stream.iterate("Lambda", (x) -> x + "->method reference");
//stream3.forEach(System.out::println);//Lambda的基础上不断地加->method reference
/*Lambda
Lambda->method reference
Lambda->method reference->method reference
Lambda->method reference->method reference->method reference
Lambda->method reference->method reference->method reference->method reference
Lambda->method reference->method reference->method reference->method reference->method reference
.....*/
//stream3.limit(12).forEach(System.out::println);//需要用limit指定输出大小,否则会无限输出
Stream<Integer> iterate = Stream.iterate(0, (x) -> x + 1);
iterate.limit(10).forEach(System.out::println);
//无限流,Stream.generate()静态方法创建
Stream.generate(() -> "return").limit(3).forEach(System.out::println);
//基本数据类型流
IntStream.range(1, 5).forEach(System.out::println);
LongStream.range(1, 6).forEach(System.out::println);
//range(),创建从第一个参数到第二个参数的有序流,以1的步长递增后续元素的值,不包括最后一个元素
//字符串的流
IntStream chars = "after".chars();
chars.forEach(System.out::print);
2. 流操作
操作并不会改变原始数据,但会产生一个新的流,且如果不对产生的新流进行终端操作,该流不会有任何输出。流操作可以没有。
(1) 筛选 filter
从流中筛选元素
public interface Stream<T> extends BaseStream<T, Stream<T>> {
Stream<T> filter(Predicate<? super T> predicate);
//参数为断言接口,可以用lambda表达式
示例:
//数组流,通过Arrays.stream()静态方法获得
int[] count = new int[10];
count[0] = 1;
count[1] = 2;
count[3] = 3;
count[2] = 44;
count[4] = 56;
count[5] = 66;
IntStream stream2 = Arrays.stream(count, 1, 5);
//stream2.forEach(System.out::println);执行此代码后不可以执行中间操作
IntStream intStream = stream2.filter((x) -> {System.out.println("是否大于3");return x > 3;});
//中间操作会返回一个新流。
//如果在中间操作之前执行过终端操作(如forEach)则不可以执行中间操作。
intStream.forEach(System.out::println);
(2) 截断流 limit
使元素不超过给定数量
Stream<T> limit(long maxSize);
示例:
List<String> list = new ArrayList<>();
list.add("aa");
list.add("ee");
list.add("cc");
list.add("dd");
Stream<String> stream = list.stream();
stream.limit(2).forEach(System.out::println);//aa ee
(3) 跳过元素 skip
Stream<T> skip(long n);
示例:
List<String> list = new ArrayList<>();
list.add("aa");
list.add("ee");
list.add("cc");
list.add("dd");
Stream<String> stream = list.stream();
stream.skip(2).forEach(System.out::println);//cc dd
(4) 去重 distinct
通过流生成元素的hashCode()和equals()去除重复元素。
对于对象来说要重写hashCode()和equals()才会去重成功
Stream<T> distinct();
示例:
List<String> list = new ArrayList<>();
list.add("aa");
list.add("aa");
list.add("aa");
list.add("aa");
Stream<String> stream = list.stream();
stream.skip(2).forEach(System.out::println);//cc dd
(5) 映射 map
以函数为参数,将每个元素都以函数作用之后返回一个新元素 。
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
//以函数接口为参数。Function,接收一个参数,返回一个类型。
示例:
List<String> list = new ArrayList<>();
list.add("aa");
list.add("aa");
list.add("aa");
list.add("aa");
Stream<String> stream = list.stream();
stream.map((x) -> x.toUpperCase() + "小写变大写").forEach(System.out::println);
(5) 映射 flatMap
以函数为参数,将每个元素都以函数作用之后返回一个新流,再将每个元素产生的流拼接成一个流 。
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
//以函数接口为参数。Function,接收一个参数,返回一个类型。
示例:
public class StreamTest {
@Test
public void TestStream(){
List<String> list = new ArrayList<>();
list.add("aa");
list.add("aa");
list.add("aa");
list.add("aa");
Stream<String> stream = list.stream();
stream.flatMap(StreamTest::toStream).forEach(System.out::println);
//使用flatMap可以达到以下两行代码的效果
//Stream<Stream<Character>> streamStream = stream.map(StreamTest::toStream);
//此时中间操作返回一个流 (包含着很多流)
//streamStream.forEach((x) -> x.forEach(System.out::println)); }
//传入字符串返回一个流
public static Stream<Character> toStream(String string) {
List list = new ArrayList<>();
for (Character ch : string.toCharArray()) {
//String -> char[]
list.add(ch);//将每个Character存入List中
}
Stream stream = list.stream();
return stream;
}
}
(6) 自然排序 sorted
Stream<T> sorted();
示例:
List<String> list = new ArrayList<>();
list.add("abcde");
list.add("ab");
list.add("abcd");
list.add("abc");
Stream<String> stream = list.stream();
stream.sorted().forEach(System.out::println);
//ab
//abc
//abcd
//abcde
(7) 定制排序 sorted(Comparator com)
Stream<T> sorted(Comparator<? super T> comparator);
示例:
List<String> list = new ArrayList<>();
list.add("abcde");
list.add("ab");
list.add("abcd");
list.add("abc");
Stream<String> stream = list.stream();
stream.sorted((e, x) -> {
if (e.length() < x.length()) {
return 1;
}else
{
return -1;
}
}).forEach(System.out::println);
//abcde
//abcd
//abc
//ab
3. 终端操作
创建流后可以直接执行终端操作。
- allMatch 检查是否匹配所有元素
boolean allMatch(Predicate<? super T> predicate);
- anyMatch 检查是否匹配至少一个元素
boolean anyMatch(Predicate<? super T> predicate);
- noneMatch Z检查是否没有匹配所有元素
boolean noneMatch(Predicate<? super T> predicate);
- findFirst 返回第一个元素
Optional<T> findFirst();
示例:
List<String> list = new ArrayList<>();
list.add("abcde");
list.add("ab");
list.add("abcd");
list.add("abc");
Stream<String> stream = list.stream();
Optional<String> first = stream.findFirst();
System.out.println(first.get());//
- findAny 返回当前流的任意一个元素
Optional<T> findAny();
- count 返回流中元素的总个数
long count();
- max 返回流最大值
Optional<T> max(Comparator<? super T> comparator);
- min 返回流最小值
Optional<T> min(Comparator<? super T> comparator);
示例:
Optional<String> max = stream.min((x, y) -> {
if (x.length() > y.length()) {
return 1;
} else {
return -1;
}
});
System.out.println(max.get());//ab
- reduce 归约
T reduce(T identity, BinaryOperator<T> accumulator);
//指定初始值,并对流内元素进行累加操作,返回值一定不为空
Optional<T> reduce(BinaryOperator<T> accumulator);
//返回值可能为空,所以返回Optional
<U> U reduce(U identity,
BiFunction<U, ? super T, U> accumulator,
BinaryOperator<U> combiner);
示例:
List<String> list = new ArrayList<>();
list.add("abcde");
list.add("ab");
list.add("abcd");
list.add("abc");
Stream<String> stream = list.stream();
String reduce = stream.reduce("0", (x, y) -> x + y);
System.out.println(reduce);
//0abcdeababcdabc
- collect 收集
<R> R collect(Supplier<R> supplier,
BiConsumer<R, ? super T> accumulator,
BiConsumer<R, R> combiner);
<R, A> R collect(Collector<? super T, A, R> collector);
//Collector是一个接口是一个收集器,该接口有一个实现类:Collectors提供很多静态方法,
示例:
List<Student> list = new ArrayList<>();
list.add(new Student("张三", 12, "秦国", "学习中"));
list.add(new Student("李四", 13, "楚国", "缀学"));
list.add(new Student("王五", 15, "晋国", "学习中"));
list.add(new Student("赵六", 16, "赵国", "缀学"));
Stream<Student> stream = list.stream();
HashSet<String> collect = stream.map(Student::getName).collect(Collectors.toCollection(HashSet::new));
collect.forEach(System.out::println);
补充知识
Optional 对象
是一个容器对象,可以包含也可以不包含非null值。个人理解是一个包装类,可以将类进行包装,能避免空指针异常。
Optional<Object> empty = Optional.empty();
//获取空的Optional对象
Optional<Student> stuOp = Optional.ofNullable(new Student());
Optional<Student> stuOp1 = Optional.of(new Student());
//获取Optional对象
//of与ofNullable区别:两者方法传入参数为null时,of方法会报错,而ofNullable不会报错。
Student student = stuOp.get();
//获取Optional封装的对象
Student s = new Student("zs", 1, "齐国", "学习中");
stuOp.orElse(s);
stuOp1.orElseGet(Student::new);
//Optional不为空返回包含值,为空返回形参。
//区别: orElseGet操作空间更大。且当Optional不为空时不会执行orElseGet方法,而orElse不论Optional是否为空都执行。
boolean present = stuOp.isPresent();
//判断Optional对象是否为空
Optional<Student> stu = Optional.ofNullable(s);
System.out.println(stu.map((y) -> y.getName()).get());
System.out.println(stu.flatMap((y) -> Optional.of(y.getName())).get());
//对Optional进行处理,处理结果有值时返回新的Optional,无值返回Optional.empty()
//区别:方法 形参的返回值 不同,flatMap形参返回必须是Optional;
//Optional在存在始终牵着Null的手
Fork/Join框架
将一个大任务拆分为多个小任务,然后将小任务的执行结果进行汇总。当数据量庞大时适合使用。
并行流
把一个流的内容拆分为多个数据块,使用多个线程分别处理每个数据块的流。并行流内部使用的是Fork/Join框架。在Stream中可以使用parallel() 和 sequential() 进行并行和顺序的转换。