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());