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 值作为参考进行排序 |
| map() | 这个方法比较特殊,后面用到会详细说明 |
使用流式编程需要了解他的特点:
- 我们通过流式编程操作集合是不会影响集合本身
- 流式编程的代码都是延迟执行的,只有在获取结果的时候才会执行
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方法操作的实体类必须复写equals和hashCode方法
// 去重操作,可以看到两个老八只剩下一个
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);
}
}
map:生成新的数据
map同之前那几个稍微有些区别,类似filter或者sorted方法都是对集合进行编辑,而map可以将集合改变为一组新的数据:
// 通过map返回每个用户的姓名,将用户集合改变成了用户姓名集合
public class ApplicationMain {
public static void main(String[] args) {
UserService userService = new UserService();
List<UserEntity> list = userService.selectList();
list.stream()
.map(UserEntity::getName)
.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<String> result = list.stream()
// 找到所有男性员工
.filter(item->item.getGender()=='男')
// 去除重复数据
.distinct()
// 按照年龄进行排序
.sorted(Comparator.comparingInt(UserEntity::getAge))
// 获取他们所有人的名字
.map(UserEntity::getName)
// 最后转换为List集合
.collect(Collectors.toList());
// 打印查看效果
System.out.println(result);
}
}
JDK8新特性(二) 流式编程Stream的更多相关文章
- 深入理解java虚拟机---jdk8新特性(二)
1.jdk8新特性 1.新特性 2.lambda函数表达式的作用 A: 替换内部类 B:对集合的操作并行化
- 010-jdk1.8版本新特性二-Optional类,Stream流
1.5.Optional类 1.定义 Optional 类是一个可以为null的容器对象.如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象. Optional 是个 ...
- Java8 新特性之流式数据处理
一. 流式处理简介 在我接触到java8流式处理的时候,我的第一感觉是流式处理让集合操作变得简洁了许多,通常我们需要多行代码才能完成的操作,借助于流式处理可以在一行中实现.比如我们希望对一个包含整数的 ...
- Java8 新特性之流式数据处理(转)
转自:https://www.cnblogs.com/shenlanzhizun/p/6027042.html 一. 流式处理简介 在我接触到java8流式处理的时候,我的第一感觉是流式处理让集合操作 ...
- 类的加载、时机、反射、模板设计、jdk7/jdk8新特性(二十六)
1.类的加载概述和加载时机 * A:类的加载概述 * 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化. * 加载 * 就是指将class文 ...
- Stream流式编程
Stream流式编程 Stream流 说到Stream便容易想到I/O Stream,而实际上,谁规定“流”就一定是“IO流”呢?在Java 8中,得益于Lambda所带来的函数式编程,引入了一个 ...
- JDK8新特性关于Stream流
在Java1.8之前还没有stream流式算法的时候,我们要是在一个放有多个User对象的list集合中,将每个User对象的主键ID取出,组合成一个新的集合,首先想到的肯定是遍历,如下: 1 2 3 ...
- JDK8新特性:使用stream、Comparator和Method Reference实现集合的优雅排序
大家对java接口Comparator和Comparable都不陌生,JDK8里面Comparable还和以前一样,没有什么改动:但是Comparator在之前基础上增加了很多static和defau ...
- JDK8新特性一览
转载自:http://blog.csdn.net/qiubabin/article/details/70256683 官方新特性说明地址 Jdk8新特性.png 下面对几个常用的特性做下重点说明. 一 ...
随机推荐
- SpringBoot2.x整合JavaMail以qq邮箱发送邮件
本文参考spring官网email接口文档所写. spring-email官方网址:https://docs.spring.io/spring/docs/5.1.8.RELEASE/spring-fr ...
- centos7 SNMP错误记录
如果本地测试ok,远程测试出现如下报错: No Such Object available on this agent at this OID或No more variables left in th ...
- CSS元素层级的概念及性质
元素的层级的介绍 什么是元素的层级 通过z-index可以改变开启定位元素的层级 父元素的层级再高也不会遮盖住子元素 元素的层级的介绍 什么是元素的层级 当元素开启定位后就会是元素提升一个层级,网页是 ...
- 440. 字典序的第K小数字 + 字典树 + 前缀 + 字典序
440. 字典序的第K小数字 LeetCode_440 题目描述 方法一:暴力法(必超时) package com.walegarrett.interview; /** * @Author WaleG ...
- 剑指 Offer 42. 连续子数组的最大和 + 动态规划
剑指 Offer 42. 连续子数组的最大和 题目链接 状态定义: 设动态规划列表 \(dp\) ,\(dp[i]\) 代表以元素 \(4nums[i]\) 为结尾的连续子数组最大和. 为何定义最大和 ...
- 漏洞复现-CVE-2016-4977-Spring远程代码执行
0x00 实验环境 攻击机:Win 10 靶机也可作为攻击机:Ubuntu18 (docker搭建的vulhub靶场)(兼顾反弹shell的攻击机) 0x01 影响版本 Spring Secu ...
- beego 框架用的页面样式模板
https://themequarry.com/category/free 页面样式
- IntelliJ IDEA报错总结
不能运行java程序 可能是没有选择运行环境点击 edit Configurations在Use classpath of module 中选择本项目的运行环境 Run报错: Error:java: ...
- Django1和2的区别
一.路由的区别 1.Django1中的url from django.conf.urls import url # 使用url关键字 urlpatterns = [ url('article-(\d+ ...
- MVC中"删除"按钮无法实现
出现原因:MVC视图中定义了空的模板页 解决办法:删除模板页 或 改成定义页面标题都可以