JavaStream
Java8引入Stream,主要用来处理集合,可以执行查找,过滤,映射等操作
特点:
- 不是数据结构,不会保存数据
- 不会修改原来的值
- 流在中间过程中只是对操作记录,并不会立即执行(惰性求值)
Stream操作
1. 创建流
//Collection
List<String> list = new ArrayList<>();
Stream<String> OrderStream = list.stream(); //顺序流
Stream<String> parallelStream = list.parallelStream(); //并行流
//Arrays
Integer[] nums = new Integer[10];
Stream<Integer> stream = Arrays.stream(nums);
//Stream
Stream<Integer> stream1 = Stream.of(1,2,3,4,5,6);
Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 1).limit(1);//0,1,2,3,4
Stream<Double> stream3 = Stream.generate(Math::random).limit(2);//随机生成两个double
stream3.forEach(System.out::println);//stream流的输出
//BufferedReader.lines()
BufferedReader reader = new BufferedReader(new FileReader("a.txt"));
Stream<String> stream = reader.lines();
//Pattern.splitAsStream(),分割字符串为流
Pattern pattern = Pattern.compile(",");
Stream<String> stringStream = pattern.splitAsStream("a,b,c,d");
2. 流操作
2.1 中间操作
- filter() 过滤元素
- limit(n) 获取n个元素
- skip(x) 跳过x个元素
- distinct() 配合hashCode(),equals()去重
- map() 接收一个函数(有返回值),被应用在每个元素上,并映射为一个新的元素
- flatMap() 接收一个函数,将每个值都换成另一个流,然后将所有流链接成一个流
- sorted() 自然排序,流中的元素要实现Comparable接口
- sorted(Comparator com) 自定义排序,自定义排序接口
- peek() 接受一个Consumer表达式(无返回值),可以得到流中的每个元素
2.2 终止操作
-
allMatch() 接收一个Predicate函数,当流中元素都符合该断言返回TRUE,否则返回FALSE
-
noneMatch() 接收一个Predicate函数,当流中每个元素都不符合该断言则返回TRUE,否则返回FALSE
-
anyMatch() 接收一个Predicate函数,当流中有一个元素符合该断言则返回TRUE,否则返回FALSE
-
findFirst() 返回流中的第一个元素
-
findAny() 返回流中的任意元素
-
count() 返回流中元素的个数
-
max()/min() 返回流中元素的最大值,最小值
2.3 规约操作
Optional<T> reduce(BinaryOperator<T> accumulator)
第一次执行时,accumulator函数的第一个参数为流中的第一个元素,第二个参数为流中元素的第二个元素;第二次执行时,第一个参数为第一次函数执行的结果,第二个参数为流中的第三个元素;依次类推T reduce(T identity, BinaryOperator<T> accumulator)
流程跟上面一样,只是第一次执行时,accumulator函数的第一个参数为identity,而第二个参数为流中的第一个元素。<U> U reduce(U identity,BiFunction<U, ? super T, U> accumulator,BinaryOperator<U> combiner)
在串行流(stream)中,该方法跟第二个方法一样,即第三个参数combiner不会起作用。在并行流(parallelStream)中,我们知道流被fork join出多个线程进行执行,此时每个线程的执行流程就跟第二个方法reduce(identity,accumulator)一样,而第三个参数combiner函数,则是将每个线程的执行结果当成一个新的流,然后使用第一个方法reduce(accumulator)流程进行规约。
2.4 收集操作
-
collect() 接收一个Collector实例,将流中的元素收集为另一种数据结构
Collector工具包
- Collectors.toList() 转为list
- Collectors.toSet() 转为set
- Collectors.toMap() 转为map
- Collectors.joining() 字符串分割连接
- Collectors.count() 聚合操作 求数量
- Collectors.maxBy(Integer:compare) 聚合操作,求最大值/最小值
- Collectors.summingInt() 聚合操作,求和
- Collectors.average() 聚合操作,求平均值
- Collectors.groupingBy() 分组操作
- Collectors.partitioningBy() 分区操作,根据条件分为两部分
- Collectors.reduce() 规约
实践
将List元素存储到数组
List<Integer> list=new ArrayList<>(Arrays.asList(1,2,3,4,5));
int[] arr=list.stream().mapToInt(Integer::intValue).toArray();
将数组元素存储到List
List<Integer> list2=Arrays.stream(arr).boxed().collect(Collectors.toList());
统计元素个数
Map<Integer, Long> map = Stream.of(arr)
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (m1, m2) -> m2,
LinkedHashMap::new));
Map<Integer, Integer> map2=Stream.of(arr).collect(Collectors.toMap(k->k, k->1,Integer::sum));
//统计并输出
Stream.of(arr).collect(Collectors.toMap(k->k, k->1,Integer::sum)).forEach((k,v)-> System.out.println(k+" : "+v));
自定义排序
int[] arr={1,5,9,7,2,3,7,-1,0,3};
arr= IntStream.of(arr).boxed().sorted(Comparator.reverseOrder()).mapToInt(Integer::intValue).toArray();
统计前k个高频元素
int[] arr={4,3,2,3,4,1,2,3,1,2,1};
int k=3;
int[] res=IntStream.of(arr)
.boxed()
.collect(Collectors.toMap(x->x,x->1,Integer::sum))
.entrySet()
.stream()
.sorted((e1,e2)-> e2.getValue()-e1.getValue()).limit(k)
.mapToInt(Map.Entry::getKey)
.toArray();