开篇
最近开始写一些项目才发现Java8的新特性有一些特别重要的结果自己还没有真正学习过,比如现在在项目中经常用到的Stream流,用于简化代码可以说事半功倍,今天抽了段时间专门来消化这些知识,并通过一个应用来巩固复习一下。
Stream流的使用步骤
- 获取Stream流对象
- 使用中间方法处理数据
- 使用终结方法处理数据
下面我们一步步来看:
一、获取Stream流对象
- 单列集合 default Stream stream() Collections中的默认方法
//获取Stream流,也就是把list中的数据放到stream流中
Stream<String> stream = list.stream();
- 双列集合无法直接使用Stream流,需要先通过keySet()或entrySet()转为单列集合
//法1
hashMap.entrySet().stream().forEach(s -> System.out.println(s));
//法2
hashMap.keySet().stream().forEach(s -> System.out.println(s));
- 数组 public static Stream stream(T[] array) Arrays工具类中的静态方法
String[] a = {"sda","sda","a"};
Arrays.stream(a).forEach(s-> System.out.println(s));
- 一堆零散数据 public static Stream of(T… values) Stream接口中的静态方法
Stream.of(1,2,3,4,"5").forEach(s-> System.out.println(s));
二、中间方法处理数据
首先我们需要知道一些常用的中间方法,如下:
/*
常见中间方法:
filter 数据过滤
limit 获取前面几个元素
skip 跳过前几个元素
distinct 元素去重(依赖hashcode和equals方法),所以对象记得重写这两个方法
concat 合并a和b的两个流和为一个
map 转换流中的数据类型
注意:
注意1:中间方法,返回新的Stream流,原来的Stream只能使用1次,所以建议使用链式编程
注意2:终结方法,返回新的数据,对原来的数据不造成影响
*/
通过代码举例使用:
ArrayList<String> list = new ArrayList<>();
list.add("cc");
list.add("cas");
list.add("caw");
list.add("44");
list.add("66");
list.add("dds");
//filter
list.stream().filter(s -> s.startsWith("c")).forEach(s -> System.out.print(s+" "));
System.out.println();
System.out.println("=============");
//skip
list.stream().skip(2).forEach(s-> System.out.print(s+" "));
System.out.println();
System.out.println("=============");
//取过滤后的跳过2个元素的后面的元素
list.stream().filter(s -> s.startsWith("c")).skip(2).forEach(s -> System.out.println(s));//caw
list.add("cc");
System.out.println();
System.out.println("=============");
//distinct
list.stream().distinct().forEach(s-> System.out.print(s+" "));//ccc as caw 44 66 dds
System.out.println();
System.out.println("=============");
//limit
list.stream().filter(s -> s.startsWith("c")).limit(2).forEach(s -> System.out.print(s + " "));
System.out.println();
System.out.println("=============");
//concat
ArrayList<String> strings = new ArrayList<>();
strings.add("yjh");
strings.add("wu");
Stream.concat(list.stream(),strings.stream()).forEach(s -> System.out.print(s+" "));//cc cas caw 44 66 dds cc yjh wu
System.out.println(" ============= ");
//map
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("dasd","22");
hashMap.put("das3d","3");
hashMap.put("d2asd","33");
hashMap.put("1dasd","2222");
//要求将hsahMap中的value值转换成int类型
//s 就为 dasd=22 ...
hashMap.entrySet().stream().map(s->Integer.parseInt(s.getValue())).forEach(s-> System.out.print(s+" "));//22 3 33 2222
}
三、终结方法处理数据
终结方法如下:
在这里插入代码片 /**
* 终结方法:
* foreach 遍历
* count 统计
* toArray 转数组
* collect(Collertor collector) 收集流中的数据到(List Set Map)
*/
对于前三种简单的,我们同样使用代码举例使用:
ArrayList<String> list = new ArrayList<>();
list.add("cc");
list.add("cas");
list.add("caw");
list.add("44");
list.add("66");
list.add("dds");
list.stream().forEach(s -> System.out.println(s));
long count = list.stream().count();
System.out.println(count);
//Arrays
//toArray方法参数作用,负责创建一个指定类型的底层
//toArray方法底层,会依次得到流里面的每一个数据,并把数据放到数组中
//toArray的返回值:是一个装着流里面的所有数据的数组
String[] array = list.stream().toArray(new IntFunction<String[]>() {
@Override
public String[] apply(int value) {
return new String[value];
}
});
System.out.print(Arrays.toString(array)+" ");//[cc, cas, caw, 44, 66, dds]
String[] strings = list.stream().toArray(value -> new String[value]);
System.out.print(Arrays.toString(strings)+" ");//[cc, cas, caw, 44, 66, dds]
}
第四种,收集流中的数据到(List Set Map等等)
较于前三种比较复杂一些,主要体现在转map的过程中,如下:
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("cc-1");
list.add("cas-1");
list.add("caw-2");
list.add("44-3");
list.add("66-1");
list.add("dds-2");
//收集-后为1的数据
// 到List集合中
List<String> collect = list.stream().filter(s -> "1".equals(s.split("-")[1]))
.collect(Collectors.toList());
//到set集合中
Set<String> collect1 = list.stream().filter(s -> "1".equals(s.split("-")[1]))
.collect(Collectors.toSet());
//收集到List和Set的区别就是集合的区别,一个可以重复一个不可以重复嘛
//到Map集合中,注意:收集到map集合中不能存在重复数据,否则会报错
/**
* toMap:参数一表示键的生成规则
* 参数二表示值的生成规则
* 参数一:
* Function泛型一:表示流中每个数据的类型
* 泛型二:表示Map集合中每个键的类型
* 参数二:
* Function泛型一:表示流中每个数据的类型
* 泛型二:表示Map集合中每个值的类型
* 方法apply形参:依次表示流里面的每一个数据
* 方法体:生成值的代码
* 返回值:已经生成的值
*/
//匿名内部类写法
Map<String, String> map = list.stream().filter(s -> "1".equals(s.split("-")[1]))
.collect(Collectors.toMap(new Function<String, String>() {
@Override
public String apply(String s) {
return s.split("-")[0];
}
},
new Function<String, String>() {
@Override
public String apply(String s) {
return s.split("-")[1];
}
}));
System.out.println(map);//{66=1, cc=1, cas=1}
//lambda写法
Map<String, String> map1 = list.stream().filter(s -> "1".equals(s.split("-")[1]))
.collect(Collectors.toMap(
s -> s.split("-")[0],
s -> s.split("-")[1]
));
System.out.println(map1);//{66=1, cc=1, cas=1}
四、综合应用
ArrayList<String> arrayList = new ArrayList<>();
arrayList.add("啊啊,23");
arrayList.add("呜呜呜呜,24");
arrayList.add("阿萨德,25");
arrayList.add("嗷嗷,25");
arrayList.add("急急急,25");
arrayList.add("阿闪大,25");
//1.男的只要3个字的前两个人
List<String> boyList = arrayList.stream()
.filter(x -> x.split(",")[0].length() == 3)
.limit(2)
.collect(Collectors.toList());
System.out.println(boyList);//[阿萨德,25, 急急急,25]
ArrayList<String> arrayList1 = new ArrayList<>();
arrayList1.add("杨孩子1,23");
arrayList1.add("杨孩子2,24");
arrayList1.add("女孩子,25");
arrayList1.add("女孩子2,25");
arrayList1.add("女孩子3,25");
arrayList1.add("女孩1子,25");
//2.女孩只要只要姓杨的且不要第一个
List<String> girlList = arrayList1.stream()
.filter(x -> x.startsWith("杨"))
.skip(1)
.collect(Collectors.toList());
System.out.println(girlList);//[杨孩子2,24]
//3.把过滤后的男的和女的拼成一个list
List<String> boyAndGirlList = Stream.concat(boyList.stream(), girlList.stream())
.collect(Collectors.toList());
System.out.println(boyAndGirlList);//[阿萨德,25, 急急急,25, 杨孩子2,24]
//4.上一步的信息封装成Actor对象并存入一个list中
ArrayList<Actor> actors = new ArrayList<>();
for (String ac : boyAndGirlList) {
String[] split = ac.split(",");
Actor actor = new Actor();
actor.setName(split[0]);
actor.setAge(Integer.parseInt(split[1]));
actors.add(actor);
}
System.out.println(actors);
//[Actor{name='阿萨德', age=25}, Actor{name='急急急', age=25}, Actor{name='杨孩子2', age=24}]
//3,4可通过map转换来合并
List<Actor> actorList = Stream.concat(boyList.stream(), girlList.stream())
.collect(Collectors.toList())
.stream().map(x -> new Actor(x.split(",")[0], Integer.parseInt(x.split(",")[1])))
.collect(Collectors.toList());
System.out.println(actorList);
//[Actor{name='阿萨德', age=25}, Actor{name='急急急', age=25}, Actor{name='杨孩子2', age=24}]
5、总结
Stream流结合了Lambda表达式,简化了集合、数组的操作,让很多对集合操作的长段代码大幅度缩减。虽然这不可避免地让代码的可读性变差了一些,但实用性却是毋庸置疑的。