java_Stream流和Optional
这里写目录标题
- 1.Stream流
- 入门案例:
- 创建流
- 中间操作
- 终结操作
- forEach
- count
- max&min
- collect
- 查找与匹配
- anyMatch
- allMatch
- noneMatch
- findAny
- findFirst
- reduce归并
- 注意事项
- 2.Optional
- 使用
- 创建
- 安全消费值
- 获取值
- 安全获取值
- 过滤
- 判断
- 数据转换
1.Stream流
Java8的Stream使用的是函数式编程模式,如同它的名字一样,它可以被用来对集合或数组进行链状流式的操作。可以更方便的让我们对集合或数组操作。
入门案例:
public class StreamDemo {public static void main(String[] args) {// System.out.println(getAuthors());List<Author> authors = getAuthors();authors.stream().distinct().filter(author -> author.getAge()<18).forEach(author -> System.out.println(author.getName())); //必须要有终结操作}
idea 对debug对stream流的直观体现:
创建流
单列集合: 集合对象.stream()
数组:Arrays.stream(数组)
或者使用Stream.of(数组)
来创建
双列集合:转换成单列集合后再创建
Map<String,Integer> map = new HashMap<>();map.put("蜡笔小新",19);map.put("黑子",17);map.put("日向翔阳",16);Stream<Map.Entry<String, Integer>> stream = map.entrySet().stream();
中间操作
filter 流中的元素进行条件过滤
map 可以把对流中的元素进行计算或转换。
这个Map是映射的意思,映射成其他的元素
public void t1(){getAuthors().stream().map(new Function<Author, String>() {@Overridepublic String apply(Author author) {return author.getName();}}).forEach(name-> System.out.println(name));
}
public void t1(){getAuthors().stream().map(new Function<Author, Author>() {@Overridepublic Author apply(Author author) {author.setAge(author.getAge()+10);return author;}}).forEach(author-> System.out.println(author.getAge()));
}
- distinct 可以去除流中的重复元素。
distinct方法是依赖Object的equals方法来判断是否是相同对象的。所以需要注意重写equals方法
sorted 可以对流中的元素进行排序。
对象需要实现comparable接口 或者 传一个Comparator的匿名内部类
//author对象实现了omparable接口
@Overridepublic int compareTo(Author o) {//返回负整数、零或正整数,因为此对象小于、等于或大于指定对象return o.getAge()-this.getAge();}
public void t2(){getAuthors().stream().sorted().forEach(author -> System.out.println(author.getName()+author.getAge()));
}@Testpublic void t2(){getAuthors().stream().sorted((o1, o2) -> o1.getAge()-o2.getAge()) //o1 应该是当前项目.forEach(author -> System.out.println(author.getName()+author.getAge()));}
- limit
可以设置流的最大长度,超出的部分将被抛弃。 limit 获取前N个元素
public void t3(){getAuthors().stream()//年龄最小的前2个.sorted((o1, o2) -> o1.getAge() - o2.getAge()).limit(2).forEach(author -> System.out.println(author.getName()+author.getAge()));
}
- skip 跳过流中的前n个元素,返回剩下的元素
@Test
public void t4(){getAuthors().stream()//跳过前两个.skip(2).forEach(author -> System.out.println(author.getName()+author.getAge()));
}
flatMap
map只能把一个对象转换成另一个对象来作为流中的元素。而flatMap可以把一个对象转换成多个对象作为流中的元素。
public void t5(){getAuthors().stream().flatMap(new Function<Author, Stream<?>>() {@Overridepublic Stream<?> apply(Author author) {return author.getBooks().stream();}}).forEach(book -> System.out.println(book)); }public void t5(){getAuthors().stream().flatMap(author -> author.getBooks().stream()).forEach(book -> System.out.println(book));}
终结操作
forEach
对流中的元素进行遍历操作,我们通过传入的参数去指定对遍历到的元素进行什么具体操作。
count
可以用来获取当前流中元素的个数。
@Test
public void t7(){List<Author> authors = getAuthors();long count = authors.stream().distinct().count();System.out.println(count);
}
max&min
可以用来或者流中的最值。
public void t7(){// 分别获取这些作家的所出书籍的最高分和最低分并打印。List<Author> authors = getAuthors();Optional<Integer> max = authors.stream().flatMap(author -> author.getBooks().stream()).map(book -> book.getScore()).max((o1, o2) -> o1 - o2);Integer integer = max.get();System.out.println(integer);}
collect
把当前流转换成一个集合。
List<Author> authors = getAuthors();
List<String> list = authors.stream().map(author -> author.getName()).collect(Collectors.toList()); //使用 java.util.stream.Collectors; 这个工具类
System.out.println(list);
// set 一模一样
map 需要注意的是 key 数据一定不能重复(下面用了distinct 其实是对author对象euaqls 去重,也没实际是对name去重)
List<Author> authors = getAuthors();
Map<String, List<Book>> map = authors.stream().distinct().collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks()));System.out.println(map);
查找与匹配
anyMatch
可以用来判断是否有任意符合匹配条件的元素,结果为boolean类型。
allMatch
可以用来判断是否都符合匹配条件,结果为boolean类型。如果都符合结果为true,否则结果为false。
public void t10() {List<Author> authors = getAuthors();boolean b = authors.stream().anyMatch(author -> author.getAge() > 18);System.out.println(b);
}public void t10() {List<Author> authors = getAuthors();boolean b = authors.stream().allMatch(author -> author.getAge() > 18);System.out.println(b);}
noneMatch
可以判断流中的元素是否都不符合匹配条件。如果都不符合结果为true,否则结果为false
// 判断作家是否都没有超过100岁的。List<Author> authors = getAuthors();boolean b = authors.stream().noneMatch(author -> author.getAge() > 100);System.out.println(b); //true 就是都没有
findAny
获取流中的任意一个元素。该方法没有办法保证获取的一定是流中的第一个元素。
例子:
获取任意一个年龄大于18的作家,如果存在就输出他的名字
List<Author> authors = getAuthors();Optional<Author> optionalAuthor = authors.stream().filter(author -> author.getAge()>18).findAny();optionalAuthor.ifPresent(author -> System.out.println(author.getName()));
findFirst
获取流中的第一个元素。
例子:
获取一个年龄最小的作家,并输出他的姓名。
// 获取一个年龄最小的作家,并输出他的姓名。List<Author> authors = getAuthors();Optional<Author> first = authors.stream().sorted((o1, o2) -> o1.getAge() - o2.getAge()).findFirst();first.ifPresent(author -> System.out.println(author.getName()));
它俩区别的注意点~~
返回的元素是不确定的,对于同一个列表多次调用findAny()有可能会返回不同的值。使用findAny()是为了更高效的性能。如果是数据较少,串行地情况下,一般会返回第一个结果,如果是并行的情况,那就不能确保是第一个。
所以 你测试的时候可能发现 他俩结果一样 可能是因为数据量小
reduce归并
内部操作:
发现 返回的值 是和元素的类型一样的 所以一般先进行map操作 连起来叫 map-reduce操作
@Testpublic void t12() {// 年龄和 List<Author> authors = getAuthors();Integer sum = authors.stream().map(author -> author.getAge()).reduce(0, new BinaryOperator<Integer>() {@Overridepublic Integer apply(Integer re, Integer elem) {return re + elem;}});System.out.println(sum);}
min 和 max 操作其实就是reduce
使用reduce求所有作者中年龄的最大值
// 使用reduce求所有作者中年龄的最大值List<Author> authors = getAuthors();Integer max = authors.stream().map(author -> author.getAge()).reduce(Integer.MIN_VALUE, (result, element) -> result < element ? element : result);System.out.println(max);
使用reduce求所有作者中年龄的最小值
// 使用reduce求所有作者中年龄的最小值List<Author> authors = getAuthors();Integer min = authors.stream().map(author -> author.getAge()).reduce(Integer.MAX_VALUE, (result, element) -> result > element ? element : result);System.out.println(min);
注意事项
- 惰性求值(如果没有终结操作,没有中间操作是不会得到执行的)
- 流是一次性的(一旦一个流对象经过一个终结操作后。这个流就不能再被使用)
- 不会影响原数据(我们在流中可以多数据做很多处理。但是正常情况下是不会影响原来集合中的元素的。这往往也是我们期望的)
特殊:影响原数据
List<Author> authors = getAuthors();
authors.stream().forEach(author -> System.out.println("原数据"+author.getAge()));authors.stream().map(new Function<Author, Author>() {@Overridepublic Author apply(Author author) {author.setAge(author.getAge() + 10);return author;}}).forEach(author -> System.out.println(author.getAge()));authors.stream().forEach(author -> System.out.println("原数据"+author.getAge()));
//原数据都改变了
原数据33
原数据15
原数据14
原数据14
43
25
24
24
原数据43
原数据25
原数据24
原数据24Process finished with exit code 0
@Testpublic void t13() {List<Author> authors = getAuthors();authors.stream().forEach(author -> System.out.println("原数据"+author.getAge()));authors.stream().map( author -> author.getAge()+10).forEach(age -> System.out.println(age));authors.stream().forEach(author -> System.out.println("原数据"+author.getAge()));}
原数据33
原数据15
原数据14
原数据14
43
25
24
24
原数据33
原数据15
原数据14
原数据14Process finished with exit code 0
也就是不会影响集合内元素项的类型、个数、顺序。但由于值传递,可能改变元素项的属性
2.Optional
在JDK8中引入了Optional,养成使用Optional的习惯后你可以写出更优雅的代码来避免空指针异常。(比如mapper 查某个数据)
在实际开发中我们的数据很多是从数据库获取的。Mybatis从3.5版本可以也已经支持Optional了。我们可以直接把dao方法的返回值类型定义成Optional类型,MyBastis会自己把数据封装成Optional对象返回。封装的过程也不需要我们自己操作。
并且在很多函数式编程相关的API中也都用到了Optional。
使用
创建
Optional就好像是包装类,可以把我们的具体数据封装Optional对象内部。然后我们去使用Optional中封装好的方法操作封装进去的数据就可以非常优雅的避免空指针异常。
@Testpublic void t1() {Optional<Author> authorOptional = getAuthorOptional();authorOptional.ifPresent(author -> System.out.println(author)); //如果不是null (ifPresent)才去消费}private Optional<Author> getAuthorOptional() {Author author = new Author(3L, "易", 14, "是这个世界在限制他的思维", null);return Optional.ofNullable(author);//ofNullable创建}
- 不经常用的两个创建方法:
如果你确定一个对象不是空的则可以使用Optional的静态方法of来把数据封装成Optional对象。
Author author = new Author();Optional<Author> authorOptional = Optional.of(author);
但是一定要注意,如果使用of的时候传入的参数必须不为null。(尝试下传入null会出现什么结果)
如果一个方法的返回值类型是Optional类型。而如果我们经判断发现某次计算得到的返回值为null,这个时候就需要把null封装成Optional对象返回。这时则可以使用Optional的静态方法empty来进行封装。
Optional.empty()
- 更多使用 更方便的应该是
ofNullable
安全消费值
我们获取到一个Optional对象后肯定需要对其中的数据进行使用。这时候我们可以使用其ifPresent方法对来消费其中的值。
这个方法会判断其内封装的数据是否为空,不为空时才会执行具体的消费代码。这样使用起来就更加安全了。
例如,以下写法就优雅的避免了空指针异常。
Optional<Author> authorOptional = Optional.ofNullable(getAuthor());authorOptional.ifPresent(author -> System.out.println(author.getName()));
获取值
如果我们想获取值自己进行处理可以使用get方法获取,但是不推荐。因为当Optional内部的数据为空的时候会出现异常。
@Test
public void t2() {Optional<Author> authorOptional = getAuthorOptional();Author author = authorOptional.get(); //如果下面 return Optional.ofNullable(null); 那么这一行会报错System.out.println(author);//Author(id=3, name=易, age=14, intro=是这个世界在限制他的思维, books=null)
}private Optional<Author> getAuthorOptional() {Author author = new Author(3L, "易", 14, "是这个世界在限制他的思维", null);return Optional.ofNullable(author);
}
安全获取值
如果我们期望安全的获取值。我们不推荐使用get方法,而是使用Optional提供的以下方法。
orElseGet
获取数据并且设置数据为空时的默认值。如果数据不为空就能获取到该数据。如果为空则根据你传入的参数来创建对象作为默认值返回。
public void t2() {Optional<Author> authorOptional = getAuthorOptional();Author author = authorOptional.orElseGet(() -> new Author());//否则获取System.out.println(author);//Author(id=null, name=null, age=null, intro=null, books=null)}private Optional<Author> getAuthorOptional() {Author author = new Author(3L, "易", 14, "是这个世界在限制他的思维", null);return Optional.ofNullable(null);}
orElseThrow
获取数据,如果数据不为空就能获取到该数据。如果为空则根据你传入的参数来创建异常抛出。
@Testpublic void t3() {Optional<Author> authorOptional = getAuthorOptional();Author author = null;try {author = authorOptional.orElseThrow(() -> new RuntimeException("数据为空"));} catch (Throwable e) {e.printStackTrace();}System.out.println(author);}private Optional<Author> getAuthorOptional() {Author author = new Author(3L, "易", 14, "是这个世界在限制他的思维", null);return Optional.ofNullable(null);}
过滤
我们可以使用filter方法对数据进行过滤。如果原本是有数据的,但是不符合判断,也会变成一个无数据的Optional对象。
Optional<Author> authorOptional = Optional.ofNullable(getAuthor());authorOptional.filter(author -> author.getAge()>100).ifPresent(author -> System.out.println(author.getName()));
判断
我们可以使用isPresent方法进行是否存在数据的判断。如果为空返回值为false,如果不为空,返回值为true。但是这种方式并不能体现Optional的好处,更推荐使用ifPresent方法。
Optional<Author> authorOptional = Optional.ofNullable(getAuthor());if (authorOptional.isPresent()) {System.out.println(authorOptional.get().getName());}
数据转换
Optional还提供了map可以让我们的对数据进行转换,并且转换得到的数据也还是被Optional包装好的,保证了我们的使用安全。
例如我们想获取作家的书籍集合。
public void t4() {Optional<Author> authorOptional = getAuthorOptional();Optional<List<Book>> books = authorOptional.map(author -> author.getBooks());books.ifPresent(books1 -> System.out.println(books1));//[Book(id=1, name=刀的两侧是光明与黑暗, category=哲学,爱情, score=88, intro=用一把刀划分了爱恨), Book(id=2, name=一个人不能死在同一把刀下, category=个人成长,爱情, score=99, intro=讲述如何从失败中明悟真理)]}private Optional<Author> getAuthorOptional() {Author author = new Author(3L, "易", 14, "是这个世界在限制他的思维", null);List<Book> books1 = new ArrayList<>();books1.add(new Book(1L, "刀的两侧是光明与黑暗", "哲学,爱情", 88, "用一把刀划分了爱恨"));books1.add(new Book(2L, "一个人不能死在同一把刀下", "个人成长,爱情", 99, "讲述如何从失败中明悟真理"));author.setBooks(books1);return Optional.ofNullable(author);}
java_Stream流和Optional相关推荐
- Stream流和Optional
Lambda表达式和函数式接口 https://blog.csdn.net/qq_45888932/article/details/122451124 目录 一.什么是Stream流 注意事项 二.快 ...
- Java8函数式编程(Lambda表达式,Stream流,Optional)
目录 一.函数式编程思想 二.lambda表达式 1.概念 2.Lambda表达式对接口的要求 编辑编辑编辑 3.Lambda表达式的语法 4.函数引用 4.1引用一个静态方法 4.2引用一个非 ...
- stream 上传插件 java_stream: 流式(包含断点续传)上传文件,包括前端和java后台...
#Stream 上传插件 Stream 是解决不同浏览器上传文件的插件,是Uploadify的Flash版和Html5版的结合! #Stream 简介 Stream 是根据某网的文件上传插件加工而来, ...
- stream distinct去重_再来看看Java的新特性——Stream流
半年前开始试着使用Java的新特性,给我印象最深的就是Stream流和Optional.其中Stream提高了看法效率,让代码看起来十分清爽. 为什么要使用流? 摘要中已经说明了,为了提高开发效率.流 ...
- Java8新特性学习_001_(Lambda表达式,函数式接口,方法引用,Stream类,Optional类)
目录 ■代码 ■代码运行结果 ■代码说明 ・44行:Stream的.foreach方法ー参数类型:函数式接口 ・82行:Interface中,default方法 ・92行 Stream的.max方 ...
- stream、lamda、optional
Lambda Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性. Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中). 可以理解lambda表达式为方 ...
- 京东云开发者|深入JDK中的Optional
概述:Optional最早是Google公司Guava中的概念,代表的是可选值.Optional类从Java8版本开始加入豪华套餐,主要为了解决程序中的NPE问题,从而使得更少的显式判空,防止代码污染 ...
- 可以通过parallel()把顺序流转换成并行流
先贴上几个案例,水平高超的同学可以挑战一下: 从员工集合中筛选出salary大于8000的员工,并放置到新的集合里. 统计员工的最高薪资.平均薪资.薪资之和. 将员工按薪资从高到低排序,同样薪资者年龄 ...
- stream流的使用说明书
1 stream的概念 Stream将要处理的元素集合看作一种流,在流的过程中,借助Stream API对流中的元素进行操作,比如:筛选.排序.聚合等. Stream可以由数组或集合创建,对流的操作分 ...
最新文章
- Python中os和shutil模块实用方法集锦
- android webview 填充,从Android使用WebView自动填充表格
- jquery.treeview.js树控件的应用
- 怎么用Android做登录界面,利用Android怎么制作一个APP登录界面
- python获取android手机信息
- java file类复制文件路径_java进阶(34)--File类、目录复制
- 返回指针_C语言面试中的问题指针和引用的使用场景?
- python数据科学入门_干货!小白入门Python数据科学全教程
- React 入门学习笔记2
- pytorch中的gather函数_Pytorch中Emdedding函数的解释及使用方法
- goldendb基于mysql_中兴通讯GoldenDB在中信银行信用卡核心应用实践
- 基于 Android NDK 的学习之旅-----Java 调用C(附源码)
- 【PL/SQL】用星号拼出金字塔
- stap监控cpu脚本小结
- c++类模板用法讲解
- Redhat Linux 5.3环境实施DB2 V9.7 HADR
- 多测师拱墅校区__肖sir__项目讲解(1)
- Vue3使用路由及配置vite.alias简化导入写法
- linuxprobe
- SpringBoot实现百度文库文档上传,通俗易懂适合萌新