一.引言
现在有个任务,如下所示:
ArrayList<String> list = new ArrayList<>(); list.add("张无忌"); list.add("周芷若"); list.add("赵敏"); list.add("张强"); list.add("张三丰");将这些数据中姓张的,并且名字是三个字的单独放一个集合打印出来
我们可以使用增强for循环来完成遍历和筛选,如下代码所示:
ArrayList<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");
//把所有张开头的人加到一个集合中
ArrayList<String> arrayList = new ArrayList<>();
for (String name : list) {
if (name.startsWith("张")){
arrayList.add(name);
}
}
//把张姓的三字人名加到一个集合中
ArrayList<String> list1 = new ArrayList<>();
for (String s : arrayList) {
int length = s.length();
if (length == 3){
list1.add(s);
}
}
System.out.println(list1);
可见使用增强for循环来遍历略显复杂,我们接下来使用Stream流来进行遍历筛选
ArrayList<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");
list.stream()
.filter(name->name.startsWith("张"))
.filter(name->name.length() == 3)
.forEach(name-> System.out.println(name));
使用Stream流来遍历,大大简化了代码复杂度
二.获取Stream流
Stream流的思想就相当于一个流水线一样,将数据放在流水线上层层处理,最终输出
使用Stream流步骤有三个:
- 获取Stream流,并将数据装到流里
- 使用中间操作处理流
- 使用终结操作处理流
下面逐一说说这三个步骤
首先是获取Stream流,针对不同类型的集合有不同的方式
- 单列集合 default Stream<E> stream() Collection中默认的方法
ArrayList<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
//单列集合获取Stream流
Stream<String> stream = list.stream();
stream.forEach(name-> System.out.println(name));
- 双列集合 没有直接能获取Stream流的方式,需要借助keySet和entrySet
Map<String, Integer> map = Map.of("a", 111, "b", 222, "c", 333);
//方式一:获取map的key
map.keySet().stream().forEach(key-> System.out.println(key));
//方式二:获取map的key和value
map.entrySet().stream().forEach(s-> System.out.println(s));
- 数组 public static <T> Stream(T[] array) Arrays工具类中的静态方法
String[] str = {"a","b","c","d","e"};
Arrays.stream(str).forEach(s-> System.out.println(s));
- 一堆零散数据 public static <T> Stream<T> of(T...values) Stream接口中的静态方法
Stream.of("1","2","3").forEach(s-> System.out.println(s));
三.Stream常见中间方法
- filter方法——过滤不需要的数据
这个例子可以看看目录一中的代码
- limit方法——获取流中前几个元素
List<String> list = Arrays.asList("a-12", "b-13", "c-20");
//获取前两个元素
list.stream().limit(2).forEach(s-> System.out.println(s));
- skip方法——跳过前几个元素
List<String> list = Arrays.asList("a-12", "b-13", "c-20");
//跳过前一个元素
list.stream().skip(1).forEach(s-> System.out.println(s));
- distinct方法——元素去重(依赖于hashcode和eqauls方法,需要重写)
List<String> list = Arrays.asList("a-12", "b-13", "c-20", "c-20");
//元素去重
list.stream().distinct().forEach(s-> System.out.println(s));
- map方法——转换流中的数据类型
List<String> list = Arrays.asList("a-12", "b-13", "c-20", "c-20");
//对元素进行筛选,留下每个元素的数字部分,并且转换成整型
list.stream()
.map(s->Integer.parseInt(s.split("-")[1]))
.forEach(s-> System.out.println(s));
四.Stream常见终结方法
- forEach方法——获取每一个元素
看看上面的例子里的代码,有关于forEach的使用
- toArray方法——将流转换成数组
List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd");
Object[] array = list.stream().toArray();
toArray()有两种重载形式,上面这种不需要参数的方法,它返回一个Object类型的数组,如果我们要想返回具体的类型,需要使用带参数的toArray方法,如下所示
String[] strings = list.stream().toArray(new IntFunction<String[]>() {
@Override
public String[] apply(int value) {
//参数value表示数组的长度
return new String[value];
}
});
这个方法的参数,需要一个具体类型的数组,如下所示,表示泛型是一个具体类型的数组
刚刚上面的代码是使用匿名内部类实现的,我们现在看看Lambda表达式的形式,如下所示
list.stream().toArray(value->new String[value]);
- count方法——返回元素的个数
long count = list.stream().count();
- collect方法——收集元素并放到集合中
//收集数据并将其存放进List中
List<String> collect1 = list.stream().collect(Collectors.toList());
//收集数据并将其存放进Set中
Set<String> collect2 = list.stream().collect(Collectors.toSet());
//收集数据并将其存放进Map中
Map<String, String> collect = list.stream()
.collect(Collectors.toMap(
k -> k.split("-")[0], v -> v.split("-")[1]
)
);
主要讲一下这个toMap方法,有两个参数,第一个参数是Map的key,第二个是value,这个方法中的匿名内部类和刚刚上面讲的中间方法Map的匿名内部类是一样的