流的定义
是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
集合讲的是数据,流讲的是计算。
流的特点
- Stream 本身不会存储数据;
- Stream 不会改变数据源,相反会生成一个持有结果的新 Stream;
- Stream 的操作时延迟的,会等到需要结果的时候才去执行。
流的创建
- 通过 Collection 系列集合提供的 stream() 或者 parallelStream() 方法创建;
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream(); //串行流
Stream<String> stringStream = list.parallelStream();//并行流
- 通过 Arrays 的 stream() 方法创建;
String[] arr = new String[10];
Stream<String> stream = Arrays.stream(arr);
- 通过 Stream 类的静态方法创建;
Stream<String> stream = Stream.of("test");
- 创建无限流
Stream<Integer> stream = Stream.iterate(0, (x) -> x + 2);
Stream 的中间操作
Stream 的多个中间操作可以连接起来形成流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理,而在终止操作时一次性全部处理,称为惰性求值。
- filter(过滤):从流中排除某些元素;
String[] arr = {"abcx","sjdjs","66"};
Stream<String> stream1 = Arrays.stream(arr);
Stream<String> stream2 = stream1.filter((e) -> {
System.out.println(e); //注意,此条语句不会执行,会在终止操作时统一执行
return e.length()>2;
});
stream2.forEach(System.out::println);//运行结果:abcx、sjdjs
- limit(截断):使其元素不超过指定数量
String[] arr = {"java","ruby","shell","json"};
Stream<String> stream1 = Arrays.stream(arr);
Stream<String> stream2 = stream1.limit(2);//指定元素不超过两个
stream2.forEach(System.out::println);//运行结果:java、ruby
- skip(跳过):跳过元素,返回去掉前n个元素的流。如果流中的元素不超过n个,则返回一个空流,与limit(n)互补;
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
Stream<Integer> stream = list.stream().skip(2);
stream.forEach(System.out::println);//运行结果:3,4; 跳过了1、2
- distinct(去重):通过流所生成的元素的 hashCode() 和 equals() 去重。
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(1);
list.add(1);
Stream<Integer> stream = list.stream().distinct();
stream.forEach(System.out::println);//运行结果: 1、2、3、4
- map(映射):接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
List<String> list = Arrays.asList("a","b","c","d");
Stream<String> stream = list.stream().map((str) -> str.toUpperCase());
stream.forEach(System.out::println);//运行结果:A、B、C、D,大写方法全部应用到每个元素上
- flatMap:接收一个函数作为参数,将流中的每一个元素地换成一个流,然后把所有的流连接成一个流。
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class StreamMapTest {
public static Stream<Character> strToCharStream(String str){
List<Character> list = new ArrayList<>();
for (Character character : str.toCharArray()){
list.add(character);
}
return list.stream();
}
@Test
public void test(){
String[] arr = new String[]{"aaa","bbb","ccc"};
Stream<Stream<Character>> mapStream = Arrays.stream(arr).map(StreamMapTest::strToCharStream);//得到的是 Stream<Stream<Character>>,即流的流
mapStream.forEach(System.out::print);
System.out.println();
Stream<Stream<Character>> mapStream2 = Arrays.stream(arr).map(StreamMapTest::strToCharStream);
mapStream2.forEach((s)->s.forEach(System.out::print));
System.out.println();
Stream<Character> flatStream = Arrays.stream(arr).flatMap(StreamMapTest::strToCharStream);//得到的 Stream<Character>,即单个流
flatStream.forEach(System.out::print);
}
}
/*
*java.util.stream.ReferencePipeline$Head@244038d0java.util.stream.ReferencePipeline$Head@5680a178java.util.stream.ReferencePipeline$Head@5fdef03a
*aaabbbccc
*aaabbbccc
*/
- sorted():自然排序;sorted(Comparator com):定制排序;
public void testSorted(){
List<String> list = Arrays.asList("wade ","james ","kobe ");
list.stream().sorted().forEach(System.out::print);
System.out.println();
list.stream().sorted((e1,e2)-> -e1.compareTo(e2)).forEach(System.out::print);
}
/** 输出结果:
* james kobe wade
* wade kobe james
*/
终止操作
- allMatch():全部匹配
List<Integer> list = Arrays.asList(3,4,5,6,7);
System.out.println(list.stream().allMatch(e-> e>1));//输出 ture
System.out.println(list.stream().allMatch(e-> e>5));//输出 false
- anyMatch():部分匹配
List<Integer> list = Arrays.asList(3,4,5,6,7);
System.out.println(list.stream().anyMatch(e -> e>5));//输出 ture
System.out.println(list.stream().anyMatch(e -> e==1));//输出 false
- noneMatch():不匹配
List<Integer> list = Arrays.asList(3,4,5,6,7);
System.out.println(list.stream().noneMatch(e -> e==1));//输出 true
System.out.println(list.stream().noneMatch(e -> e==3)); //输出 false
- findFirst():返回第一个元素
List<Integer> list = Arrays.asList(3,4,5,6,7);
Optional<Integer> first = list.stream().findFirst();
System.out.println(first.get());//输出3
- findAny():返回当前流的任一一个元素
List<Integer> list = Arrays.asList(3,4,5,6,7);
Optional<Integer> any = list.stream().filter(e -> e > 5).findAny();
System.out.println(any.get()); //输出6
- count():返回流的元素的个数
List<Integer> list = Arrays.asList(3,4,5,6,7);
long count = list.stream().filter(e -> e > 5).count();
System.out.println(count);//输出2
- max():返回流中的最大元素
min():返回流中的最小元素
List<Integer> list = Arrays.asList(3,4,5,6,7);
Optional<Integer> max = list.stream().filter(e -> e > 5).max((e1, e2) -> e1.compareTo(e2));
System.out.println(max.get());//输出7
Optional<Integer> min= list.stream().filter(e -> e > 5).min((e1, e2) -> e1.compareTo(e2));
System.out.println(min.get());//输出6
- reduce() : 归约,可以将流中的元素反复结合起来,得到一个值
List<String> list = Arrays.asList("football","basketball","swimming","tennis");
String reduce = list.stream().reduce("table tennis", (e1, e2) -> e1 + "," + e2);
System.out.println(reduce);//输出:table tennis,football,basketball,swimming,tennis 第一个参数为起始值,将每个元素进行拼接
Optional<String> reduce2 = list.stream().filter(e -> e.length() > 6).map(e -> e.toUpperCase()).reduce(String::concat);//没有起始值,所以有可能为空,返回类型为Optional<String>
System.out.println(reduce2.get()); //输出结果:FOOTBALLBASKETBALLSWIMMING
- collect():收集,接收一个Collector的接口的实现,用于给Stream 中的元素做汇总,Collectors 工具类提供了常用的方法。
List<String> list = Arrays.asList("football","basketball","swimming","tennis","tennis","tennis");
Long collect = list.stream().collect(Collectors.counting());
System.out.println(collect);//输出 6
Set<String> collect1 = list.stream().collect(Collectors.toSet());
System.out.println(collect1); //输出[swimming, basketball, football, tennis]
并行流和串行流
串行流和并行流的抽象方法存在 BaseStream 中
- 串行流:sequential(),返回顺序的等效流。可能会返回本身,或者是因为流已经是顺序的,或者是因为底层流状态被修改为顺序的。
Instant start = Instant.now();
long sum = LongStream.rangeClosed(0, 10000000000L)
.sequential() //指定串行流
.sum();
Instant end = Instant.now();
long time = ChronoUnit.MILLIS.between(start, end);
System.out.println(time); //输出 4566 根据机器的不同此值不同
- 并行流:parallel(),返回一个并行的等效流。可能会返回本身,或者因为这个流已经是并行的,或者因为底层流状态被修改为并行的。
Instant start = Instant.now();
longsum = LongStream.rangeClosed(0, 10000000000L)
.parallel() //指定并行流
.sum();
Instant end = Instant.now();
long time = ChronoUnit.MILLIS.between(start, end);
System.out.println(time); //输出 1330 根据机器的不同此值不同