文章目录

  • 5,Optional
    • 5.1,概述
    • 5.2,使用
      • 5.2.1,创建对象
      • 5.2.2,安全消费值
      • 5.2.3,获取值
      • 5.2.4,安全获取值
      • 5.2.5,过滤
      • 5.2.6,判断
      • 5.2.7,数据转换
  • 6,方法引用
    • 6.1 推荐用法
    • 6.2 基本格式
    • 6.3 语法详解(了解)
      • 6.3.1 引用类的静态方法
      • 6.3.2 引用对象的实例方法
      • 6.3.3 引用类的实例方法
      • 6.3.4 构造器引用
  • 7,高级用法
    • 7.1,基本数据类型优化
    • 7.2,并行流

5,Optional

5.1,概述

​ 我们在编写代码的时候出现最多的就是空指针异常。所以在很多情况下我们需要做各种非空的判断。

​ 例如:

        Author author = getAuthor();if(author!=null){System.out.println(author.getName());}

​ 尤其是对象中的属性还是一个对象的情况下。这种判断会更多。

​ 而过多的判断语句会让我们的代码显得臃肿不堪。

​ 所以在JDK8中引入了Optional,养成使用Optional的习惯后你可以写出更优雅的代码来避免空指针异常。

​ 并且在很多函数式编程相关的API中也都用到了Optional,如果不会使用Optional也会对函数式编程的学习造成影响。

5.2,使用

5.2.1,创建对象

​ Optional就好像是包装类,可以把我们的具体数据封装Optional对象内部。然后我们去使用Optional中封装好的方法操作封装进去的数据就可以非常优雅的避免空指针异常。

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

Author author = getAuthor();
Optional<Author> authorOptional = Optional.ofNullable(author);

​ 你可能会觉得还要加一行代码来封装数据比较麻烦。但是如果改造下getAuthor方法,让其的返回值就是封装好的Optional的话,我们在使用时就会方便很多。

​ 而且在实际开发中我们的数据很多是从数据库获取的。Mybatis从3.5版本可以也已经支持Optional了。我们可以直接把dao方法的返回值类型定义成Optional类型,MyBastis会自己把数据封装成Optional对象返回。封装的过程也不需要我们自己操作。

​ 如果你确定一个对象不是空的则可以使用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

5.2.2,安全消费值

​ 我们获取到一个Optional对象后肯定需要对其中的数据进行使用。这时候我们可以使用其ifPresent方法对来消费其中的值。

​ 这个方法会判断其内封装的数据是否为空,不为空时才会执行具体的消费代码。这样使用起来就更加安全了。

​ 例如,以下写法就优雅的避免了空指针异常。

Optional<Author> authorOptional = Optional.ofNullable(getAuthor());authorOptional.ifPresent(author -> System.out.println(author.getName()));

5.2.3,获取值

​ 如果我们想获取值自己进行处理可以使用get()方法获取,但是不推荐。因为当Optional内部的数据为空的时候会出现异常。

5.2.4,安全获取值

​ 如果我们期望安全的获取值。我们不推荐使用get方法,而是使用Optional提供的以下方法。

  • orElseGet

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

    Optional<Author> authorOptional = Optional.ofNullable(getAuthor());
    Author author1 = authorOptional.orElseGet(() -> new Author());
    
  • orElseThrow

    获取数据,如果数据不为空就能获取到该数据。如果为空则根据你传入的参数来创建异常抛出。

    Optional<Author> authorOptional = Optional.ofNullable(getAuthor());
    try {Author author = authorOptional.orElseThrow((Supplier<Throwable>) () -> new RuntimeException("author为空"));System.out.println(author.getName());
    } catch (Throwable throwable) {throwable.printStackTrace();
    }
    

5.2.5,过滤

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

        Optional<Author> authorOptional = Optional.ofNullable(getAuthor());authorOptional.filter(author -> author.getAge()>100).ifPresent(author -> System.out.println(author.getName()));

5.2.6,判断

​ 我们可以使用isPresent方法进行是否存在数据的判断。如果为空返回值为false,如果不为空,返回值为true。但是这种方式并不能体现Optional的好处,更推荐使用ifPresent方法

Optional<Author> authorOptional = Optional.ofNullable(getAuthor());if (authorOptional.isPresent()) {System.out.println(authorOptional.get().getName());
}

5.2.7,数据转换

​ Optional还提供了map可以让我们的对数据进行转换,并且转换得到的数据也还是被Optional包装好的,保证了我们的使用安全。

例如我们想获取作家的书籍集合。

    private static void testMap() {Optional<Author> authorOptional = getAuthorOptional();Optional<List<Book>> optionalBooks = authorOptional.map(author -> author.getBooks());optionalBooks.ifPresent(books -> System.out.println(books));}

6,方法引用

6.1 推荐用法

​ 我们在使用lambda时不需要考虑什么时候用方法引用,用哪种方法引用,方法引用的格式是什么。我们只需要在写完lambda方法发现方法体只有一行代码,并且是方法的调用时使用快捷键尝试是否能够转换成方法引用即可。

6.2 基本格式

类名或者对象名::方法名

6.3 语法详解(了解)

6.3.1 引用类的静态方法

其实就是引用类的静态方法

格式

类名::方法名

使用前提

​ 如果我们在重写方法的时候,方法体中只有一行代码,并且这行代码是调用了某个类的静态方法,并且我们把要重写的抽象方法中所有的参数都按照顺序传入了这个静态方法中,这个时候我们就可以引用类的静态方法。

例如:

如下代码就可以用方法引用进行简化

List<Author> authors = getAuthors();Stream<Author> authorStream = authors.stream();authorStream.map(author -> author.getAge()).map(age->String.valueOf(age));

注意,如果我们所重写的方法是没有参数的,调用的方法也是没有参数的也相当于符合以上规则。

优化后如下:

List<Author> authors = getAuthors();Stream<Author> authorStream = authors.stream();authorStream.map(author -> author.getAge()).map(String::valueOf);

6.3.2 引用对象的实例方法

格式

对象名::方法名

使用前提

​ 如果我们在重写方法的时候,方法体中只有一行代码,并且这行代码是调用了某个对象的成员方法,并且我们把要重写的抽象方法中所有的参数都按照顺序传入了这个成员方法中,这个时候我们就可以引用对象的实例方法

例如:

传进去一个参数name,并且按顺序传入了append的sb的成员方法中。

List<Author> authors = getAuthors();Stream<Author> authorStream = authors.stream();
StringBuilder sb = new StringBuilder();
authorStream.map(author -> author.getName()).forEach(name->sb.append(name));

优化后:

List<Author> authors = getAuthors();Stream<Author> authorStream = authors.stream();
StringBuilder sb = new StringBuilder();
authorStream.map(author -> author.getName()).forEach(sb::append);

6.3.3 引用类的实例方法

格式

类名::方法名

使用前提

​ 如果我们在重写方法的时候,方法体中只有一行代码,并且这行代码是调用了第一个参数的成员方法,并且我们把要重写的抽象方法中剩余的所有的参数都按照顺序传入了这个成员方法中,这个时候我们就可以引用类的实例方法。

例如:

调用了第一个参数str,且重写的抽象方法use剩余参数start和length按照顺序依次传入成员方法substring()中。

interface UseString{String use(String str,int start,int length);
}public static String subAuthorName(String str, UseString useString){int start = 0;int length = 1;return useString.use(str,start,length);
}
public static void main(String[] args) {subAuthorName("三更草堂", new UseString() {@Overridepublic String use(String str, int start, int length) {return str.substring(start,length);}});}

优化后如下:

public static void main(String[] args) {subAuthorName("三更草堂", String::substring);}

6.3.4 构造器引用

如果方法体中的一行代码是构造器的话就可以使用构造器引用。

格式

类名::new

使用前提

​ 如果我们在重写方法的时候,方法体中只有一行代码,并且这行代码是调用了某个类的构造方法,并且我们把要重写的抽象方法中的所有的参数都按照顺序传入了这个构造方法中,这个时候我们就可以引用构造器。

例如:

List<Author> authors = getAuthors();
authors.stream().map(author -> author.getName()).map(name->new StringBuilder(name)).map(sb->sb.append("-三更").toString()).forEach(str-> System.out.println(str));

优化后:

List<Author> authors = getAuthors();
authors.stream().map(author -> author.getName()).map(StringBuilder::new).map(sb->sb.append("-三更").toString()).forEach(str-> System.out.println(str));

7,高级用法

7.1,基本数据类型优化

​ 我们之前用到的很多Stream的方法由于都使用了泛型。所以涉及到的参数和返回值都是引用数据类型。

​ 即使我们操作的是整数小数,但是实际用的都是他们的包装类。JDK5中引入的自动装箱和自动拆箱让我们在使用对应的包装类时就好像使用基本数据类型一样方便。但是你一定要知道装箱和拆箱肯定是要消耗时间的。虽然这个时间消耗很下。但是在大量的数据不断的重复装箱拆箱的时候,你就不能无视这个时间损耗了。

​ 所以为了让我们能够对这部分的时间消耗进行优化。Stream还提供了很多专门针对基本数据类型的方法。

​ 例如:mapToInt,mapToLong,mapToDouble,flatMapToInt,flatMapToDouble等。

List<Author> authors = getAuthors();
authors.stream().map(author -> author.getAge()).map(age -> age + 10).filter(age->age>18).map(age->age+2).forEach(System.out::println);authors.stream().mapToInt(author -> author.getAge()).map(age -> age + 10).filter(age->age>18).map(age->age+2).forEach(System.out::println);

优化后:

使用.mapToInt(author -> author.getAge())后,流当中的元素都是int类型了,节省了时间。

authors.stream().mapToInt(author -> author.getAge()).map(age -> age + 10).filter(age->age>18).map(age->age+2).forEach(System.out::println);

7.2,并行流

当流中有大量元素时,我们可以使用并行流去提高操作的效率。其实并行流就是把任务分配给多个线程去完全。如果我们自己去用代码实现的话其实会非常的复杂,并且要求你对并发编程有足够的理解和认识。而如果我们使用Stream的话,我们只需要修改一个方法的调用就可以使用并行流来帮我们实现,从而提高效率。

  • parallel() 将顺序流转换为并行流,使得后续的操作(如 peekfilterreduce)可能在多个线程中并行执行。
private static void test() {Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);Integer sum = stream.parallel().peek(new Consumer<Integer>() {@Overridepublic void accept(Integer num) {System.out.println(num+Thread.currentThread().getName());}}).filter(num -> num > 5).reduce((result, ele) -> result + ele).get();System.out.println(sum);
}

执行结果:

7main
2ForkJoinPool.commonPool-worker-11
8ForkJoinPool.commonPool-worker-4
9ForkJoinPool.commonPool-worker-18
6main
1ForkJoinPool.commonPool-worker-11
5ForkJoinPool.commonPool-worker-29
4ForkJoinPool.commonPool-worker-4
10ForkJoinPool.commonPool-worker-18
3ForkJoinPool.commonPool-worker-25
40

为什么会打印多次num+mian?

主线程也被分配到任务,main 线程参与了并行流的处理,主线程处理了元素 7 和 6,说明这两个元素被分配给了主线程执行。

并行流执行流程示例:

  1. 主线程将 10 个元素分成 4 个子任务(例如每组 2~3 个元素)。
  2. 工作线程 worker-1worker-4 各领取一个子任务。
  3. 主线程发现还有剩余元素(如最后 2 个),直接处理它们。
  4. 所有线程并行执行 peekfilterreduce 操作。

也可以通过parallelStream直接获取并行流对象。

parallelStream() 是集合(如 ListSet 等)提供的一个方法,用于创建并行流。它与 stream().parallel() 的效果相同,但写法更简洁。并行流的核心特点是将流的处理任务分解到多个线程上并行执行,从而提高处理大量数据时的性能。

List<Author> authors = getAuthors();
authors.parallelStream().map(author -> author.getAge()).map(age -> age + 10).filter(age->age>18).map(age->age+2).forEach(System.out::println);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/91248.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/91248.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/91248.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一般芯片电气特性中Flash参数达到其最大值的条件是什么?

芯片电气特性中标注的最大值&#xff08;比如 Data Flash 擦除时间的最大值&#xff09;&#xff0c;代表在最恶劣但仍在规格书定义的工作条件范围内的情况下&#xff0c;该参数可能达到的最差值。达到这个最大值通常是由多个最坏情况因素组合造成的。 对于 Data Flash 擦除时间…

python中正则中的split方法、sub方法、finditer方法、compile方法、match对象

正则常见方法梳理 split方法 将一个字符串按照正则表达式匹配结果进行分割,返回结果是列表类型。 pattern:正则表达式的字符串或原生字符串表示string:待匹配字符串maxsplit:最大分割数,剩余部分最为最后一个元素输出flags:正则表达式使用时候的控制标记 re模块的spli…

Pytorch中张量的索引和切片使用详解和代码示例

PyTorch 中张量索引与切片详解 使用前先导入&#xff1a; import torch1.基础索引&#xff08;类似 Python / NumPy&#xff09; 适用于低维张量&#xff1a;x[i]、x[i, j] x torch.tensor([[10, 11, 12],[13, 14, 15],[16, 17, 18]])print(x[0]) # 第0行: tensor([10…

北京-4年功能测试2年空窗-报培训班学测开-第五十一天

行叭&#xff0c;今天复习第一天&#xff0c;状态效率&#xff0c;差我发现&#xff0c;一旦换了新环境/知识&#xff0c;我就需要重新调整状态&#xff0c;少则一两天&#xff0c;多则一周多。从周日起就很迷茫&#xff0c;哪怕昨天老师讲了简历与面试&#xff0c;我也清楚地知…

虚拟现实的镜廊:当技术成为存在之茧

傍晚&#xff0c;摘下VR头盔的瞬间&#xff0c;房间里未关的台灯竟显得刺眼。指尖划过光滑的塑料外壳&#xff0c;温热的机体还在微微震动&#xff0c;如同某种活物的呼吸。窗外城市的光污染在玻璃上晕染成片&#xff0c;而我的视网膜里仍残留着方才的极光&#xff1a;挪威峡湾…

OSPF过滤

首先需要复习一个点&#xff1a;ACL最终隐含规则不同&#xff1a;如果acl匹配的是流量&#xff0c;则默认是运行所有如果acl匹配的是路由&#xff0c;则默认是拒绝所有OSPF过滤&#xff1a; 1.路由过滤1.LSA可以正常学习&#xff0c;但是不会使用LSA计算路由[AR1]acl 2000[AR1-…

OneCode 3.0 VFS客户端驱动(SDK)技术解析:从架构到实战

引言 在分布式系统架构中&#xff0c;高效的文件管理一直是开发者面临的核心挑战。OneCode 3.0作为新一代微内核引擎&#xff0c;其VFS&#xff08;虚拟文件系统&#xff09;模块通过客户端驱动(SDK)提供了统一的文件操作抽象&#xff0c;屏蔽了底层存储细节&#xff0c;为开发…

@Reusable-组件复用

Reusable组件复用概述&#xff1a;ArkUI布局中&#xff0c;将自定义组件从组件树上移除后放入缓存池&#xff0c;后续在创建相同类型的组件节点时&#xff0c;直接复用缓存池中的组件对象。ArkUI中使用Reusable装饰器以实现自定义组件的复用。常见的组件复用场景是当有大量数据…

黑马点评系列问题之p63unlock.lua不知道怎么整

问题描述&#xff1a;这个位置的这个unlock.lua文件是怎么生成的。老师给的不是很清楚。解决右键单击resources。如图输入回车&#xff0c;然后界面的上方&#xff0c;大概是在这个位置&#xff0c;会有让你引入这个依赖的选项&#xff0c;我的已经没有了。他会出来大概三个选项…

Python爬虫实战:研究Python-Markdown库相关技术

1. 引言 在当今信息爆炸的时代,网络上存在着大量有价值的技术文章。对于技术人员来说,如何高效地收集、整理和保存这些文章是一个重要的问题。爬虫技术可以帮助我们自动从网络上获取所需的文章内容,而 Markdown 作为一种轻量级标记语言,因其简洁的语法和良好的兼容性,成为…

JAVA经典单例模式

前言单例模式&#xff08;Singleton Pattern&#xff09;是一种创建型设计模式&#xff0c;确保一个类仅有一个实例&#xff0c;并提供全局访问点。它在需要控制资源&#xff08;如数据库连接、配置管理&#xff09;或避免重复创建对象的场景中广泛应用。一&#xff0c;核心概念…

20250715问答课题-基于BERT与混合检索问答系统

1. 引言构建一个基于BERT与混合检索策略的智能问答系统&#xff0c;通过深度学习与传统检索技术的融合&#xff0c;解决了心法领域知识检索中的三个关键问题&#xff1a;(1)专业术语的语义理解不足&#xff1b;(2)问答匹配精度低&#xff1b;(3)检索结果多样性差。2. 方法2.1. …

面向对象与面向过程、函数式编程

面向对象与面向过程、函数式编程 1. 面向过程编程&#xff08;Procedure-Oriented Programming&#xff09; 面向过程编程将程序视为一系列函数的集合&#xff0c;数据和操作数据的函数是分离的。在 Vue 3 中&#xff0c;这种风格通常表现为使用组合式 API&#xff08;Composit…

基于大数据的淘宝用户行为数据分析系统的设计与实现

开发环境开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven…

视频人脸处理——人脸面部动作提取

文章目录基于openface实现的技术方案windows环境下使用1. 安装依赖软件2. 下载OpenFace代码3. 编译OpenFace4. 提取面部动作单元5.选择提取目标方案liunx环境下使用安装与配置使用 OpenFace 提取面部动作单元应用场景基于py-feat实现的方案1. 从HuggingFace下载模型并设置Detec…

【Docker基础】Dockerfile构建与运行流程完全指南:从原理到实践优化

目录 引言 1 docker build命令参数详解 1.1 命令概述 1.2 常用参数详解 1.2.1 -t, --tag 1.2.2 -f, --file 1.2.3 --build-arg 1.2.4 --no-cache 1.2.5 --pull 1.3 构建流程图解 2 构建上下文&#xff08;Context&#xff09;优化技巧 2.1 构建上下文定义 2.2 优化…

StarRocks Community Monthly Newsletter (Jun)

版本动态 v3.5.0 存算分离&#xff1a;支持生成列、主键表重建索引&#xff1b;大规模导入逻辑优化&#xff0c;降低小文件数量。 数据湖分析&#xff1a;Beta 支持 Iceberg 视图创建与修改&#xff1b;支持 Iceberg REST Catalog 嵌套命名空间&#xff1b; 性能提升与查询优…

HDMI接口 vs. DisplayPort接口:电竞玩家该如何选择更优?

在搭建游戏主机或电竞PC时&#xff0c;显示器接口的选择&#xff08;HDMI vs. DP&#xff09;会直接影响画质、刷新率和延迟表现。本文将从分辨率、刷新率、可变刷新率&#xff08;VRR&#xff09;、带宽、兼容性等角度对比&#xff0c;帮你选出最适合游戏的接口。1. 基础对比&…

论文笔记:Learning Cache Replacement with CACHEUS

2021 USENIX GitHub - sylab/cacheus: The design and algorithms used in Cacheus are described in this USENIX FAST21 paper and talk video: https://www.usenix.org/conference/fast21/presentation/rodriguez Learning Cache Replacement with CACHEUS 1 intro 基于…

极致cms多语言建站|设置主站默认语言与设置后台固定语言为中文

小记 很长时间没有建站了,最近有需求所以又回炉了&#xff0c;使用的极致cms 极致cms帮助文档 | 极致CMS帮助文档 由于很长时间没做&#xff0c;又遇到了之前碰到的两个问题&#xff0c;凭借经验和记忆还是处理掉了 1.当网站前台使用?len或?lzh来切换语言时&#xff0c;管…