java新特性stream与Optional

函数式接口

只有一个抽象方法接口我们称之为函数接口。
JDK的函数式接口都加上了@FunctionalInterface注解进行标识,但无论是否加上该注解只要接口只有一个抽象方法,都是函数式接口。

方法引用

基本格式

类名或对象名::方法名

类名::方法名

只有一行代码,并且这行代码是调用了第一个参数的成员方法,
并且我们要把要重写的抽象方法中剩余的参数按着顺序传入这个成员方法中。

在这里插入图片描述

对象名::方法名使用场景为

方法体中只有一行代码,并且这个代码是调用了某个对象的成员方法,并且我们要把抽象方法中
的所有参数都按照顺序传入到这个方法中。

使用场景

如果我们方法体中只有一个方法被调用的话(包括构造方法),我们可以使用方法引用,进一步简化代码。

 List<String> collect = authors.stream()
                .map(author -> author.getName())
                .collect(Collectors.toList());
        System.out.println(collect);

使用后

List<String> collect = authors.stream()
                .map(Author::getName)
                .collect(Collectors.toList());
        System.out.println(collect);

构造器引用

类型::new

方法体中只有一行代码,并且这行代码调用了某个类的构造方法。并且我们要把所要重写的参数都按着顺序传入到这个构造方法中。

stream

Java 8 是一个非常成功的版本,这个版本新增的Stream,配合同版本出现的 Lambda ,给我们操作集合(Collection)提供了极大的便利。
Stream将要处理的元素集合看作一种流,在流的过程中,借助Stream API对流中的元素进行操作,比如:筛选、排序、聚合等。

stream特性

stream不存储数据,而是按照特定的规则对数据进行计算,一般会输出结果。
stream不会改变数据源,通常情况下会产生一个新的集合或一个值。
stream具有延迟执行特性(惰性求值),只有调用终端操作时,中间操作才会执行。
stream是一次性的(一旦一个流对象经过一个终结操作后,这个流就不会被使用)

在这里插入图片描述
debug中可以看到流的执行过程。

常用操作

创建流

中间操作

每次返回一个新的流,可以有多个

终结操作

每个流只能进行一次终端操作,终端操作结束后流无法再次使用。终端操作会产生一个新的集合或值。

ctrl+alt+m可以自动封装为函数

创建流的方式

集合对象

集合对象.stream()

数组

Arrays.stream(数组)
 Integer arr[]={1,2,3,4,5};
        Stream<Integer> stream = Arrays.stream(arr);
        stream.distinct().forEach(integer -> System.out.println(integer));

双列集合

先转换为单列集合再创建
map.entrySet().stream();
 Map<String, Integer> map = new HashMap<>();
        map.put("蜡笔",11);
        map.put("蜡笔2",11);
        map.put("蜡笔3",11);

        Set<Map.Entry<String, Integer>> entries = map.entrySet();
        entries.stream().distinct().forEach(stringIntegerEntry -> System.out.println(stringIntegerEntry));

stream中的常用API中间操作

filter

筛选,是按照一定的规则校验流中的元素,将符合条件的元素提取到新的流中的操作。

map与flatMap

在这里插入图片描述
flatMap
接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
举例说明
比如一个作者类里有
在这里插入图片描述
然后需要输出所有作者的所有书籍。
在这里插入图片描述
传统需要双重for循环,
flatMap将作者流中的值转换为书籍流,然后将所有书籍流组合成一个大流。

authors.stream()
                .flatMap((Function<Author, Stream<Book>>) author -> author.getBooks().stream())
                .distinct()
                .forEach(book -> System.out.println(book.getName()));

获取所有分类

authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .flatMap(book -> Arrays.stream(book.getCategory().split(",")))
                .distinct()
                .forEach(s -> System.out.println(s));

先将作者流转换为书籍流,然后将书籍流转换为分类流,最后对分类流进行操作。

二者区别

可以看出flatmap和map的参数差别在于,
map传入一个传入实体返回实体,
flatMap是传入实体返回的却是Stream流,
那既然是流,那么最好返回值本身是一个Stream,或者能被转换成Stream的对象!
flatmap的作用 —— 把嵌套集合,按照子集合的形式,
统一放入到新的一个集合中去,这就叫结果展平

例如,一个年级的学生,按照班级为单位,如今年段长想统计该年段所有的学生信息,一个flatmap就能轻松搞定,无需再for循环取遍历获取了~

distinct

可以去除流中的重复元素,底层依赖的是Object的equals方法来判断是否是相同对象。所以需要重写equals方法。

在这里插入图片描述

sorted

sorted,实现排序,中间操作。

如果调用空参的

实体类需要实现Comparable接口
在这里插入图片描述
重写方法,实现排序
在这里插入图片描述
调用有参的
需要重写里面的方法
在这里插入图片描述

limit

可以设置流的最大长度,超出的部分将被抛弃
例如:打印年龄最大的两个作者的姓名。

authors.stream()
                .distinct()
                .sorted()
                .limit(2)
                .forEach(author -> System.out.println(author.getName()));

skip

跳过流中的前n个元素了,返回剩下的元素

authors.stream()
                .sorted()
                .skip(1)
                .forEach(author -> System.out.println(author.getName()));

stream中常用API终结操作

forEach

对流中的元素进行遍历操作,我们通过传入参数去指定对遍历的元素进行什么具体操作。

count

可以获取流中元素的个数

  //打印这些作家的所出书籍的数目,去重
        long count = authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .count();
        System.out.println(count);

max与min

可以用来获取流中的最值

//获取作品中的最高分和最低分
        Optional<Integer> max = authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .map(book -> book.getScore())
                .max((o1, o2) -> o1 - o2);
        System.out.println(max.get());

collect

把当前流转换为一个集合

例.获取一个存放所有作者名字的List集合

List<String> collect = authors.stream()
                .map(author -> author.getName())
                .collect(Collectors.toList());
        System.out.println(collect);

例.获取一个所有书名的set集合

Set<Book> collect1 = authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .collect(Collectors.toSet());
        System.out.println(collect1);

例.获取一个map集合,map的key为作者名,value为List

Map<String, List<Book>> collect2 = authors.stream().distinct()
                .collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks()));
        System.out.println(collect2);

anyMatch

只要有一个满足条件,就返回true

allMatch

如果都符合,结果为true

boolean b = authors.stream()
                .allMatch(author -> author.getAge() > 18);
        System.out.println(b);

noneMatch

可以判断流中元素是否都不符合匹配条件,如果都不符合结果为true

findAny

获取流中的任意一个,该方法没有办法保证获取的一定是流中的第一个元素。

findFirst

获取流中的第一个元素

reduce

归并
对流中的数据按照你制定的计算方法计算出一个结果
reduce的作用就是把stream()中的元素组合起来,我们可以传入一个初始值,他会按着我们的计算方式依次拿流中的元素和初始化值进行计算,计算结果在和后面的元素计算。

//求所有作者的年龄之和
        Integer reduce = authors.stream()
                .map(author -> author.getAge())
                .reduce(0, (integer, integer2) -> integer + integer2);
        System.out.println(reduce);
  //求所有作者中,年龄最小的值
        Integer reduce1 = authors.stream()
                .map(author -> author.getAge())
                .reduce(Integer.MAX_VALUE, (integer, integer2) -> integer > integer2 ? integer2 : integer);
        System.out.println(reduce1);

stream基本数据类型优化

减少自动装箱拆箱工作
第一个map是转换为integer类型,第二个map会进行装箱与拆箱工作后才能运算,故可以优化此操作。
在这里插入图片描述

在这里插入图片描述

并行流

在这里插入图片描述

parallel可以把串行流改成并行流
peek是一个调试函数

在这里插入图片描述

Integer arr[]={1,2,3,4,5,6,7,8,9,0,11};

        Stream<Integer> stream1 = Arrays.stream(arr);
        Integer reduce = stream1.parallel()
                .peek(integer -> System.out.println(Thread.currentThread().getName() + integer))
                .reduce(0, (integer, integer2) -> integer + integer2);
        System.out.println(reduce);

Optional

到目前为止,臭名昭著的空指针异常是导致Java应用程序失败的最常见原因。以前,为了解决空指针异常,Google公司著名的Guava项目引入了Optional类,Guava通过使用检查空值的方式来防止代码污染,它鼓励程序员写更干净的代码。受到Google Guava的启发,Optional类已经成为Java 8类库的一部分。
出现空指针异常的情况,比如mybaits在查询数据库时,如果查询的数据为null,则就会出现空指针异常。
使用optional可以优雅的避免空指针异常,optional就好像是包装类,可以把我们具体的数据封装到Optional对象内部。然后我们调用封装好的方法操作封装进去的数据就可以了。

使用

创建optional对象

我们一般使用optional的静态方法ofNullable来把数据封装成一个Optional对象,无论传入的参数是否为null都不会出现问题。

1.使用ofNullable()

Optional<List<Author>> authors1 = Optional.ofNullable(authors);
        authors1.ifPresent(authors2 -> System.out.println(authors2));

of与ofNullable区别
of在使用时,要确保封装的对象不为空。
ofNullable则是两种情况都可以

安全消费值

我们获取到一个Optimal对象后肯定需要对其中的数据进行使用,这时候我们可以使用其中的ifpresent方法来消费其中的值。
这个方法会判断其内封装的数据是否为空,不为空时,才会执行具体的消费代码。下述代码就优雅的避免了空指针问题。

Optional<List<Author>> authors1 = Optional.ofNullable(authors);
        authors1.ifPresent(authors2 -> System.out.println(authors2));

获取值

如果我们想要获取值自己处理可以使用get方法获取,不推荐,因为为空时会有异常。

安全获取值

orElseGet
获取数据并设置数据为空时的默认值。如果数据不为空就能够获取到该数据。
如果为空,就根据传入的参数来创建对象作为默认值返回。

下述情况就是如果为空,则返回一个空的list集合。

List<Author> authors2 = authors1.orElseGet(() -> new ArrayList<>());
        System.out.println(authors2);
orElseThrow
如果数据为空,则根据传入的参数来创建异常抛出。使用spring时较好。
try {
            List<Author> authors3 = authors1.orElseThrow((Supplier<Throwable>) () -> new RuntimeException("数据为空"));
            System.out.println(authors3);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }

过滤

我们使用**filter**方法可以对数据进行过滤,如果原本是有数据的,但是不符合条件,也会变成一个无数据的Optional对象。

 Optional<List<Author>> authors1 = Optional.ofNullable(authors);
authors1.filter(authors3 -> authors3.get(1).getAge()>10)
                .ifPresent(authors32 -> System.out.println(authors32));

判断

我们使用isPresent方法来判断是否存在数据的判断。如果为空,返回值为flase,如果不为空,返回值为true。但这中方式不能体现Options的好处。更推荐使用ifPresent。

数据转换

Optional还提供了map可以让我们对数据进行转换,并且可以转换得到的数据还是被Optional包装好的,并且保证了我们使用的安全。
例如我们想要获取作家的书籍集合。

 Optional<List<Book>> books = authors1.map(authors2 -> authors2.get(1).getBooks());
        System.out.println(books);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
StreamOptionalJava 8中增的两个特性,它们都可以用于简化代码和提高代码的可读性。 Stream流简介: StreamJava 8中增的一种数据处理方式,它可以用于对集合、数组等数据进行批量操作。Stream提供了很多方法来进行数据处理,例如filter()、map()、reduce()等。Stream的使用可以大大简化代码,提高代码的可读性。 Stream的使用步骤: 1. 创建Stream对象:可以通过集合、数组等方式创建Stream对象。 2. 对Stream进行中间操作:可以使用filter()、map()、reduce()等方法对Stream进行中间操作。 3. 对Stream进行终止操作:可以使用count()、collect()等方法对Stream进行终止操作,获取最终结果。 Optional简介: OptionalJava 8中增的一种特殊类型,它可以用于解决代码中的null值问题。Optional对象可以包含一个非null的值,也可以为空。使用Optional可以避免代码中出现空指针异常,提高代码的健壮性和可读性。 Optional的使用步骤: 1. 创建Optional对象:可以通过of()、ofNullable()等方法创建Optional对象。 2. 对Optional进行操作:可以使用isPresent()、orElse()等方法对Optional进行操作,获取Optional对象中的值。 3. 对Optional进行转换:可以使用map()、flatMap()等方法将Optional中的值进行转换。 Stream流和Optional的关系: StreamOptional都是Java 8中增的特性,它们的使用可以大大简化代码,提高代码的可读性。StreamOptional常常一起使用,例如对集合中的数据进行处理时,使用Stream来处理数据,使用Optional来处理空值问题。 例如,以下代码使用StreamOptional来获取一个集合中的第一个元素: ``` List<String> list = Arrays.asList("apple", "banana", "cherry"); Optional<String> first = list.stream().findFirst(); if (first.isPresent()) { System.out.println(first.get()); } else { System.out.println("List is empty"); } ``` 在以上示例中,我们使用了Stream来处理集合中的数据,使用Optional来处理空值问题。通过调用stream()方法将集合转换为Stream对象,然后使用findFirst()方法获取第一个元素。使用isPresent()方法判断Optional对象是否为空,如果不为空,则使用get()方法获取Optional对象中的值。 总结: StreamOptional都是Java 8中增的特性,它们的使用可以大大简化代码,提高代码的可读性。Stream可以用于对集合、数组等数据进行批量操作,而Optional可以用于解决代码中的null值问题。StreamOptional常常一起使用,例如对集合中的数据进行处理时,使用Stream来处理数据,使用Optional来处理空值问题。在使用StreamOptional时,需要注意使用恰当的操作方法,以提高代码的效率和可读性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值