Stream接口
Stream是在JDK1.8中才引入的接口,其中包含大量对集合对象操作的功能方法,它能使得对集合对象的操作更加高效和遍历。
Stream的特点:
- Stream不存储元素
- Stream不会修改数据源,而是会产生一个修改后的Stream对象,进而链式调用
- Stream的执行具有延迟特性
如何创建Stream对象:
1.从数组中获取Stream对象
//方式1:Arrays中的静态stream方法
Integer[] arr= {1,2,3,4,5};
Stream<Integer> stream=Arrays.stream(arr);
2.使用Stream中的静态方法of
//方式2:Stream类中的静态方法of(T... param)
Stream<String> stream2=Stream.of("a","b","c","d");
Stream<Integer> stream3=Stream.of(1,2,3,4,5);
3.使用集合
List<Integer> list =Arrays.asList(1,2,3,4);
//普通流
Stream<Integer> stream01=list.stream();
//并行流
Stream<Integer> stream02=list.parallelStream();
Stream转换成数组、集合
1.Stream-->数组
//String[] :: new 等价于创建一个new String[stream元素个数]
List<Integer> list=Arrays.asList(1,2,3,4,5);
Integer[] arr=list.stream().toArray(Integer[]::new);//Stream-->数组
System.out.println(Arrays.toString(arr));
2.Stream-->List、Set、Stack
//Stream-->List、Set、Stack
List<String> list3=Arrays.asList("a","b","c","a"); //将list--->Stream
Stream<String> stream1=list3.stream(); //将Stream ---> list
List<String> list4=stream1.collect(Collectors.toList());
System.out.println(list4); //将Stream ---> Set
Set<String> set1=stream1.collect(Collectors.toSet());
System.out.println(set1); //将Stream ---> Stack
Stack<String> stack=stream1.collect(Collectors.toCollection(Stack::new));
Stream流的操作方法:
流的链式调用有两类方法:一类是中间操作,指的是调用过程中会产生新的Stream对象进而用来调用新的方法。另一类是终端操作,指的是调用这类方法会终止掉Stream流,从而结束掉链式调用。
常用操作方法:
中间操作方法:
- filter:过滤,将符合条件的数据保留下来生成一个新的Stream
- sorted:排序,对Stream中元素进行排序,然后生成一个新的Stream
- distinct:去掉重复值,将不重复的元素 生成一个新的Stream
- map:遍历流中每一个元素,生成一个新的Stream对象
- flatMap:将每一个元素拆分成新的流
- limit:截断流,返回一个不超过给定长度的新Stream对象
终端操作方法:
- forEach:遍历流中元素,会关闭流
- findFirst:返回第一个元素
- findAny:
- allMatch:要求所有Stream中所有元素都满足条件才返回true
- noneMatch:要求所有Stream中所有元素都不满足才返回true
- anyMatct:要求所有Stream中只要有一个元素满足就返回true
- reducr:把Stream中元素按照一种规则串起来,参数必须要是Integer类型或者Double类型
- count:返回Stream中元素的个数
- collect:将Stream装换为别的类型(List、Set、Stack等)
- groupingBy:Collections中用于分组的方法
中间操作: Stream<T> distinct() 去重
Stream<T> filter(Predicate<? super T> predicate) 过滤
<R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper) 1:n映射
Stream<T> limit(long maxSize) 获取指定个数元素的Stream
<R> Stream<R> map(Function<? super T,? extends R> mapper) IntStream mapToInt(ToIntFunction<? super T> mapper) 将对象某个属性为int 字段存入IntStream中
Stream<T> sorted() 返回由此流的元素组成的流,根据自然顺序排序。
Stream<T> sorted(Comparator<? super T> comparator)
终端操作: boolean allMatch(Predicate<? super T> predicate) Stream中所有元素否满足条 件才返回true
boolean anyMatch(Predicate<? super T> predicate) Stream中有任意一个元素满 足条件返回true
boolean noneMatch(Predicate<? super T> predicate) Stream中所有元素都不满足 条件返回true
<R,A> R collect(Collector<? super T,A,R> collector) 将Stream转换成 数 组、List、Set 结合groupingBy分组 使用转换map
Optional<T> findAny() Optional<T> findFirst() void forEach(Consumer<? super T> action) 遍历Stream中元素
Optional<T> max(Comparator<? super T> comparator) 根据提供的 Comparator返回此流的最大元素。
Optional<T> min(Comparator<? super T> comparator) 根据提供的 Comparator返回此流的最小元素。
Optional<T> reduce(BinaryOperator<T> accumulator)
在使用filter时会使用到Lambda表达式,因此介绍一下Lambda表达式:
首先,Lambda表达式是JDK1.8版本新增加特性,它的格式如下;
Lambda表达式的格式:
第一部分:(参数)
第二部分:->
第三部分:方法体
Lambda表达式的功能是为了替代匿名内部类。
它适用于只有一个抽象方法的接口(方法大于1就不知道传入参数是哪个方法的参数了)。
还有就是作为函数式接口适用于函数式编程场景(因为Java中的函数式编程体现就是Lambda,所以函数式接口就是可以使用Lambda的接口)。
使用例子来对比一下使用Lambda表达式和不使用的区别:
package com.lambda;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.function.Consumer;
public class Demo1 {
public static void main(String[] args) {
List<String> list= new ArrayList<String>();
Collections.addAll(list, "科特迪瓦", "阿根廷", "澳大利亚", "塞尔维亚", "荷兰",
"尼日利亚", "日本", "美国", "中国", "新西兰", "巴西", "比利时",
"韩国", "喀麦隆", "洪都拉斯", "意大利");
//匿名内部类
Collections.sort(list,new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.length()-o2.length();
}
});
//未简化版Lambda表达式
Collections.sort(list,(String o1,String o2) -> {return o1.length()-o2.length();});
//简化版Lambada表达式
Collections.sort(list,(o1,o2) -> o1.length()-o2.length());
//使用foreach遍历
list.forEach(new Consumer<String>() {
@Override
public void accept(String t) {
System.out.println(t);
}} );
//使用lambda表达式遍历
list.forEach(t->System.out.println(t));
//简化lambda表达式
list.forEach(System.out::println);
}
}
使用例子来看看Lambda在函数式接口在中的作用:
介绍一下,我使用了Predicate类,我们只用把它理解为过滤的条件就行,因为它创建的对象的作用确实就是为了给过滤器提供过滤条件。
package com.lambda;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class Demo4 {
public static void main(String[] args) {
List<String> list=Arrays.asList("Java","Peee","JSwing","Python");
//过滤条件
Predicate<String> tj1=(t)->t.startsWith("J");
Predicate<String> tj2=(t)->t.length()==4;
//stream是对集合功能的增强操作,然后调用过滤器,过滤条件通过Lambda表达式定义
list.stream().filter(tj1.and(tj2)).forEach(System.out::println);
}
}
以上是我对Lambda表达式的入门级的理解和总结。接下来接着介绍Stream的相关内容方法。其他的方法都相对比较简单,通过简单的例子应该就能理解它们的用法,在此只着重介绍分组的相关内容。
分组(待补充和修正)
首先要知道哪里使用分组?
通常理解题目意思时出现按照某种条件分类讨论问题的时候,就需要想到可能使用分组。
分组的调用方法?
调用collect方法,参数可以传递分组,格式为:collect(Collectors.groupingBy(分组条件));