JDK16即将发布,你准备好了吗?JDK8新特性Lambda
岁月无声,岁月有声.2020实鼠不易,2021牛转乾坤。
当我们开发者与大多企业还停留在JDK8的时候,JDK16即将问世,你准备好了吗?
作为开发者的我与大家一样,我真心的跟不上,也跟不上jdk更新的速度,但这会影响我们吗?答案是否定的,目前主流大型企业很多停留在jdk6,jdk7与jdk8,jdk9这几个主流版本。所以对于我们而言,也可暂时不去更新学习jdk16。当然,具体情况根据自身需求情况,有需要就可以去学习,暂时不影响工作,也未必马上就去学习。当然,作为程序员的我们,是需要经常学习的,学海无涯,活到老学到老。有梦想就去追逐,即使失败,也无愧于心。那么在这里,博主并不会去介绍jdk16,博主这里主要是介绍jdk8相关的知识特性。
1、JDK8新特性简介
- 速度更快:算法的优化(比如HashMap)、底层内存结构的优化(将永久区PremGen变成了元空间MetaSpace)
- 代码更少(增加了新的语法Lambda表达式)
- 强大的Stream API
- 偏于并行
- 最大化减少空指针异常 Optional
tips:
永久区属于堆heap(在jdk1.7之前,heap中分为了2个区:垃圾回收区和永久区);而元空间存储在物理内存上
2、函数式编程思想
- 在数学中,函数指的是给定一个输入值,通过一套计算方案,最终给出结果值。 也就是拿什么东西做什么事。
- 面向对象又过分的强调了必须要通过对象的形式来做某事。(重视做事的过程)
- 而函数式编程强调“做什么,而不是以什么形式去做”。(重视做事的结果)
3、Lambda编程基础
3.1函数式接口
在学习Lambda之前,需要先搞清楚函数式接口
函数式接口:适用于函数式编程场景(Lambda表达式),接口中有且仅有一个抽象方法,且需要添加FunctionalInterface注解
示例代码如下:
@FunctionalInterface interface Conver{ void fun(); }
3.2Lambda表达式格式及说明
Lambda表达式的标准格式为: (参数类型 参数名称) ‐> { 代码语句 }
说明:
- 小括号内的语法与传统方法参数列表一致
- -> 是新引入的语法格式,代表指向动作 ,表示小括号前面的参数被用于后面{}里面的代码语句
- 大括号内的语法与传统方法体要求基本一致,它实际上是对函数式接口里唯一的那个抽象方法的重写
3.3Lambda省略格式
Lambda强调的是“做什么”而不是“怎么做”,所以凡是可以根据上下文推导得知的信息,都可以省略。
省略规则如下:
- 小括号内参数的类型可以省略;
- 如果小括号内有且仅有一个参,则小括号可以省略;
- 如果大括号内有且仅有一个语句,则无论是否有返回值,都可以省略大括号、return关键字及语句分号。
3.4代码实例
1)无参无返回值
import org.junit.Test; public class demo01 { @Test public void demo01(){ //匿名内部类写法 Runnable task = new Runnable() { @Override public void run() { System.out.println("多线程任务1"); } }; new Thread(task).start(); //Lambda写法 new Thread(()->{System.out.println("多线程任务2");}).start(); //{}里面只有一条语句,可以省略{}和; new Thread(()->System.out.println("多线程任务3")).start(); } }
2)有参有返回值
//有参有返回值 //有参有返回值 @FunctionalInterface public interface addSum { int sum(int a,int b); }
package com.demo.lambda.day03; import org.junit.Test; public class LambdaAddSumDemo { @Test public void demo02() { //需求:求两个整数和 //int result = addSum(10,20,(a,b)->{return a+b;}); //可优化为下面代码 int result = sum(10,20,(a,b)->a+b); System.out.println(result); } //两个int类型进行处理 public int sum(int a,int b,addSum c){ return c.sum(a,b); } }
3)参数、返回值类型为函数式接口类型
package com.demo.lambda.day03; import org.junit.Test; import java.util.Arrays; import java.util.Comparator; public class demo03 { @Test public void demo03() { //需求1:执行1个线程任务 startThread(()->System.out.println("多线程")); //需求2:将数组按照由小到大顺序排序 String[] arr = {"c","a","d","b"}; Arrays.sort(arr,compara()); System.out.println(Arrays.toString(arr)); } //参数为函数式接口,执行1个线程操作 public void startThread(Runnable target){ new Thread(target).start(); } //返回值类型为一个函数式接口,返回一个比较器对象 public Comparator<String> compara(){ return (a,b)->a.compareTo(b); } }
3.5Lambda的延迟执行
有些场景代码执行后,结果不一定会使用,这就造成了性能浪费。而Lambda具有延迟执行的特性,就可以很好的解决这个问题。
参考代码如下:
package com.demo.lambda.day03; import org.junit.Test; public class LambdaStringDemo { @Test public void demo04() { String msg1 = "hello"; String msg2 = "world"; //不论level,在调用log方法的时候,后面的参数一定要进行拼接操作 log("2",msg1+msg2); //只有当level符合条件,才会去调用append方法,才会执行Lambda newLog("1",()->msg1+msg2); } //记录日志 public void log(String level,String msg){ if("1".equals(level)){ System.out.println(msg); } } public void newLog(String level,MessageBuilder mb){ if("1".equals(level)){ System.out.println(mb.append()); } } }
4、Lambda编程进阶
公共定义的函数式接口
从jdk1.8开始提供了function包,该包针对于用户有可能做的函数式接口做了一个公共定义
最为核心的有四个接口:
- 功能性接口:Function<T, R>
是对接收一个T类型参数,返回R类型的结果的方法的抽象
抽象方法:R apply(T t)
默认方法:andThen
示例代码如下:
package com.demo.lambda.day03; import org.junit.Test; import java.util.function.Function; public class demo5 { @Test public void functionTest() { int num = fun("100",s->Integer.parseInt(s) );//字符串转成int类型 System.out.println(num); //先将字符串转成int,再*10 int result = method("5", s->Integer.parseInt(s), a->a *= 10); System.out.println(result); } //用于字符串处理 public Integer fun(String s, Function<String,Integer> fun){ return fun.apply(s); } //andThen:先执行一次apply操作,然后将第一次执行apply操作后获得的返回值作为参数再执行一次apply操作 public int method(String s, Function<String,Integer> one,Function<Integer,Integer> two){ return one.andThen(two).apply(s); } }
2. 消费型接口:Consumer<T>
对应的方法类型为接收一个参数,没有返回值
抽象方法:void accept(T t)
默认方法:andThen
示例代码如下:
package com.demo.lambda.day03; import org.junit.Test; import java.util.function.Consumer; public class demo6 { @Test public void consumerTest(){ shopping(12345, m->System.out.println("花了"+m+"元买了包包")); //将"hElLo"转成大写输出,其次再转成小写输出 fun("hElLo",s->System.out.println(s.toUpperCase()), s->System.out.println(s.toLowerCase())); } //花钱购物 public void shopping(double money,Consumer<Double> con){ con.accept(money); } //andThen:使用提供的参数执行两次操作 public void fun(String str, Consumer<String> one, Consumer<String> two){ one.andThen(two).accept(str); } }
3.供给型接口:Supplier<T>
该接口对应的方法类型不接受参数,但是提供一个返回值
抽象方法:T get()
示例代码如下:
package com.demo.lambda.day03; import org.junit.Test; import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.function.Supplier; public class demo7 { @Test public void supplierTest(){ //获取10个0~99之间的随机数 List<Integer> list = getList(10, ()->new Random().nextInt(100)); System.out.println(list); } //获取指定个数的Integer集合 public List<Integer> getList(int count, Supplier<Integer> sup){ List<Integer> list = new ArrayList<>(); for(int i=0;i<count;i++){ list.add(sup.get()); } return list; } }
4.断言型接口:Predicate<T>
该接口对应的方法为接收一个参数,返回一个Boolean类型
抽象方法:boolean test(T t)
默认方法:and(与),or(或),negate(非)
示例代码如下:
package com.demo.lambda.day03; import org.junit.Test; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.function.Predicate; public class demo8 { @Test public void predicateTest(){ List<String> list = Arrays.asList("Tom","Jerry","Tony"); List<String> nl = filterList(list, s->s.startsWith("T"));//将所有以“T”开头的字符串放入集合中 System.out.println(nl); //判断一个字符串既包含"H",又包含"O" boolean bool = andFun(s->s.contains("H"),s->s.contains("O"),"HelloOpen"); System.out.println(bool); //判断一个字符串中是否含有"H"或者"O" bool = orFun(s->s.contains("H"),s->s.contains("O"),"HelloOpen"); System.out.println(bool); //对给定操作进行非判定 bool = negateFun(s->s.length()<5,"helloworld"); System.out.println(bool); } //将满足条件的字符串放入集合中 public List<String> filterList(List<String> list, Predicate<String> pre){ List<String> nl = new ArrayList<>(); for(String s:list){ if(pre.test(s)){ nl.add(s); } } return nl; } //and public boolean andFun(Predicate<String> one,Predicate<String> two,String s){ return one.and(two).test(s); } //or public boolean orFun(Predicate<String> one,Predicate<String> two,String s){ return one.or(two).test(s); } //negate public boolean negateFun(Predicate<String> pre, String s){ return pre.negate().test(s); } }
附:一些常用的其它接口
注:参考引用文献:
https://blog.csdn.net/u010572176/article/details/104393869
Jeff不能吃饭: 你的博客很有价值,分享了自己的见解,对我很有启发。
毒液Venom: 要饭也不好干了,现在大家都没钱
2301_81997377: 所以现在哪个方向比较好,本人普通二本
secret125: 不知道,反正国外已经没啥人用java了
EMIINGDY: 全别学了,全去要饭吧,每行都不好干,还是要饭最好干,一点不卷,环境好,争取40w,五年1w,200年