Java 关于jdk1.8的Stream流的一些使用总结
最近看了一些关于jdk1.8新出的stream流的一些使用方式,发现很多东西在开发中能节省不少的代码量,并且十分方便,所以在这里做一些总结。
1 . 使用场景
下面都是自己的一些理解,如果有错误,请多指教;
stream流主要对集合进行操作,在真正的项目中有许多操作结合这样的场景,比如说我们从数据库查询出来的数据,需要做一层过滤,再比如所,我们要在结果集里对数据进行操作等,这写都需要我们做循环,再筛选,再进行操作,其实这并不难,但这些都给我们增加了大量的代码量,如果用stream流,用一行代码就可以解决我们的需求!
2 . 如何获取stream流对象
在jdk1.8以后,我们会发现 Collection里新增加了一个接口 Collection default Stream stream(),这说明我们的集合对象中会新增加一个方法,我们调用这个方法试试,就可以获取到我们需要的stream流对象,而我们对集合进行的操作,也都是通过这个stream流对象进行操作的。
代码对应如下:
示例代码:
public static void main(String[] args){
List<String> strList = new ArrayList<>();
strList.add("shaochen");
strList.add("shaohen");
strList.add("cool");
strList.add("bean");
strList.add("java");
strList.add("java");
// 这行获取我们的stream流对象,我们的操作都是通过这个流对象进行操作的。
Stream<String> stream = strList.stream();
// 首先我们做一个简单的循环遍历
stream.forEach(System.out::println);
}
3 . 使用stream流获取集合的长度
示例代码:
public static void main(String[] args){
List<String> strList = new ArrayList<>();
strList.add("shaochen");
strList.add("shaohen");
strList.add("cool");
strList.add("bean");
strList.add("java");
strList.add("java");
// 这行获取我们的stream流对象,我们的操作都是通过这个流对象进行操作的。
Stream<String> stream = strList.stream();
long count = stream.count();
System.out.println(count);
}
4 . 使用stream流对数据进行去重
示例代码:
public static void main(String[] args){
List<String> strList = new ArrayList<>();
strList.add("shaochen");
strList.add("shaohen");
strList.add("cool");
strList.add("bean");
strList.add("java");
strList.add("java");
// 这行获取我们的stream流对象,我们的操作都是通过这个流对象进行操作的。
Stream<String> stream = strList.stream();
// 对数据进行去重并循环遍历结果
stream.distinct().forEach(System.out::println);
}
5 . 将stream流处理后的数据收集成一个集合
示例代码:
public static void main(String[] args){
List<String> strList = new ArrayList<>();
strList.add("shaochen");
strList.add("shaohen");
strList.add("cool");
strList.add("bean");
strList.add("java");
strList.add("java");
// 这行获取我们的stream流对象,我们的操作都是通过这个流对象进行操作的。
Stream<String> stream = strList.stream();
// 去重后收集成一个集合
List<String> collect = stream.distinct().collect(Collectors.toList());
System.out.println(collect.toString());
}
6 . stream流的循环
stream流里面有两个循环遍历的方式:
Stream<T> peek(Consumer<? super T> action);
void forEach(Consumer<? super T> action);
既然出现了两种循环,肯定有一定的区别,如果你真的使用的话,你肯定会发现forEach使用后,我如果想再对stream流进行操作是不可行的,这是因为forEach是一种消费性接口,也就是返回值是void,也就是没有返回值的接口,而我们看其他的stream流提供的接口,大部分都是有返回值的,返回的也是一个Stream流对象。
前面第一个示例就是循环的示例,在这就不再重复写了
7 . stream流的map的使用
示例代码:
public static void main(String[] args){
List<String> strList = new ArrayList<>();
strList.add("shaochen");
strList.add("shaoChen");
strList.add("cool");
strList.add("bean");
strList.add("java");
strList.add("java");
// 这行获取我们的stream流对象,我们的操作都是通过这个流对象进行操作的。
Stream<String> stream = strList.stream();
// 将集合中的数据循环变为大写字母,然后过滤,找到包含A的数据,循环打印出来
stream.map(s -> s.toUpperCase()).filter(s -> s.contains("A")).forEach(System.out::println);
}
map可以对stream流中的一行数据进行操作
8. stream流中的分页操作
示例代码:
public static void main(String[] args){
List<String> strList = new ArrayList<>();
strList.add("shaochen");
strList.add("shaoChen");
strList.add("cool");
strList.add("bean");
strList.add("java");
strList.add("java");
// 这行获取我们的stream流对象,我们的操作都是通过这个流对象进行操作的。
Stream<String> stream = strList.stream();
// stream流对数据进行分页查询
stream.skip(2).limit(2).forEach(s -> System.out.println(s));
}
可以看到有两个方法,一个skip和一个limit,skip代表着要跳过结果集中的前几个数据,limit也就是取结果集中的几个数据,也就是一个是page字段,一个是size字段,可以做到简单的分页。
9. stream流中匹配条件
stream流中有两个匹配的接口,anyMatch和allMatch;
anyMatch: 只要有一条数据可以匹配,那就会返回true
allMatch: 必须要每一条数据都匹配才会返回true
由于用法都是一样的,这里就只用anyMatch作为示例
#####8.1 如果集合中匹配一条数据就返回true
当集合中一条数据包含字符"a",就返回true
public static void main(String[] args){
List<String> strList = new ArrayList<>();
strList.add("shaochen");
strList.add("shaoChen");
strList.add("cool");
strList.add("bean");
strList.add("java");
strList.add("java");
// 这行获取我们的stream流对象,我们的操作都是通过这个流对象进行操作的。
Stream<String> stream = strList.stream();
if (stream.anyMatch(s -> s.contains("a"))) {
System.out.println("匹配");
}
}
当然我们肯定会遇到多匹配条件的情况,这样就不做不到了?不存在的,往下看
#####8.2 如果集合中匹配多条数据就返回true
我们要先定义两个断言,也就是两个条件,然后我们在stream流里面有and或者or来进行判断,顾名思义,and就是两个条件在一行数据中全都匹配,在下面的代码中的含义就是:是否有一条数据中既有"a"又有"b",如果存在就返回true,or的含义就是有"a"或者"b"就可以匹配
public static void main(String[] args){
List<String> strList = new ArrayList<>();
strList.add("shaochen");
strList.add("shaoChen");
strList.add("cool");
strList.add("bean");
strList.add("java");
strList.add("java");
// 这行获取我们的stream流对象,我们的操作都是通过这个流对象进行操作的。
Stream<String> stream = strList.stream();
Predicate<String> predicateOne = s -> s.contains("a");
Predicate<String> predicateTwo = s -> s.contains("b");
if (stream.anyMatch(predicateOne.and(predicateTwo))){
System.out.println("匹配");
}
}
暂时也就能理解到这个层次,日后会有更新的,下期再见
10 补充:使用stream流对集合进行分组
这个功能,相当于将一个excel表格中的各个单元格进行合并,首先创建一个类,这里用于集合存放的数据类型,我相信这种场景我们会经常遇到的
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Demo {
private String name;
private Integer key;
}
接下来我们创建一个数据类型为Demo的集合,并放置一些默认的数据类型
public static void main(String[] args){
List<Demo> demos = new ArrayList<>();
demos.add(getDemo("DaMing", 1));
demos.add(getDemo("DaMing", 2));
demos.add(getDemo("Amy", 3));
demos.add(getDemo("Sam", 4));
demos.add(getDemo("Sam", 5));
}
public static Demo getDemo(String name, Integer key) {
return new Demo(name, key);
}
现在这个集合里的数据如果对应在excel表格里的话,应该是这样的:
但是有时候,我们需要的并不应该是这样的数据结构,而是将他们都分好组,比如下图:
对应我们的steam流就应该是如下的操作:
public static void main(String[] args){
List<Demo> demos = new ArrayList<>();
demos.add(getDemo("DaMing", 1));
demos.add(getDemo("DaMing", 2));
demos.add(getDemo("Amy", 3));
demos.add(getDemo("Sam", 4));
demos.add(getDemo("Sam", 5));
Map<String, List<Integer>> collect = demos.stream().collect(Collectors.groupingBy(Demo::getName, Collectors.mapping(Demo::getKey, Collectors.toList())));
Set<String> keys = collect.keySet();
keys.stream().forEach(s -> System.out.println(s + " --> " + collect.get(s).toString()));
}
public static Demo getDemo(String name, Integer key) {
return new Demo(name, key);
}
输出结果如下: