首页 / JAVA / Java 8 Stream特性
Java 8 Stream特性
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了Java 8 Stream特性,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含14656字,纯文字阅读大概需要21分钟。
内容图文
Java 8 新特性 java 8 Stream
一、Stream (流)到底是什么呢?
答: 是数据渠道,将数据源(集合,数组等)中的元素操作之后拍成新的序列
由定义可知,我们很轻松的就可以画个图
一、获得流
@Test public void getStream() { // 1.通过Collection获得提供的stream,parallelStream获得流 List<String> stringList = new ArrayList<>(); stringList.add("abc"); stringList.add("bac"); stringList.add("cab"); Stream<String> stream = stringList.stream(); //Stream<String> stringStream = stringList.parallelStream(); //2.通过Arrays的静态方法 Arrays.stream 获得流 Stream<String> stream1 = Arrays.stream(new String[]{"a", "b"}); //3.通过Stream的静态方法of获得流 Stream<String> stringStream = Stream.of(new String[]{"a", "b"}); Stream<String> a = Stream.of("a", "b"); //4.生成無限流 Stream<Integer> iterate = Stream.iterate(1, (x) -> x * 2); Stream<Double> generate = Stream.generate(() -> Math.random()); }
二、中间操作
2.1 筛选与切片
Emploee Dto
import java.util.Objects; public class Employee implements Comparable<Employee> { private String name; private Integer age; private Status status; private Double salary; public String getName() { return name; } publicvoid setName(String name) { this.name = name; } public Integer getAge() { return age; } publicvoid setAge(Integer age) { this.age = age; } public Status getStatus() { return status; } publicvoid setStatus(Status status) { this.status = status; } public Double getSalary() { return salary; } publicvoid setSalary(Double salary) { this.salary = salary; } public Employee(String name, Integer age, Status status, Double salary) { this.name = name; this.age = age; this.status = status; this.salary = salary; } public Employee() { } @Override public String toString() { return "Employee{" + "name=‘" + name + ‘\‘‘ + ", age=" + age + ", status=" + status + ", salary=" + salary + ‘}‘; } @Override publicboolean equals(Object o) { if (this == o) returntrue; if (o == null || getClass() != o.getClass()) returnfalse; Employee employee = (Employee) o; return Objects.equals(name, employee.name) && Objects.equals(age, employee.age) && status == employee.status && Objects.equals(salary, employee.salary); } @Override publicint hashCode() { return Objects.hash(name, age, status, salary); } @Override publicint compareTo(Employee o) { if (this.getAge() > o.getAge()) { return 1; } return -1; } publicenum Status { FREE, BUSY, VACATION; } }
执行结果这里就不一一展示了
/** * 筛选 */ @Test public void test1() { // 1.生成流 Stream<Employee> employeeStream = Stream.of(new Employee("张三", 17, Employee.Status.FREE, 999.99), new Employee("李四", 20, Employee.Status.BUSY, 9999.99), new Employee("王五", 23, Employee.Status.BUSY, 7777.00), new Employee("赵六", 25, Employee.Status.VACATION, 6666.66), new Employee("田七", 29, Employee.Status.FREE, 997.99), new Employee("李青", 37, Employee.Status.VACATION, 100000.99) ); //操作流(这里为了方便就进行了终止操作,方便查看) //2 筛选出年龄大于20的员工信息 employeeStream. filter(e -> e.getAge() > 20).//Predicate<? super T> predicate 方法中需要一个断言型接口 forEach(x -> System.out.println(x));//Consumer<? super T> action } /** * 切片 */ @Test publicvoid test2() { //1.生成流 Stream<Employee> employeeStream = Stream.of(new Employee("张三", 17, Employee.Status.FREE, 999.99), new Employee("李四", 20, Employee.Status.BUSY, 9999.99), new Employee("王五", 23, Employee.Status.BUSY, 7777.00), new Employee("赵六", 25, Employee.Status.VACATION, 6666.66), new Employee("田七", 29, Employee.Status.FREE, 997.99), new Employee("李青", 37, Employee.Status.VACATION, 100000.99), new Employee("李青", 37, Employee.Status.VACATION, 100000.99), new Employee("李青", 37, Employee.Status.VACATION, 100000.99) ); //操作流(这里为了方便就进行了终止操作,方便查看) //2.1 筛选出年龄大于20的前2个员工信息/*employeeStream. filter(e -> e.getAge() > 20). limit(2).//Predicate<? super T> predicate 方法中需要一个断言型接口 forEach(x -> System.out.println(x));//Consumer<? super T> action*///2.2 筛选出年龄大于20的员工信息(排除前两个)/* employeeStream. filter(e->e.getAge()>20). skip(2). forEach(x -> System.out.println(x));*///2.3 对流进行去重(对象的重复是根据hashCode和equals方法来判断的,所有需要重写这两个方法) employeeStream. distinct(). forEach(x -> System.out.println(x)); }
2.2映射
映射主要有2个函数map和flatMap 主要用来提取对象中的属性
map(Function<? super T, ? extends R> mapper)
/** * 映射 */ @Test public void test3() { // 1.生成流 Stream<Employee> employeeStream = Stream.of(new Employee("张三", 17, Employee.Status.FREE, 999.99), new Employee("李四", 20, Employee.Status.BUSY, 9999.99), new Employee("王五", 23, Employee.Status.BUSY, 7777.00), new Employee("赵六", 25, Employee.Status.VACATION, 6666.66), new Employee("田七", 29, Employee.Status.FREE, 997.99), new Employee("李青", 37, Employee.Status.VACATION, 100000.99) ); //操作流(这里为了方便就进行了终止操作,方便查看) //2 取出所有员工的姓名 employeeStream. map(e -> e.getName()). forEach(System.out::println); }
flatMap (Function<? super T, ? extends R> mapper) 平铺映射
为什么已经有一个映射方法,还需要一个flatMap呢?话不多说,上代码
/** * 普通映射 */ @Test public void test4() { // 1.生成流 Stream<String> abdas = Stream.of("abdas", "das", "das"); //操作流(这里为了方便就进行了终止操作,方便查看) Stream<Stream<String>> streamStream = abdas.map(e -> transfer(e));//流中嵌流,数据很不直观 streamStream.forEach(e -> e.forEach(System.out::println));//虽然还是可以拿到所有字符的集合,但是如果是对象呢? } private Stream<String> transfer(String s) { List<String> list = new ArrayList<>(); char[] chars = s.toCharArray(); for (int i = 0; i < chars.length; i++) { String s1 = chars[i] + ""; list.add(s1); } return list.stream(); }
平铺映射
/** * 平铺映射 */ @Test public void test5() { // 1.生成流 Stream<String> abdas = Stream.of("abdas", "das", "das"); //操作流(这里为了方便就进行了终止操作,方便查看) Stream<String> stringStream = abdas.flatMap(e -> transfer(e)); stringStream.forEach(System.out::println); }
2者效果一样
2.3排序
sort
/** * 排序 */ @Test public void test6() { // 1.生成流 Stream<Employee> employeeStream = Stream.of(new Employee("张三", 16, Employee.Status.FREE, 999.99), new Employee("李四", 16, Employee.Status.BUSY, 9999.99), new Employee("王五", 23, Employee.Status.BUSY, 7777.00), new Employee("赵六", 37, Employee.Status.VACATION, 6666.66), new Employee("田七", 29, Employee.Status.FREE, 997.99), new Employee("李青", 25, Employee.Status.VACATION, 100000.99) ); //操作流(这里为了方便就进行了终止操作,方便查看) //2.1 自然排序 此处必须要实现接口Comparable
// employeeStream.sorted().forEach(System.out::println);
//2.2 自定义排序
employeeStream.sorted((e1, e2) -> {
if (e1.getAge() == e1.getAge()) {
return e1.getName().compareTo(e2.getName());
} else {
return Integer.compare(e1.getAge(), e2.getAge());
}
}).forEach(System.out::println);
三、终止操作
3.1 查找与匹配
Match
/** * Match */ @Test public void test7() { // 1.生成流 Stream<String> stringStream = Stream.of("abdas", "das", "das"); //操作流(这里为了方便就进行了终止操作,方便查看) //2.1 集合中所有元素是不是都满足条件 //boolean allMatch = stringStream.allMatch(e -> e.startsWith("d"));//Predicate<? super T> predicate //System.out.println(allMatch); //false //2.2 集合中元素只要有一个满足条件则返回true,否则返回false //boolean anyMatch = stringStream.anyMatch(e -> e.startsWith("d")); //System.out.println(anyMatch);//true //2.3 集合中所有元素不满足条件则返回true,否则返回falseboolean noneMatch = stringStream.noneMatch(e -> e.startsWith("c")); System.out.println(noneMatch); }
Find and Statistics
/** * Find * statistics */ @Test public void test8() { // 1.生成流 Stream<String> stringStream = Stream.of("abc", "defg", "hijqn"); List<String> stringList = new ArrayList<>(); stringList.add("abc"); stringList.add("defg"); stringList.add("hijqn"); stringList.add("784"); stringList.add("852"); stringList.add("943"); stringList.add("120"); stringList.add("120"); List<Long> longList = new ArrayList<>(); longList.add(784l); longList.add(852l); longList.add(943l); longList.add(120l); longList.add(120l); //操作流(这里为了方便就进行了终止操作,方便查看) //2.1 findFirst 查找集合中第一个元素 Optional 是java8的一个容器类,能很好的避免空指针异常/*Optional<String> streamFirst = stringStream.findFirst(); Optional<String> listFirst = stringList.parallelStream().findFirst(); System.out.println("streamFirst:" + streamFirst.get()); System.out.println("listFirst:" + listFirst.get());*///2.2 findAny/*Optional<String> streamFirst = stringStream.findAny(); Optional<String> listFirst = stringList.parallelStream().findAny(); System.out.println("streamFirst:" + streamFirst.get());//第一个元素 System.out.println("listFirst:" + listFirst.get());//随机一个元素*///count 统计流中有多少个元素/*long count = stringStream.count(); System.out.println(count);*///max(Comparator<? super T> comparator) Optional<Long> max = longList.stream().max(Long::compareTo); System.out.println(max.orElse(99999999l)); //min(Comparator<? super T> comparator) Optional<String> min = stringList.stream().min(String::compareTo); System.out.println(min.orElse("0")); }
3.2 规约 reduce
/** * reduce */ @Test public void test9() { // 1.生成流 Stream<Employee> employeeStream = Stream.of(new Employee("张三", 16, Employee.Status.FREE, 999.99), new Employee("李四", 16, Employee.Status.BUSY, 9999.99), new Employee("王五", 23, Employee.Status.BUSY, 7777.00), new Employee("赵六", 37, Employee.Status.VACATION, 6666.66), new Employee("田七", 29, Employee.Status.FREE, 997.99), new Employee("李青", 25, Employee.Status.VACATION, 100000.99), new Employee("李青", 26, Employee.Status.VACATION, 100000.99), new Employee("李青", 35, Employee.Status.VACATION, 100000.99) ); //操作流(这里为了方便就进行了终止操作,方便查看) Optional<Double> reduce = employeeStream. filter((s) -> s.getName().equals("李青")). map(e -> e.getSalary()). reduce(Double::sum); System.out.println(reduce.orElse(0.00)); }
3.2 收集collect
/** * collect */ @Test public void test10() { // 1.生成流 Stream<Employee> employeeStream = Stream.of(new Employee("张三", 16, Employee.Status.FREE, 999.99), new Employee("李四", 16, Employee.Status.BUSY, 9999.99), new Employee("王五", 23, Employee.Status.BUSY, 7777.00), new Employee("赵六", 37, Employee.Status.VACATION, 6666.66), new Employee("田七", 29, Employee.Status.FREE, 997.99), new Employee("李青", 25, Employee.Status.VACATION, 100000.99), new Employee("李青", 26, Employee.Status.VACATION, 100000.99), new Employee("李青", 35, Employee.Status.VACATION, 100000.99) ); //年龄小于25岁的员工信息/*List<Employee> employeeList = employeeStream. filter(e -> e.getAge() <= 25). collect(Collectors.toList()); employeeList.forEach(System.out::println);*///所有员工姓名/*Set<String> set = employeeStream. map(Employee::getName). collect(Collectors.toSet()); set.forEach(System.out::println);*///所有员工信息(去重)/*HashSet<Employee> collect = employeeStream. collect(Collectors.toCollection(HashSet::new)); System.out.println(collect);*///员工个数/*Long collect = employeeStream.collect(Collectors.counting()); System.out.println(collect);*///平均工资/*Double avg = employeeStream.collect(Collectors.averagingDouble(Employee::getSalary)); System.out.println(avg);*///工资最高的员工信息/*Optional<Employee> optionalEmployee = employeeStream.collect(Collectors.maxBy((e1, e2) -> e1.getSalary().compareTo(e2.getSalary()))); System.out.println(optionalEmployee.orElse(null));*///工资最低的员工信息/*Optional<Employee> optionalEmployee = employeeStream.collect(Collectors.minBy((e1, e2) -> e1.getSalary().compareTo(e2.getSalary()))); System.out.println(optionalEmployee.orElse(null));*///工资总和/* Double allCounts = employeeStream.collect(Collectors.summingDouble(Employee::getSalary)); System.out.println("工资总和" + allCounts);*///工资信息摘要 DoubleSummaryStatistics dss = employeeStream.collect(Collectors.summarizingDouble(Employee::getSalary)); double avg = dss.getAverage(); double sum = dss.getSum(); long count = dss.getCount(); double max = dss.getMax(); double min = dss.getMin(); System.out.println(avg); System.out.println(sum); System.out.println(count); System.out.println(max); System.out.println(min); }
3.3 分区,分组,连接字符串
@Test public void test11() { Stream<Employee> employeeStream = Stream.of(new Employee("张三", 16, Employee.Status.FREE, 999.99), new Employee("李四", 16, Employee.Status.BUSY, 9999.99), new Employee("王五", 23, Employee.Status.BUSY, 7777.00), new Employee("赵六", 37, Employee.Status.VACATION, 6666.66), new Employee("田七", 29, Employee.Status.FREE, 997.99), new Employee("李青", 25, Employee.Status.VACATION, 100000.99), new Employee("李青", 26, Employee.Status.VACATION, 100000.99), new Employee("李青", 35, Employee.Status.VACATION, 100000.99) ); //按照工资是否大于9000来分区 [true:{.....} false:{......}]/*Map<Boolean, List<Employee>> booleanListMap = employeeStream.collect(Collectors.partitioningBy(e -> e.getSalary() > 9000.0)); System.out.println(booleanListMap);*///按照状态分组/*Map<Employee.Status, List<Employee>> statusListMap = employeeStream.collect(Collectors.groupingBy(Employee::getStatus));*///多级分组/*Map<Employee.Status, Map<String, Map<String, List<Employee>>>> map = employeeStream.collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy(e -> { if (e.getAge() <= 25) { return "青年"; } else { return "中年"; } }, Collectors.groupingBy(e -> { if (e.getSalary() > 9000) { return "高于平均工资"; } else { return "低于平均工资"; } }) ))); System.out.println(map);*///拼接名称/*String str = employeeStream.map(Employee::getName).collect(Collectors.joining()); System.out.println(str);*///拼接名称,带前缀和间隔 String joinStr = employeeStream.map(Employee::getName).collect(Collectors.joining(",", " start ", " end ")); System.out.println(joinStr); }
四、注意事项
1.Stream不会出仓元素
2.Stream不会改变数据源中的数据
3.Stream是惰性执行的
写两段代码证明Stream是惰性执行的。
I.
@Test public void test() { List<String> stringList = new ArrayList<>(); stringList.add("abc"); stringList.add("bac"); stringList.add("cab"); Stream<String> stringStream = stringList.stream().peek(System.out::println); System.out.println("执行完成"); }
结果:字符串并没有被打印出来
D:\java\jdk\bin\java.exe
执行完成 Process finished with exit code 0
II.
public class TestStream { @Test public void test() { List<String> stringList = new ArrayList<>(); stringList.add("abc"); stringList.add("bac"); stringList.add("cab"); Stream<String> stringStream = stringList.stream().peek(System.out::println); stringStream.collect(Collectors.toList());//使用流 System.out.println("执行完成"); } }
结果:字符串正常输出
D:\java\jdk\bin\java.exe
abc
bac
cab
执行完成
Process finished with exit code 0
4.流不能被重复使用
III
@Test public void test() { List<String> stringList = new ArrayList<>(); stringList.add("abc"); stringList.add("bac"); stringList.add("cab"); Stream<String> stringStream = stringList.stream().peek(System.out::println); stringStream.collect(Collectors.toList()); stringStream.collect(Collectors.toList()); System.out.println("执行完成"); }
java.lang.IllegalStateException: stream has already been operated upon or closed
原文:https://www.cnblogs.com/wblogw/p/12283387.html
内容总结
以上是互联网集市为您收集整理的Java 8 Stream特性全部内容,希望文章能够帮你解决Java 8 Stream特性所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。