JDK8新特性(二) 流式编程Stream

流式编程是1.8中的新特性,基于常用的四种函数式接口以及Lambda表达式对集合类数据进行类似流水线一般的操作

流式编程分为大概三个步骤:获取流 → 操作流 → 返回操作结果

流的获取方式

这里先了解获取流的常用的两种方式,后面在进行流的操作

集合中获取流

众所周知Java中所有的集合都是Collection下的实现类,在Collection接口中就提供了获取流的方法:

public class ApplicationMain {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        // 获取流
        Stream<Integer> stream1 = list.stream();
        // 获取流(多线程,大数据量下效率较高)
        Stream<Integer> stream2 = list.parallelStream();
    }
}

数组中获取流

针对数组Java中提供了一个Arrays工具类,我们可以将数组转换为集合在获取流

public class ApplicationMain {
    public static void main(String[] args) {
        Integer[] arr = {1, 2, 3, 4, 5};
        List<Integer> list = Arrays.asList(arr);
        Stream<Integer> stream1 = list.stream();
        Stream<Integer> stream2 = list.parallelStream();
    }
}

或者直接通过Arrays类获取到流

public class ApplicationMain {
    public static void main(String[] args) {
        Integer[] arr = {1, 2, 3, 4, 5};
        Stream<Integer> stream = Arrays.stream(arr);
    }
}

流的获取方式 总结与补充

方法名 说明
Collection.stream() 从集合中获取流
Collection.parallelStream() 从集合中获取流 ( 多线程 )
Arrays.stream(T[]) 从数组中获取流
Stream.of(T... values) 直接传入多个元素返回一个流
Stream.generate(Supplier s) Lambda返回的每个实例都是流中的一个元素
Stream iterate(final T seed, final UnaryOperator f) Lambda接收参数一个参数,返回一个结果作为元素,每次返回的结果都将作为下一个Lambda的参数 ( 迭代 )

操作流中的数据

假数据模拟

知道了如何获取到流之后,就要开始学习操作流了,在练习之间先写一个假的接口来模拟数据:

// 接口模拟数据
public class UserService {
    public List<UserEntity> selectList() {
        ArrayList<UserEntity> list = new ArrayList<>();
        list.add(new UserEntity("老八", 32, '男', 8000));
        list.add(new UserEntity("郭老师", 36, '女', 7000));
        list.add(new UserEntity("卢本伟", 32, '男', 18000));
        list.add(new UserEntity("张春德", 22, '男', 2800));
        list.add(new UserEntity("大司马", 34, '男', 12000));
        list.add(new UserEntity("老八", 32, '男', 8000));
        list.add(new UserEntity("贾玲", 22, '女', 21000));
        list.add(new UserEntity("周淑怡", 26, '女', 14800));
        list.add(new UserEntity("PDD", 37, '男', 26300));
        return list;
    }
}
// UserEntity实体类
public class UserEntity {

    private String name;
    private int age;
    private char gender;
    private int salary;

    public UserEntity(){}
    public UserEntity(String name, int age, char gender, int salary) {
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.salary = salary;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public char getGender() {
        return gender;
    }
    public void setGender(char gender) {
        this.gender = gender;
    }
    public int getSalary() {
        return salary;
    }
    public void setSalary(int salary) {
        this.salary = salary;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        UserEntity that = (UserEntity) o;
        return getAge() == that.getAge() &&
                getGender() == that.getGender() &&
                getSalary() == that.getSalary() &&
                getName().equals(that.getName());
    }
    @Override
    public int hashCode() {
        return Objects.hash(getName(), getAge(), getGender(), getSalary());
    }

    @Override
    public String toString() {
        return "{" +
                "姓名='" + name + '\'' +
                ", 年龄=" + age +
                ", 性别=" + gender +
                ", 薪水=" + salary +
                '}';
    }
}

函数式接口复习

在操作流式编程之前先来复习一下函数式编程,想要实现一个集合的过滤器函数:

public class ApplicationMain {

    public static void main(String[] args) {
        UserService userService = new UserService();
        List<UserEntity> list = userService.selectList();
        // 获取所有女性员工
        ArrayList<UserEntity> result = filter(list, item -> item.getGender() == '女');
        result.forEach(System.out::println);
    }

    public static ArrayList<UserEntity> filter(List<UserEntity> list, Predicate<UserEntity> predicate) {
        // 创建一个结果集
        ArrayList<UserEntity> result = new ArrayList<>();
        // 空值校验
        if (list == null || list.size()==0)
            return null;
        // 遍历传入的集合,根据调用者制定的过滤规则进行判断,符合条件就添加到结果集中
        for (UserEntity entity : list) {
            if (predicate.test(entity)) {
                result.add(entity);
            }
        }
        return result;
    }

}

这样我们就获取到了一个 ArrayList 集合的过滤器

操作流的方法

流式编程操作流非常类似上面的代码,常用函数如下所示:

方法名 说明
filter() 循环集合中每个元素进行判断,返回false的元素会被过滤掉
limit() 截取方法,传入 int 类型的 n,从第一个元素开始只获取 n 个
skip() 跳过方法,传入 long 类型的 n,流将从第 n+1 个元素开始操作
distinct() 去重方法,去掉集合中重复的元素,只保留第一个
sorted() 排序方法,通过判断返回的 boolean 值作为参考进行排序

使用流式编程需要了解他的特点:

  1. 我们通过流式编程操作集合是不会影响集合本身
  2. 流式编程的代码都是延迟执行的,只有在获取结果的时候才会执行

filter 过滤方法

// 获取到薪水大于10000的所有用户
public class ApplicationMain {
    public static void main(String[] args) {
        UserService userService = new UserService();
        List<UserEntity> list = userService.selectList();
        list.stream()
                .filter(item->item.getSalary()>10000)
                .forEach(System.out::println);
    }
}

limit 截取方法

// 只获取结果中的5条数据(从首个开始截取)
public class ApplicationMain {
    public static void main(String[] args) {
        UserService userService = new UserService();
        List<UserEntity> list = userService.selectList();
        list.stream()
                .limit(5)
                .forEach(System.out::println);
    }
}

skip 跳过方法

// 这里就跳过了2个元素,从"卢本伟"开始操作
public class ApplicationMain {
    public static void main(String[] args) {
        UserService userService = new UserService();
        List<UserEntity> list = userService.selectList();
        list.stream()
                .skip(2)
                .forEach(System.out::println);
    }
}

distinct:去重方法

这里需要提一嘴,使用distinct方法操作的实体类必须复写equalshashCode方法

// 去重操作,可以看到两个老八只剩下一个
public class ApplicationMain {
    public static void main(String[] args) {
        UserService userService = new UserService();
        List<UserEntity> list = userService.selectList();
        list.stream()
                .distinct()
                .forEach(System.out::println);
    }
}

sorted :排序方法

// 通过薪水对集合进行排序
public class ApplicationMain {
    public static void main(String[] args) {
        UserService userService = new UserService();
        List<UserEntity> list = userService.selectList();
        list.stream()
                // 排序需要传入一个Comparator比较器,这里通过Integer直接获取
                // 通过调换item1和item2的顺序实现升序降序的调整
                .sorted((item1, item2)->Integer.compare(item1.getSalary(), item2.getSalary()))
                .forEach(System.out::println);
    }
}

返回操作结果

返回操作结果是流式编程最后一步,也是最关键的一步,之前说过流式编程操作集合不会影响集合本身,那么想要获取结果就需要进行这最后一步,需要注意的是流式编程只有在返回操作结果的时候才会执行操作代码

之前使用的forEach就属于返回结果的代码,如果只调用了filter方法而没有调用返回结果,那么filter方法是不会执行的,可以使用下面这段代码进行测试

// 代码正常执行,如果将forEach移除就会发现filter中的打印语句同样没有执行
public class ApplicationMain {
    public static void main(String[] args) {
        UserService userService = new UserService();
        List<UserEntity> list = userService.selectList();
        list.stream()
                .filter(item->{
                    System.out.println("过滤代码执行了");
                    return item.getSalary() > 10000;
                }).forEach(System.out::println);
    }
}

常用获取结果的方法

方法名 作用
forEach() 对流中的数据进行遍历
min() 传入比较器获取最小值
max() 传入比较器获取最大值
count() 计算最终结果的数量
collect() 将操作结果转换为集合

forEach:循环遍历

// forEach是最简单的循环遍历,没什么好说的
public class ApplicationMain {
    public static void main(String[] args) {
        UserService userService = new UserService();
        List<UserEntity> list = userService.selectList();
        list.stream()
                .filter(item->item.getSalary() > 10000)
                .forEach(System.out::println);
    }
}

min:取最小值

public class ApplicationMain {
    public static void main(String[] args) {
        UserService userService = new UserService();
        List<UserEntity> list = userService.selectList();
        UserEntity entity = list.stream()
                .filter(item -> item.getSalary() > 10000)
                // 获取最小值需要传入Comparator比较器,直接从Comparator中取出Int类型比较器
                .mim(Comparator.comparingInt(UserEntity::getSalary))
                // 这里并不会直接返回实体类,需要在get一下才能获取到
                .get();
        System.out.println(entity);
    }
}

max:取最大值

public class ApplicationMain {
    public static void main(String[] args) {
        UserService userService = new UserService();
        List<UserEntity> list = userService.selectList();
        UserEntity entity = list.stream()
                .filter(item -> item.getSalary() > 10000)
                // max同min一致
                .max(Comparator.comparingInt(UserEntity::getSalary))
                .get();
        System.out.println(entity);
    }
}

count:对结果进行计数

// 获取月薪大于10000的人数
public class ApplicationMain {
    public static void main(String[] args) {
        UserService userService = new UserService();
        List<UserEntity> list = userService.selectList();
        long count = list.stream()
                .filter(item -> item.getSalary() > 10000)
                .count();
        System.out.println(count);
    }
}

collect:返回操作结果

public class ApplicationMain {
    public static void main(String[] args) {
        UserService userService = new UserService();
        List<UserEntity> list = userService.selectList();
        List<UserEntity> collect = list.stream()
                .filter(item -> item.getSalary() > 10000)
                // 直接调用collect方法,然后调用toList将结果转换为List集合
                .collect(Collectors.toList());
        System.out.println(collect);
    }
}

流式编程综合练习

// 流式编程+链式编程
public class ApplicationMain {
    public static void main(String[] args) {
        UserService userService = new UserService();
        List<UserEntity> list = userService.selectList();
        List<UserEntity> result = list.stream()
                // 找到所有男性员工
                .filter(item->item.getGender()=='男')
                // 去除重复数据
                .distinct()
                // 按照年龄进行排序
                .sorted(Comparator.comparingInt(UserEntity::getAge))
                // 最后转换为List集合
                .collect(Collectors.toList());
        result.forEach(System.out::println);
    }
}
上一篇:JDK8新特性 Lambda表达式及相关特性


下一篇:Linux安装Jdk8环境