宋子宪博客

Java8新特性之Stream使用

Stream是java8新增的重要新特性之一
流的操作包含如下三个部分:创建流、中间流、关闭流,筛选、去重、映射、排序属于流的中间操作,收集属于终止操作。Stream是流操作的基础关键类。
下面代码是一个简单的流对集合的操作

    List<Employee> aa = new ArrayList<>();
    List<Employee> employeeList = Arrays.asList(
            new Employee(101, "张三", 18.0000, 1),
            new Employee(102, "李四", 28.0000, 1),
            new Employee(103, "王五", 38.0000, 1),
            new Employee(104, "赵六", 48.0000, 1),
            new Employee(105, "田七", 58.0000, 1),
            new Employee(105, "田七", 58.0000, 1)
    );

List<Employee> collect = employeeList.stream().distinct().filter((e) -> e.getWage() > 50).collect(Collectors.toList());

for (Employee employee : collect) {
    System.out.println("collect="+employee.toString());
}

创建流

(1)通过集合创建流

// 通过集合创建流
List<String> lists = new ArrayList<>();
lists.stream();

(2)通过数组创建流

// 通过数组创建流
String[] strings = new String[5];
Stream.of(strings);

应用较多的是通过集合创建流,然后经过中间操作,最后终止回集合。

中间操作

筛选(filter)关键字

筛选是指从(集合)流中筛选满足条件的子集,通过 Lambda 表达式生产型接口来实现。

// 通过断言型接口实现元素的过滤

employeeList.stream().filter((e) -> e.getWage() > 50)

非空过滤

非空过滤包含两层内容:一是当前对象是否为空或者非空;二是当前对象的某属性是否为空或者非空。

筛选非空对象,语法stream.filter(Objects::nonNull)做非空断言。

// 非空断言
java.util.function.Predicate<Boolean> nonNull = Objects::nonNull;

查看Objects类了解更详细信息。

去重(distinct)

去重是指将(集合)流中重复的元素去除,注意:需要重写 hashcode 和 equals 方法来判断是否是重复元素。去重操作实现了类似于 HashSet 的运算

如果流中泛型对象使用 Lombok 插件,使用@Data注解默认重写了 hashcode 和 equals 方法,字段相同并且属性相同,则对象相等。如果没有用Lombok 记得一定要重写 hashcode 和 equals 方法才生效
语法:

stream.distinct();

案例:

//去重`employeeList`整个集合中的重复数据,并生成一个新的流
List<Employee> collect = employeeList.stream().distinct().collect(Collectors.toList());

//去重`employeeList`中工资低于大于50的重复数据,并生成一个新的流
List<Employee> collect = employeeList.stream().distinct().filter((e) -> e.getWage() > 50).collect(Collectors.toList());

映射(map)

取出流中元素的某一列,然后配合收集以形成新的集合。
案例,取出employeeList集合中的wage字段(工资)并生成一个新的集合

List<Double> collect1 = employeeList.stream().map((e) -> e.getWage()).collect(Collectors.toList());

排序(sorted)

传统的Collectors类中的排序支持 List 实现类中的一部分排序,使用 stream 排序,能够覆盖所有的 List 实现类。

// 按照默认字典顺序排序
stream.sorted();

// 按照工资大小排序
Stream<Employee> sorted = employeeList.stream().sorted((x, y) -> Integer.compare(x.getStart(), y.getStart()));

(1)函数式接口排序

基于 Comparator 类中函数式方法,能够更加优雅的实现对象流的排序。

排序小案例demo
先建一个实体类

@NoArgsConstructor //无参构造
@AllArgsConstructor //有参构造
@Data
public class Person {
    // 姓名
    private String name;
    // 薪资
    private int salary;
    // 年龄
    private int age;
    //性别
    private String sex; 
}

案例代码

 public class StreamTest02 {

    public static void main(String[] args) {
        //模拟集合数据
        List<Person> personList = new ArrayList<Person>();
        personList.add(new Person("张三",10000,23,"男"));
        personList.add(new Person("李四",20000,34,"男"));
        personList.add(new Person("王五",30000,22,"女"));


        // 按工资升序排序(自然排序) 并获取员工姓名生成一个新的流
        List<String> newList1 = personList.stream().sorted(Comparator.comparing(Person::getSalary)).map(Person::getName)
                .collect(Collectors.toList());
        System.out.println("按工资升序排序:" + newList1);

        // 按工资倒序排序(.reversed()) 并获取员工姓名生成一个新的流
        List<String> newList2 = personList.stream().sorted(Comparator.comparing(Person::getSalary).reversed())
                .map(Person::getName).collect(Collectors.toList());
        System.out.println("按工资降序排序:" + newList2);

        // 先按工资再按年龄升序排序 获取员工姓名生成一个新的流
        List<String> newList3 = personList.stream()
                .sorted(Comparator.comparing(Person::getSalary).thenComparing(Person::getAge)).map(Person::getName)
                .collect(Collectors.toList());
        System.out.println("先按工资再按年龄升序排序:" + newList3);

        // 先按工资再按年龄自定义排序(降序) 多条件操作
        List<String> newList4 = personList.stream().sorted((p1, p2) -> {
            if (p1.getSalary() == p2.getSalary()) {
                return p2.getAge() - p1.getAge();
            } else {
                return p2.getSalary() - p1.getSalary();
            }
        }).map(Person::getName).collect(Collectors.toList());

        System.out.println("先按工资再按年龄自定义降序排序:" + newList4);
    }

}

现的。

终止操作

收集(collect)将流中的中间(计算)结果存储到集合中,方便后续进一步使用。为了方便对收集操作的理解,方便读者掌握收集操作,将收集分为普通收集和高级收集。

1、普通收集
(1)收集为List

默认返回的类型为ArrayList,可通过Collectors.toCollection(LinkedList::new)显示指明使用其它数据结构作为返回值容器。

List<String> collect = stream.collect(Collectors.toList());

由集合创建流的收集需注意:仅仅修改流字段中的内容,没有返回新类型,如下操作直接修改原始集合,无需处理返回值。

// 直接修改原始集合
 List<String> collect = employeeList.stream().distinct().filter((e) -> e.getWage() > 30000).map((e -> e.getUsername())).collect(Collectors.toList());
        System.out.println("小于30000工资的员工有:"+collect.toString());

打印结果:

List<Double> collect1 = employeeList.stream().map((e) -> e.getWage()).collect(Collectors.toList());

(2)收集为Set
默认返回类型为HashSet,可通过Collectors.toCollection(TreeSet::new)显示指明使用其它数据结构作为返回值容器。

Set<String> collect = stream.collect(Collectors.toSet());

当前页面是本站的「Google AMP」版。查看和发表评论请点击:完整版 »