解决什么问题

  • 集合计算不足
  • 解决重复代码

背后思想

  • 管道
  • 封装
  • 数据处理

内容说明

是什么

  • 计算担当。集合用于数据存储,流用于数据计算,不会修改原始数据
  • 内置循环。高级迭代器,内置循环和计算
  • 单向。数据只能遍历一次,遍历过一次后即用尽了,像水流过,不可往复

生命周期

Stream像操作SQL一样处理数据,所以很概念非常相近,可以对比着理解 。

创建

分为静态创建和实例创建,不同的方法适用于不同场景。目的都是为了转成流

    /**
* 初始
* <p>
* 适用于数组和简单的数据转为stream
* </p>
*/
@Test
public void test_static_of() {
Stream.of(Person.builder().name("name").age(1)); /**
* 打印的是list的元素
*/
Stream.of(newArray()).forEach(System.out::println);
/**
* 打印的是list的toString,所以集合不使用该方法
*/
Stream.of(newList()).forEach(System.out::println);
} /**
* 范围
* <p>
* 适用于整数迭代
* </p>
*/
@Test
public void test_static_range(){
/**
* 不包含10
*/
IntStream.range(1,10).forEach(System.out::println);
/**
* 包含10
*/
IntStream.rangeClosed(1,10).forEach(System.out::println);
} /**
* 生成
* <p>
* 适用于批量生成并且赋值
* 比如生成id或者uuid
* </p>
*/
@Test
public void test_static_generate() {
Stream.generate(UUID::randomUUID)
.limit(10)
.forEach(System.out::println); Stream.generate(()->Math.random()*1000)
.limit(10)
.forEach(System.out::println); } @Test
public void test_static_iterate() {
Stream.iterate(10, index -> {
Person.builder().name("name").age(index);
return --index;
}).limit(10).forEach(System.out::println);
} /**
* 集合
*/
@Test
public void test_instance_collection() {
/**
* 打印的是list的元素
*/
newList().stream().forEach(System.out::println);
} /**
* 正则
*/
@Test
public void test_regex() {
String sentence = "Program creek is a Java site.";
Pattern.compile("\\W").splitAsStream(sentence).forEach(System.out::println);
} /**
* 文件
* @throws IOException
*/
@Test
public void test_file() throws IOException {
String fileName = "c://lines.txt";
Files.lines(Paths.get(fileName)).forEach(System.out::println);
} private List<String> newList() {
List<String> list = new ArrayList<>();
list.add("lisi");
return list;
} private String[] newArray() {
return new String[]{"sili", "wangwu"};
}

转换

把一个流转为另一个流,可以不断的转换。包括:过滤,转换,限制,排序,去重。通过不断的转换最终获取目标数据

    private Stream<Person> newStream(){
List<Person> list = new ArrayList<>();
list.add(Person.builder().name("zhangsan").age(12).build());
list.add(Person.builder().name("zhangsan").age(12).build());
list.add(Person.builder().name("lisi").age(18).build());
list.add(Person.builder().name("wangwu").age(25).build());
return list.stream();
} /**
* 过滤
* <p>
* 过滤不符合条件的数据。
* 比如说:
* <ul>
* <li>结合数据库查询,在java里过滤数据</li>
* <li>过滤掉npe</li>
* <li>过滤不符合业务数据</li>
* </ul>
* </p>
*/
@Test
public void test_filter(){
newStream()
.filter(person->person.getAge()>=18)
.forEach(System.out::println); } /**
* 类型转换
* <p>
* 用于快速转换数据类型
* 比如说:
* <ul>
* <li>根据实例快速转出id集合</li>
* </ul>
* </p>
*/
@Test
public void test_mapper(){
newStream()
.map(Person::getId)
.forEach(System.out::println);
} /**
* 限制
* <p>
* 取前几个
* </p>
*/
@Test
public void test_limit(){
newStream()
.limit(2)
.forEach(System.out::println);
} /**
* 排序
*/
@Test
public void test_sorted(){
newStream()
.sorted((p1,p2)->{
if(p1.getAge()>p2.getAge()){
return 1;
}else if (p1.getAge()<p2.getAge()){
return -1;
}else{
return 0;
}
})
.forEach(System.out::println);
}
/**
* 排序
*/
@Test
public void test_sorted_comparator() {
newStream()
.sorted(Comparator
//排序
.comparing(Person::getAge)
//倒序
.reversed()
.thenComparing(Person::getName)
)
.forEach(System.out::println);
} /**
* 去重
*/
@Test
public void test_distinct(){
newStream()
.distinct()
.forEach(System.out::println);
} /**
* 综合使用
* <p>
* 通过这些计算可以快速找出期待的数据,而且还不需要不断的添加遍历和破坏代码可读性
* </p>
*/
@Test
public void test_combine(){
newStream()
.filter(person->null==person)
.distinct()
.filter(person -> person.getAge()>=18)
.map(Person::getAge)
.sorted((age1,age2)->{
if(age1>age2){
return 1;
}else if (age1<age2){
return -1;
}else{
return 0;
}
})
.limit(1)
.forEach(System.out::println);
}
  • 无须重复循环
  • 添加需求时,无须破坏式的修改内容

聚合

一个流只能有一个中止动作。中止后流就不能使用。包括:查找,匹配,循环,统计,类型转换,分组。

    private Stream<Person> newStream() {
List<Person> list = new ArrayList<>();
list.add(Person.builder().name("zhangsan").age(12).build());
list.add(Person.builder().name("zhangsan").age(12).build());
list.add(Person.builder().name("lisi").age(18).build());
list.add(Person.builder().name("wangwu").age(25).build());
return list.stream();
} /**
* 查找
*
*/
@Test
public void test_find() {
/**
* 返回第一个值
*/
Optional<Person> first = newStream().findFirst();
Assert.assertEquals(first.get(),newStream().collect(toList()).get(0));
/**
* 返回随机值
*/
Optional<Person> any = newStream().findAny();
System.out.println(any.get());
} /**
* 匹配
*/
@Test
public void test_match() {
Assert.assertTrue(newStream().anyMatch(person -> person.getAge() == 18));
Assert.assertFalse(newStream().allMatch(person -> person.getAge() == 18));
Assert.assertFalse(newStream().noneMatch(person -> person.getAge() == 18));
} /**
* 统计
*
*/
@Test
public void test_stat_max() {
Optional<Person> maxAge = newStream().max((p1, p2) -> {
if (p1.getAge() > p2.getAge()) {
return 1;
} else if (p1.getAge() < p2.getAge()) {
return -1;
} else {
return 0;
}
});
System.out.println(maxAge);
} /**
* 个数
*/
@Test
public void test_stat_count() {
long count = newStream().count();
System.out.println(count);
} /**
* 循环
*/
@Test
public void test_forEach() {
newStream().forEach(System.out::println);
} /**
* 归并
*/
@Test
public void test_reduce() {
/**
* 第一个参数是上次结果
* 第二个参数是元素
*/
Optional<Integer> totalAge = newStream()
.map(Person::getAge)
.reduce((result, age) -> result + age);
System.out.println(totalAge.get()); /**
* 第一个参数是初始值
* 第二个参数是上次结果
* 第三个参数是元素
*/
Integer totalAgeWithInit = newStream()
.map(Person::getAge)
.reduce(10, (result, age) -> result + age);
System.out.println(totalAgeWithInit);
} /**
* 转为数组
*
*/
@Test
public void test_toArray(){
newStream().toArray();
} /**
* 转为collection
*/
@Test
public void test_toCollection(){
newStream().collect(toList());
newStream().collect(toSet());
}
/**
* 转为map
*/
@Test
public void test_toMap(){
/**
* 第一个参数是key
* 第二个参数是value
*
* <p>
* 如果有重复主键时会报错。
* 如果Key为null会报错
* </p>
*/
//newStream().collect(toMap(Person::getId,person->person));
/**
* 第三个参数是如果key重复的时候取哪个值
*/
newStream().collect(toMap(Person::getId,person->person,(oldValue,newValue)->oldValue));
newStream().collect(toMap(Person::getId,person->person,(oldValue,newValue)->newValue));
/**
* 返回具体的map实例类型
*/
newStream().collect(toMap(Person::getId,person->person,(oldValue,newValue)->oldValue,HashMap::new));
newStream().collect(toMap(Person::getId,person->person,(oldValue,newValue)->oldValue,LinkedHashMap::new));
} /**
* 通过分组转为Map
*
* <p>
* 分组完,一般会对元素进行聚合
* </p>
*/
@Test
public void test_toMap_group(){
/**
* 不存在重复key报错的问题
*/
Map<Long, List<Person>> listMap = newStream().collect(groupingBy(Person::getId));
/**
* 但是返回值是double
*/
Map<Long, Double> averageAgeMap = newStream().collect(
groupingBy(Person::getId,
averagingLong(Person::getAge))
);
/**
* 找出最大年龄对应的Map
*/
Map<String, Optional<Person>> maxAgeMap = newStream().collect(
groupingBy(Person::getName,
maxBy(Comparator.comparing(Person::getAge)))
);
}

实践

可维护性

  • 点号换行,提升可阅读性
  • 不要超过3行
  • 职责单一
    @Test
public void test_format() {
newStream()
.filter(person -> null == person)
.distinct()
.filter(person -> person.getAge() >= 18)
.map(Person::getAge)
.sorted((age1, age2) -> {
if (age1 > age2) {
return 1;
} else if (age1 < age2) {
return -1;
} else {
return 0;
}
})
.limit(1)
.forEach(System.out::println); newStream()
.filter(person -> null == person)
.distinct()
.filter(person -> person.getAge() >= 18)
.map(Person::getAge)
//上面排序超过三行,不容易阅读
.sorted(Comparator.comparing(Long::valueOf))
.limit(1)
.forEach(System.out::println);
} @Test
public void test_single() {
newStream()
.filter(person -> {
if(null != person){
return true;
}
if(person.getAge() > 18){
return true;
}
if(person.getName().startsWith("hello")){
return true;
}
return false;
})
; newStream()
.filter(person -> null != person)
.filter(person -> person.getAge() > 18)
.filter(person -> person.getName().startsWith("hello"))
;
}
  • 语义更明确,不需要面向每一个过程。
  • 代码更简洁,修改更方便。
    @Test
public void test_forEach() {
List<Person> persons = new ArrayList<>();
List<Person> adultPersons = new ArrayList<>();
for (Person person : persons) {
if (person.getAge() > 18) {
adultPersons.add(person);
}
} List<Person> adultPersons2 = persons.stream()
.filter(person -> person.getAge() > 18)
.collect(Collectors.toList());
}

陷阱

    @Test
public void test_forEach(){
newStream().forEach(person -> {
// 不要在forEach里做过滤的行为
if(person.getAge()>18){
/**
* 这里的return就相当于for里的continue,后面的例子还是会继续的。
* 无法实现break的效果,一定会把所有元素走完
*/
return ;
}
System.out.println(person);
}); newStream()
.filter(person -> person.getAge()>18)
.forEach(System.out::println);
}
  • 如果有中止的需求,不要使用
  • 只做动作,不要做过滤
  • 不能用于需要索引的情景
  • 不能用于变更集合的情景
  • 使用时需要注意NPE

思考

  • 类型转换比较冗长,是否通过工具类封装或者通过重写这些子类来并且通过默认方法来进一步内置行为
  • stream和interate的区别
  • stream并发的使用

加入我们

诚邀,有梦想有激情有实力的小伙伴一起加入我们,改变世界。下面是JD的详情信息

阿里-菜鸟国际-出口大团队招新啦

JDK8漫谈——集合更强大的更多相关文章

  1. JDK8漫谈——代码更优雅

    简介 lambda表达式,又称闭包(Closure)或称匿名方法(anonymous method).将Lambda表达式引入JAVA中的动机源于一个叫"行为参数"的模式.这种模式 ...

  2. Python的regex模块——更强大的正则表达式引擎

    Python自带了正则表达式引擎(内置的re模块),但是不支持一些高级特性,比如下面这几个: 固化分组    Atomic grouping 占有优先量词    Possessive quantifi ...

  3. summerDao-比mybatis更强大无需映射配置的dao工具

    summerDao是summer框架中的一个数据库操作工具,项目地址:http://git.oschina.net/xiwa/summer. 怎么比mybatis更强大,怎么比beetlsql更简单, ...

  4. 思维导图软件TheBrain 8全新发布 提供更强大的信息管理

    TheBrain思维导图软件是全球唯一一款动态的网状结构的思维导图软件,广泛用于学习.演讲.项目管理.会议.需求调研与分析等.其独特的信息组织方式使得用户可以创建并连接到数以万计的数字想法,为此在全球 ...

  5. cVim—Chrome上更强大的vim插件

    cVim——Chrome上更强大的vim插件 介绍 也许很多人在chrome上都用过类似Vimium, ViChrome的插件,这些插件的目的都差不多,就是在浏览器中提供一些类似vim的操作来提高效率 ...

  6. 功能更强大的格式化工具类 FormatUtils.java

    package com.util; import java.text.DecimalFormat; import java.text.ParseException; import java.text. ...

  7. 10个工具让你的 shell 脚本更强大

    10个工具让你的 shell 脚本更强大 很多人误以为shell脚本只能在命令行下使用.其实shell也可以调用一些GUI组件,例如菜单,警告框,进度条等等.你可以控制最终的输出,光标位 置还有各种输 ...

  8. powerMock比easyMock和Mockito更强大(转)

    powerMock是基于easyMock或Mockito扩展出来的增强版本,所以powerMock分两种类型,如果你习惯于使用easyMock的,那你就下载基于easyMock的powerMock,反 ...

  9. 让Docker功能更强大的10个开源工具

    让Docker功能更强大的10个开源工具 更好的管理.Web前端程序.更深入地了解容器应用程序,Docker生态系统正在迅速发展,这还得归功于其充满活力的开源社区. 软件项目的成功常常根据其催生的生态 ...

随机推荐

  1. ocLazyLoad按顺序加载

    $ocLazyLoad.load({ serie:true, files: [oneFile,twoFile] }) 使用serie:true 这是 传送门

  2. Django之form总结

    复习Django项目结构: 主要的文件:manage.py,url.py,views.py,settings.py,models.py manage.py:项目管理文件,一般不做修改. url.py: ...

  3. 盐城 - 开设IT公司的好地方

    盐城:位于江苏省北部,这一好像只能算三线的城市,不久前当选为“国家中心城市”.在全国仅有的50城市中名列34.它可成为发展IT产业的好地方. (1)人才济济.从这里走出去的高级人才数不胜数,留在这里的 ...

  4. Pycharm2017常用快捷键

    Pycharm 的快捷键可以在[文件]-[设置]中自定义(见上图). 下方是根据网上资料整理的官方默认快捷键设置. 常用快捷键 Ctrl + / 行注释/取消行注释 Tab / Shift + Tab ...

  5. Django2.0.1开发框架搭建

    1.使用vs2017创建空白django项目 2.右键python环境的env---安装python包  升级django到2.0.1和setuptools到38.4.0版本,具体环境如下: 3.配置 ...

  6. SQL易错总结1

    SQL易错总结1 进阶 select语句.select * 查询所有不规范,写出要查的属性.distinct慎用,性能消耗很大 like 模糊查询 ,空值判断是 is null 单行函数:lower( ...

  7. gcc库链接

    转载于https://blog.csdn.net/zhangdaisylove/article/details/45721667 1.库的分类 库有静态库和动态库,linux下静态库为.a,动态库为. ...

  8. Sql Server 只有MDF文件恢复数据库的方法以及2008清除日志文件

    首先建立同名的空数据库,然后停止数据库服务运行,将MDF文件覆盖后启动服务,并修改和执行下面的语句. alter database JinMa_NYGL set EMERGENCY alter dat ...

  9. The resource configuration is not modifiable in this context.

    项目中使用了Jersey RESTful 框架, 更新代码后服务能正常起来, 在页面登录时验证码不显示 后台报错 java.lang.IllegalStateException: The resour ...

  10. 【微信JSSDK】PHP版微信录音文件下载

    微信的录音文件上传到微信服务器上,只能保存三天. 因此需要做一个转存到自己服务器,或者七牛云的操作. 转存到自己服务器 调用微信JSSDK API 录音, 录音结束,上传到微信服务器,获取录音文件的 ...