详解Java8中的lambda表达式、::符号和Optional类
Java8中的lambda表达式、::符号和Optional类
0. 函数式编程
函数式编程(Functional Programming)属于编程范式(Programming Paradigm)中的用语,此外还有命令式编程(Imperative Programing)等,有兴趣的同学可以自行了解,我们这里大概解释一下函数式编程,在函数式编程中,输入一旦确定了,输出都确定了,函数调用的结果只依赖于传入的输入变量和内部逻辑,不依赖于外部,这样的写出的函数没有副作用。举个例子:
public class Person{ private int a = 1; public int add(int b){ return a + b; } public int pow(int c){ return c * c; } public static void main(String[] args){ Person p = new Person(); p.add(1); p.pow(2); } }
上面代码中add(int b)这个方法就不符合函数式编程,这个函数调用后的结果不确定,它的结果不仅取决于b还取决于字段a。而pow(int c)这函数就是符合函数式编程的典范,只要调用它,输入的值c确定了返回值就肯定确定了。
在函数式编程中,函数也是一等公民,可以被当做参数传递,可以被赋值,被引用,可以把它当做一种数据类型来对待,如果你会使用javascript之类的语言就可以有更深的体会。如果要深入了解这种编程范式可以自行网上搜素资料了解。
1. lambda表达式
lambda表达式是jdk8中的新特性,上面讲函数式编程就是引入这个,oracle在jdk8中引入了lambda,从此Java中开始对函数式编程的部分支持。
Java中lambda表达式的语法结构:(params) -> expression。由三部分构成,第一部分是括号以及括号内部的形式参数,第二部分是"->"箭头符号,第三部分是expression方法体,方法体可以是代码块也可以是执行表达式。
//1. lambda表达式的完整形态:有输入参数,有返回值,有代码块。 (int a, int b) -> { int c = a + b; return c; } //2. lambda表达式在某些情况也可以省略一部分 //2.1 当代码块不需要返回值的 时候可以省略return语句 (int a, int b) -> { int c = a + b; } //2.2 当代码块只有一句的时候可以省略大括号 //并且这种情况默认返回这一句代码的执行结果 (int a, int b) -> a + b; // 同1具有同样的作用 //2.3 形参的类型可以根据函数式接口的里面的方法声明自行推断 //可以省略形参类型 (a, b) -> a + b; // 同1,2.2具有同样的效果 //2.4 当只有一个参数的时候可以省略,形参的小括号 a -> a * a;
接下来展示一个从定义接口到使用lambda表达式的代码
/** * description: * * @author waxxd * @version 1.0 * @date 2019-10-15 **/ public class Test1 { private int a = 1; private int b = 2; /** * 这个方法需要一个IAdd类型的参数 * @param add * @return **/ public int add1(IAdd add){ return add.add(a,b); } public static void main(String[] args) { Test1 test1 = new Test1(); // 使用lambda表达式 int c = test1.add1((a, b) -> a + b); System.out.println(c); // 使用匿名类 int d = test1.add1(new IAdd(){ @Override public int add(int a, int b){ return a + b; } }); System.out.println(d); } } /** * description: * 函数式接口,里面抽象方法只能有一个 * @author waxxd * @version 1.0 * @date 2019-10-15 **/ @FunctionalInterface public interface IAdd { int add(int a, int b); }
可以看见使用lambda表达式的方式相对于匿名类代码会精简优雅很多,下面给出一个经常使用的例子,创建线程:
public class Test(){ public static void main(String[] args) { Thread t1 = new Thread(new Runable(){ System.out.println("使用匿名类的方式创建线程"); }); Thread t2 = new Thread( () -> System.out.println("使用lambda方式创建线程")); t1.start(); t2.start(); } }
2. 双冒号::符号
这个符号第一次看见是在c++里面,在c++里面是一个类似标识作用域解析符号或者范围的符号,描述可能不准确,对c++有兴趣的同学可以自行查找。如果了解c++,这个操作符号就勉强类似类似在c++中函数指针,::在Java里面也可以叫做方法引用,就上面说的函数也是一等公民,这里就类似把方法作为参数传入。前面的例子我们使用lambda表达式都类似使用匿名类实现接口的方法,然而还有一种情况我们并不想要自己去实现接口的方法,只是想传进去一个已经有过实现了的方法,就可以使用::,它的语法规则如下:
类名::静态方法名 或者 类的实例::实例方法。
List<File> list = new ArrayList<>; list.forEach(File::getName); // 使用双冒号传递一个函数进来, list.forEach( file -> file.getName()); // 使用正常的lambda表达式
3. Optional类
Optional也是jdk8中的一个新的类的,它给予我们更加优雅的方式来处理Java语言中的NPE异常。可以从一定程度上代替if判断, 介绍相关接口:
- empty 创建一个空的Optional对象
- of 和ofNullable
of创建一个Optional对象, 如果传入的参数为空则跑出NPE异常.
ofNullable和上面一样, 但是当传入参数为空的时候会调用empty方法创建一个空Optional对象.
Optional<String> of = Optional.of("waxxd"); // 传入空参数会抛出NullPointerException异常 Optional<String> ofNull = Optional.of(null); // 以下两句都正常执行 Optional<String> ofNullable = Optional.ofNullable("waxxd"); // 参数为空的时候相当调用Optional.empty() Optional<String> ofNullableNull = Optional.ofNullable(null);
get/orElse/orElseGet/orElseThrow
// get 获取Option包裹的值如果值为null则抛出NoSuchElementException异常 String aa = Optional.of("aa").get(); // orElse 获取值如果值为空则返回orElse设置的默认值 String aa1 = Optional.of("aa").orElse("bb"); // orElseGet 获取值如果值为空则内部可以是一个实现Supplier接口的匿名内部类调用提供返回结果 String aa2 = Optional.of("aa").orElseGet( () -> "aaa".toUpperCase()); // orElseThrow获取值如果不存在则抛出后面的异常 Optional.empty().orElseThrow(IllegalArgumentException::new); // 实际的应用, 也就是上文所说的如何优化if // 比如你有个接口, 用户传入参数Integer type, 用户也可以选择不传, 不传我们为它设置默认值1 public void f(Integer type){ if(type = null) { type = 1; } Optional.ofNullable(type).orElse(1); }
到此这篇关于Java8中的lambda表达式、::符号和Optional类的文章就介绍到这了,更多相关Java8 lambda表达式内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!
相关文章
Java8 实现stream将对象集合list中抽取属性集合转化为map或list
这篇文章主要介绍了Java8 实现stream将对象集合list中抽取属性集合转化为map或list的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-05- 这篇文章主要介绍了java8如何用Stream查List对象某属性是否有重复的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-11
java8中的Collectors.groupingBy用法详解
这篇文章主要介绍了java8中的Collectors.groupingBy用法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-17- 取双引号内的内容我们如果一个字符串中只有一个可以使用explode来获得,但如果有多个需要使用正则表达式来提取了,具体的例子如下。 写程序的时候总结一点经验,如何只...2016-11-25
- 这篇文章主要介绍了Java8处理List的双层循环问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-19
浅谈Java8 的foreach跳出循环break/return
这篇文章主要介绍了Java8 的foreach跳出循环break/return,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-07-28- 本文主要介绍了C#中Lambda的相关知识。具有一定的参考价值,下面跟着小编一起来看下吧...2020-06-25
- 今天遇到一个正则匹配的问题,忽然翻到有捕获组的概念,手册上也是一略而过,百度时无意翻到C#和Java中有对正则捕获组的特殊用法,搜索关键词有PHP时竟然没有相关内容,自己试了一下,发现在PHP中也是可行的,于是总结一下,分享的同...2015-11-08
- 正则表达式是一门非常有用的并且进行模糊判断的一个功能了,我们下面来看通过正则来验证输入汉字、英语、数字,具体如下。 收藏了正则表达式。可以验证只能输入数...2016-11-25
- 这篇文章主要介绍了java正则表达式判断前端参数修改表中另一个字段的值,需要的朋友可以参考下...2021-05-07
- 常用的日期时间正则表达式 下面收藏了大量的日期时间正则匹配函数,包括分钟,时间与秒都能达到。 正则表达式 (?n:^(?=d)((?<day>31(?!(.0?[2469]|11))|30(?!.0?2)|29(...2016-11-25
- 网址规则是可寻的,所以我们可以使用正则表达式来提取字符串中的url地址了,下面一起来看看小编整理的几个PHP正则表达式匹配验证提取网址URL实例. 匹配网址 URL 的...2016-11-25
- 这篇文章主要介绍了Java8 使用流抽取List<T>集合中T的某个属性操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-05
- 这篇文章给大家详细介绍了JS中使用正则表达式g模式和非g模式的区别,非常不错,具有参考借鉴价值,需要的朋友参考下吧...2017-04-03
- 这篇文章主要介绍了正则表达式中两个反斜杠的匹配规则,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-05-07
- 本文主要介绍了JavaScript利用正则表达式替换字符串中内容的具体实现方法,并做了简要注释,便于理解。具有一定的参考价值,需要的朋友可以看下...2017-01-09
- 这篇文章主要介绍了C#正则表达式使用方法,大家参考使用...2020-06-25
java8时间 yyyyMMddHHmmss格式转为日期的代码
这篇文章主要介绍了java8时间 yyyyMMddHHmmss格式转为日期的代码,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-17- c#正则表达式,用于字符串处理、表单验证等场合,实用高效。现将一些常用的表达式收集于此,以备不时之需。...2020-06-25
- 这篇文章主要介绍了python正则表达式常用函数及使用方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-05-07