Stream流常用方法
简介
Java8 也出来好久了,接口默认方法,lambda 表达式,函数式接口,Date API 等特性还是有必要去了解一下。比如在项目中经常用到集合,遍历集合可以试下 lambda 表达式,经常还要对集合进行过滤和排序,Stream 就派上用场了。用习惯了,不得不说真的很好用。
Stream 作为 java8 的新特性,基于 lambda 表达式,是对集合对象功能的增强,它专注于对集合对象进行各种高效、便利的聚合操作或者大批量的数据操作,提高了编程效率和代码可读性。
Stream 的原理:将要处理的元素看做一种流,流在管道中传输,并且可以在管道的节点上处理,包括过滤筛选、去重、排序、聚合等。元素流在管道中经过中间操作的处理,最后由最终操作得到前面处理的结果。
集合有两种方式生成流:
stream() − 为集合创建串行流
parallelStream() - 为集合创建并行流
上图中是 Stream 类的类结构图,里面包含了大部分的中间和终止操作。
中间操作主要有以下方法(此类型方法返回的都是 Stream):map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered
终止操作主要有以下方法:forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator
举例说明:
首先为了说明 Stream 对象集合的操作,新建一个 Student 类(学生类)
package cn.ilove.learn.stream.pojo;
import lombok.Data;
/**
* @author Ziheng·Z
* @date Created in 2020-01-15 16:26
*/
@Data
public class Student {
private Long id;
private String name;
private int age;
private String address;
public Student() {
}
public Student(Long id, String name, int age, String address) {
this.id = id;
this.name = name;
this.age = age;
this.address = address;
}
}
filter(筛选)
package cn.ilove.learn.stream;
import cn.ilove.learn.stream.pojo.Student;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author Ziheng·Z
* @date Created in 2020-01-15 16:36
*/
public class StreamLearn {
public static void main(String[] args) {
Student s1 = new Student(1L, "阿里", 21, "浙江");
Student s2 = new Student(2L, "腾讯", 22, "深圳");
Student s3 = new Student(3L, "百度", 20, "北京");
Student s4 = new Student(4L, "京东", 13, "北京");
Student s5 = new Student(5L, "华为", 33, "深圳");
List<Student> students = new ArrayList<>();
students.add(s1);
students.add(s2);
students.add(s3);
students.add(s4);
students.add(s5);
testFilter(students);
}
/**
* 集合的筛选——filter
*
* @param students
* @return
*/
private static void testFilter(List<Student> students) {
// 筛选出北京的学生
students.stream().filter(s -> ("北京").equals(s.getAddress())).collect(Collectors.toList()).forEach(System.out::println);
// 筛选年龄大于15岁的学生
// students.stream().filter(s -> s.getAge()>15).collect(Collectors.toList()).forEach(System.out::println);
}
}
运行结果:
map(转换)
/**
* 集合的转换——map:将对应的元素按照给定的方法进行转换。
*
* @param students
*/
private static void testMap(List<Student> students) {
// 在名字前面加上部分信息,只获取姓名
students.stream().map(s -> "姓名:" + s.getName()
).collect(Collectors.toList()).forEach(System.out::println);
}
运行结果:
distinct(去重)->引用类型
public class StreamLearn {
public static void main(String[] args) {
Student s1 = new Student(1L, "阿里", 21, "浙江");
Student s2 = new Student(2L, "腾讯", 22, "深圳");
Student s3 = new Student(3L, "百度", 20, "北京");
Student s4 = new Student(4L, "京东", 13, "北京");
Student s5 = new Student(5L, "华为", 33, "深圳");
Student s6 = new Student(1L, "阿里", 21, "浙江");
Student s7 = new Student(2L, "腾讯", 22, "深圳");
List<Student> students = new ArrayList<>();
students.add(s1);
students.add(s2);
students.add(s3);
students.add(s4);
students.add(s5);
testDistinct(students);
}
/**
* 集合的去重——distinct(引用对象)
*
* @param students
*/
private static void testDistinct(List<Student> students) {
// 注意:引用对象的去重,引用对象要实现hashCode和equal方法,否则去重无效
students.stream().distinct().forEach(System.out::println);
}
}
运行结果:
distinct(去重)->基本类型
/**
* 集合的去重——distinct(基本类型)
*/
private static void testDistinct2() {
List<String> list = new ArrayList<>();
list.add("123");
list.add("456");
list.add("456");
list.add("789");
list.add("123");
list.stream().distinct().forEach(System.out::println);
}
运行结果:
sorted(排序一)
/**
* 集合的排序——sorted (默认排序)
*/
private static void testSorted() {
List<String> list = new ArrayList<>();
list.add("123");
list.add("789");
list.add("456");
list.stream().sorted().forEach(System.out::println);
}
运行结果:
sorted(排序二)
/**
* 集合的排序——sorted(引用类型)
* 按照id降序排序
*/
private static void testSorted2(List<Student> students) {
students.stream()
.sorted((stu1, stu2) -> Long.compare(stu2.getId(), stu1.getId()))
.forEach(System.out::println);
}
运行结果:
limit(限制返回个数)
/**
* limit(限制返回个数)
*/
private static void testLimit() {
List<String> list = new ArrayList<>();
list.add("123");
list.add("456");
list.add("789");
list.stream().limit(2).forEach(System.out::println);
}
运行结果:
skip(跳过元素)
/**
* skip:方法是一个中间操作,跳过stream中的前n个元素,n不能为负值。
* 如果n大于stream的大小,则返回空stream。
*/
private static void testSkip() {
List<String> list = new ArrayList<>();
list.add("123");
list.add("456");
list.add("789");
list.stream().skip(2).forEach(System.out::println);
}
运行结果:
reduce(聚合)
/**
* reduce(聚合)
*/
private static void testReduce() {
List<String> list = new ArrayList<>();
list.add("欢");
list.add("迎");
list.add("你");
list.add("!");
String s = list.stream().reduce("上海", (a, b) -> a + b);
System.out.println(s);
}
运行结果:
max/min(求最大/最小值)
/**
* Max/Min(最大值/最小值)
* 年龄最大的一个
*
* @param students
*/
private static void testMax(List<Student> students) {
Student studentMax = students.stream().max(Comparator.comparing(Student::getAge)).get();
// Student studentMin = students.stream().max(Comparator.comparing(Student::getAge)).get();
System.out.println(studentMax);
// System.out.println(studentMin);
}
运行结果:
anyMatch/allMatch/noneMatch(匹配)
/**
* anyMatch/allMatch/noneMatch(匹配)
*
*anyMatch:Stream 中任意一个元素符合传入的 predicate,返回 true
*
*allMatch:Stream 中全部元素符合传入的 predicate,返回 true
*
*noneMatch:Stream 中没有一个元素符合传入的 predicate,返回 true
*
* @param students
*/
private static void testAnyAllNoneMatch(List<Student> students) {
boolean anyMatch = students.stream().anyMatch(s -> "阿里".equals(s.getName()));
if (anyMatch) {
System.out.println("有叫 阿里 的同学!");
}
boolean allMatch = students.stream().allMatch(s -> s.getAge() >= 13);
if (allMatch) {
System.out.println("所有同学都满13岁");
}
boolean noneMatch = students.stream().noneMatch(s -> "美团".equals(s.getName()));
if (noneMatch){
System.out.println("没有叫 美团 的同学");
}
}
运行结果:
count(元素个数)
/**
* count:元素个数(终止操作)
*
* @param students
*/
private static void testCount(List<Student> students) {
long count = students.stream().count();
System.out.println(count);
}
运行结果:
总结
上面介绍了 Stream 常用的一些方法,虽然对集合的遍历和操作可以用以前常规的方式,但是当业务逻辑复杂的时候,你会发现代码量很多,可读性很差,明明一行代码解决的事情,你却写了好几行。试试 lambda 表达式,试试 Stream,你会有不一样的体验。