Java 8 Stream 闪亮登场!
Java技术栈
www.javastack.cn
关注阅读更多优质文章
作者:funnyZpC
出处:cnblogs.com/funnyzpc/p/10382053.html
一. Stream(流)是什么,干什么
Stream是一类用于替代对集合操作的工具类+Lambda式编程,他可以替代现有的遍历、过滤、求和、求最值、排序、转换等
二. Stream操作方式
并行方式parallelStream
顺序方式Stream
三. Stream优势
Lambda 可有效减少冗余代码,减少开发工作量
内置对集合List、Map的多种操作方式,含基本数据类型处理
并行Stream有效率优势(内置多线程)
四. Stream(流)的基本使用
遍历forEach
@Test
public void stream() {
//操作List
List
过滤filter
List mapList = new ArrayList() {
{
add(1);
add(10);
add(12);
add(33);
add(99);
}
};
//mapList.stream().forEach(item-> System.out.println(item));
mapList = mapList.stream().filter(item->{
return item>30;
}).collect(Collectors.toList());
System.out.println(mapList);
转换map和极值
@Test
public void trans(){
List ps = new ArrayList(){
{
Person p1 = new Person();
p1.setAge(11);
p1.setName("张强");
Person p2 = new Person();
p2.setAge(17);
p2.setName("李思");
Person p3 = new Person();
p3.setAge(20);
p3.setName("John");
add(p1);
add(p2);
add(p3);
}
};
//取出所有age字段为一个List
List sumAge = ps.stream().map(Person::getAge).collect(Collectors.toList());
System.out.println(sumAge);
//取出age最大的那
Integer maxAge =sumAge.stream().max(Integer::compare).get();
System.out.println(maxAge);
}
class Person{
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
五. Stream(流)的效率+ 模拟非耗时简单业务逻辑
class Person{
private String name;
private int age;
private Date joinDate;
private String label;
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 Date getJoinDate() {
return joinDate;
}
public void setJoinDate(Date joinDate) {
this.joinDate = joinDate;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
}
public class DataLoopTest {
private static final Logger LOG= LoggerFactory.getLogger(DataLoopTest.class);
private static final List persons = new ArrayList<>();
static {
for(int i=0;i<=1000000;i++){
Person p = new Person();
p.setAge(i);
p.setName("zhangSan");
p.setJoinDate(new Date());
persons.add(p);
}
}
/**
* for 循环耗时 ===> 1.988
* for 循环耗时 ===> 2.198
* for 循环耗时 ===> 1.978
*
*/
@Test
public void forTest(){
Instant date_start = Instant.now();
int personSize = persons.size();
for(int i=0;i persons.get(i).setLabel(persons.get(i).getName().concat("-"+persons.get(i).getAge()).concat("-"+persons.get(i).getJoinDate().getTime()));
}
Instant date_end = Instant.now();
LOG.info("for 循环耗时 ===> {}", Duration.between(date_start,date_end).toMillis()/1000.0);
}
/**
* forEach 循环耗时 ===> 1.607
* forEach 循环耗时 ===> 2.242
* forEach 循环耗时 ===> 1.875
*/
@Test
public void forEach(){
Instant date_start = Instant.now();
for(Person p:persons){
p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime()));
}
Instant date_end = Instant.now();
LOG.info("forEach 循环耗时 ===> {}", Duration.between(date_start,date_end).toMillis()/1000.0);
}
/**
* streamForeach 循环耗时 ===> 1.972
* streamForeach 循环耗时 ===> 1.969
* streamForeach 循环耗时 ===> 2.125
*/
@Test
public void streamForeach(){
Instant date_start = Instant.now();
persons.stream().forEach(p->p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime())));
Instant date_end = Instant.now();
LOG.info("streamForeach 循环耗时 ===> {}", Duration.between(date_start,date_end).toMillis()/1000.0);
}
/**
* parallelStreamForeach 循环耗时 ===> 1.897
* parallelStreamForeach 循环耗时 ===> 1.942
* parallelStreamForeach 循环耗时 ===> 1.642
*/
@Test
public void parallelStreamForeach(){
Instant date_start = Instant.now();
persons.parallelStream().forEach(p->p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime())));
Instant date_end = Instant.now();
LOG.info("parallelStreamForeach 循环耗时 ===> {}", Duration.between(date_start,date_end).toMillis()/1000.0);
}
}
模拟耗时简单业务逻辑
public class DataLoopBlockTest {
private static final Logger LOG= LoggerFactory.getLogger(DataLoopTest.class);
private static final List persons = new ArrayList<>();
static {
for(int i=0;i<=100000;i++){
Person p = new Person();
p.setAge(i);
p.setName("zhangSan");
p.setJoinDate(new Date());
persons.add(p);
}
}
/**
* for 循环耗时 ===> 101.385
* for 循环耗时 ===> 102.161
* for 循环耗时 ===> 101.472
*
*/
@Test
public void forTest(){
Instant date_start = Instant.now();
int personSize = persons.size();
for(int i=0;i try {
Thread.sleep(1);
persons.get(i).setLabel(persons.get(i).getName().concat("-"+persons.get(i).getAge()).concat("-"+persons.get(i).getJoinDate().getTime()));
}catch (Exception e){
e.printStackTrace();
}
}
Instant date_end = Instant.now();
LOG.info("for 循环耗时 ===> {}", Duration.between(date_start,date_end).toMillis()/1000.0);
}
/**
* forEach 循环耗时 ===> 101.027
* forEach 循环耗时 ===> 102.488
* forEach 循环耗时 ===> 101.608
*/
@Test
public void forEach(){
Instant date_start = Instant.now();
for(Person p:persons){
try {
Thread.sleep(1);
p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime()));
}catch (Exception e){
e.printStackTrace();
}
}
Instant date_end = Instant.now();
LOG.info("forEach 循环耗时 ===> {}", Duration.between(date_start,date_end).toMillis()/1000.0);
}
/**
* streamForeach 循环耗时 ===> 103.246
* streamForeach 循环耗时 ===> 101.128
* streamForeach 循环耗时 ===> 102.615
*/
@Test
public void streamForeach(){
Instant date_start = Instant.now();
//persons.stream().forEach(p->p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime())));
persons.stream().forEach(p->{
try {
Thread.sleep(1);
p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime()));
}catch (Exception e){
e.printStackTrace();
}
});
Instant date_end = Instant.now();
LOG.info("streamForeach 循环耗时 ===> {}", Duration.between(date_start,date_end).toMillis()/1000.0);
}
/**
* parallelStreamForeach 循环耗时 ===> 51.391
* parallelStreamForeach 循环耗时 ===> 53.509
* parallelStreamForeach 循环耗时 ===> 50.831
*/
@Test
public void parallelStreamForeach(){
Instant date_start = Instant.now();
//persons.parallelStream().forEach(p->p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime())));
persons.parallelStream().forEach(p->{
try {
Thread.sleep(1);
p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime()));
}catch (Exception e){
e.printStackTrace();
}
});
Instant date_end = Instant.now();
LOG.info("parallelStreamForeach 循环耗时 ===> {}", Duration.between(date_start,date_end).toMillis()/1000.0);
//LOG.info("\r\n===> {}",JSON.toJSONString(persons.get(10000)));
}
}
可以看到在百万数据下做简单数据循环处理,对于普通for(for\foreach)循环或Stream(并行、非并行)下,几者的效率差异并不明显。
注意: 在百万数据下,普通for、foreach循环处理可能比Stream的方式快许多,对于这点效率的损耗,其实lambda表达式对代码的简化更大!
另外,在并行流的循环下速度提升了一倍之多,当单个循环耗时较多时,会拉大与前几者的循环效率 (以上测试仅对于循环而言,其他类型业务处理,比如排序、求和、最大值等未做测试,个人猜测与以上测试结果相似)
六. Stream(流)注意项
并行Stream不是线程安全的,当对循坏外部统一对象进行读写时候会造成意想不到的错误,这需要留意 因Stream总是惰性的,原对象是不可以被修改的,在集合处理完成后需要将处理结果放入一个新的集合容器内 普通循环与Stream(非并行)循环,在处理处理数据量比较大的时候效率是一致的,推荐使用Stream的形式 对于List删除操作,目前只提供了removeIf方法来实现,并不能使用并行方式 对于lambda表达式的写法
当表达式内只有一个返回boolean类型的语句时候语句是可以简写的,例如:
persons.parallelStream().forEach(p->p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime())));
当表达式内会有一些复杂处理逻辑时需要加上大括号,这与初始化List参数方式大致一致
try {
Thread.sleep(1);
p.setLabel(p.getName().concat("-"+p.getAge()).concat("-"+p.getJoinDate().getTime()));
}catch (Exception e){
e.printStackTrace();
}
});
七. stream&Lambda表达式常用api方法
filter(过滤) map(映射转换) mapTo[Int|Long|Double] (到基本类型流的转换) flatMap(流展开合并) flatMapTo[Int|Long|Double] sorted(排序) distinct(不重复值) peek(执行某种操作,流不变,可用于调试) limit(限制到指定元素数量) skip(跳过若干元素) toArray(转为数组) reduce(推导结果) collect(聚合结果) min(最小值) max(最大值) count (元素个数) anyMatch (任一匹配) allMatch(所有都匹配) noneMatch(一个都不匹配) findFirst(选择首元素) findAny(任选一元素)
好了,本篇到这里了,如果你想阅读更多 Java 8 + 系列教程,可以关注公众号Java技术栈回复 java 获取,我都写了一大堆了。
关注Java技术栈看更多干货
评论