今日一语:当你发现编程的规律就是世界的规律时,你就是一名真正的程序员
1 Lambda(蓝布达)表达式
编译后会产生一个$XXXImpl1的编译文件,与匿名内部类相似,但不等同于匿名内部类。
其原理是将方法作为参数进行传递,
JVM会使用一个动态调用的指令调用函数式接口中的方法。
同时使用lambda将会使代码更简洁易读。
别名:【闭包】
使用方式:①使用JDK自有的函数式接口【接口列表】②自定义函数式接口使用。
如下:
1)自定义函数式接口,并且只定义一个方法,返回值与参数没有限制
/** 接口1 要点:参数再封装返回 */ @FunctionalInterface public interface EventExector { String event(String methodName); } /** 接口2 要点:计算两个数字之和返回 */ @FunctionalInterface public interface LambdaInterface1 { int mathOption(int a,int b); } /** 接口3 要点:获取当前时间的时间戳 */ @FunctionalInterface public interface LambdaInterface2 { void catCurrentDate(Date date); } /** 接口4 要点:将Map中的value取出放入一个list中 */ @FunctionalInterface public interface LambdaInterface3 { void copyMap(Mapmap, List list); } /** 接口5 要点:无返回无参数 */
2)将定义号的函数式接口通过参数传入
/** 接口1注入方法1 */ private static int operation(int a,int b,LambdaInterface1 interface1) { return interface1.mathOption(a,b); } /** 接口2注入方法2 */ private static String realize(String target,EventExector exector) { return exector.event(target); } /** 接口3注入方法3 */ private static void getDate(Date date,LambdaInterface2 interface2) { interface2.catCurrentDate(date); } /** 接口4注入方法4 */ private static void replaceMap(LambdaInterface3 interface3, Map map,List list) { interface3.copyMap(map,list); } /** 接口5注入方法5 */ private static void goToWay(LambdaInterface4 interface4) { interface4.onTheWay(); }
-
调用方法,其中()中的参数为传入的参数, -> 代表lambda表达式的箭头指引符,
箭头符号的后面,需注意,如果有返回值,有两种返回书写方式。
在大括号中,使用return返回,没有大括号,直接将返回值写在箭头符后面。
如果没有返回值,箭头符后面的指引内容将是纯粹的Java指令,不会有任何返回。
/** 传入一个参数 有返回 */ System.out.println(realize("xx", (x) -> "HELLO GUYS! " + x)); /** lambda 传入两个参数 有返回 */ System.out.println(operation(1, 2, (a, b) -> a + b)); /** 传入一个参数,无返回 */ getDate(new Date(), date -> { long time = date.getTime(); System.out.println("当前内容时间戳"+time); }); /** 传入两个参数,无返回 */ Mapmap = new Hashtable<>(); map.put("one",1); map.put("two",2); map.put("three",3); map.put("four",4); List list = new ArrayList(); replaceMap((map1, list1) -> { for (String s : map.keySet()) { list.add(map.get(s)); } },map,list); /** 无参数无返回 */ goToWay(() -> System.err.println("请纠正你的方向!"));
4)使用lambda注意事项
-
外部局部变量[基本类型]放在lambda中使用时,必须使用final修饰.
因为lambda中外部局部变量无法传递!变量值无法改变。
final:
① 如果修饰给基本类型变量,则表示值不可改变;
② 如果修饰引用类型变量,那么变量的引用地址不可改变,但是属性值是可以改变的。
-
考虑性能,如果代码不繁多,可以不用lambda
@Test public void lambda2() { String name = "我醉了"; int age = 12; sayHello("高进",message -> { name = "dsa"; // 此处编译会报错 age = 11; // 此处编译会报错 System.out.println(message+name+age); }); }
2 双冒号::语法
这种 [方法引用] 或者说 [双冒号运算] 对应的参数类型是 Function
比如表达式 person -> person.getAge(); 传入参数是 person,返回值是 person.getAge(),
那么方法引用 Person::getAge 就对应着 Function
/** 所需函数式接口 */ @FunctionalInterface public interface Merchant{ T get(); } /** 接口使用类 */ public class Computer { public static Computer create(final Merchant merchant) { return merchant.get(); } public static void getComputer(final Computer computer) { System.out.println("地址:"+computer.toString()); } public void getPro(final Computer computer) { System.out.println(computer.hashCode()); } public void getDate() { System.out.println(LocalDate.now().get(ChronoField.YEAR)); } public void getTime() { System.out.println(LocalTime.now().get(IsoFields.DAY_OF_QUARTER)); } }
主要有四种类型:
1)构造器引用 [Class::new]
Computer computer = Computer.create(Computer::new);
2)静态方法引用 [Class::static_method]
Listlist = Arrays.asList(computer); list.forEach(Computer::getComputer);
3)特定类的任意对象的方法引用 [Class::method]
Listlist = Arrays.asList(computer); list.forEach(Computer::getDate); list.forEach(Computer::getTime);
4)特定对象的方法引用 [instance::new]
Listlist = Arrays.asList(computer); final Computer huawei = Computer.create(Computer::new);` list.forEach(huawei::getPro);
3 Optional
JDK8处理空指针异常的工具类,减少空指针判断,可以存储空对象
只有两个值,一个是原本值,一个是空值
/** 静态方法 */ Optional.empty() 返回一个空的Optional对象 Optional.of() 返回一个指定非null值的Optional Optional.ofNullable() 如果为非空,返回 Optional 描述的指定值,否则返回空的 Optional /** 实例方法 */ optional.hashcode 返回存在值的哈希码,如果值不存在 返回 0 optional.toString 返回一个Optional的非空字符串,用来调试 optional.get 如果在这个Optional中包含这个值,返回值,否则抛出异常:NoSuchElementException optional.equals 判断其他对象是否等于 Optional optional.isPresent 如果值存在则方法会返回true,否则返回 false optional.ifPresent 如果值存在则使用该值调用 consumer , 否则不做任何事情 optional.filter 如果值存在,并且这个值匹配给定的 predicate,返回一个Optional用以描述这个值,否则返回一个空的Optional optional.flatMap 如果值存在,返回基于Optional包含的映射方法的值,否则返回一个空的Optional optional.orElse 如果存在该值,返回值, 否则返回 other optional.map 如果有值,则对其执行调用映射函数得到返回值。如果返回值不为 null, 则创建包含映射返回值的Optional作为map方法返回值,否则返回空Optional optional.orElseGet 如果存在该值,返回值, 否则触发 other,并返回 other 调用的结果 optional.orElseThrow 如果存在该值,返回包含的值,否则抛出由 Supplier 继承的异常
4 Stream
/** 生成流 */ list.stream() list.parallelStream() /** 所有操作 */ forEach() -> 循环操作 filter() -> 条件满足 map() -> 值处理 sorted() -> 排序 limit() -> 控制数量 summaryStatistics() -> 数据统计 在之前需要使用mapTo系列方法,也就是前提需要有数据流(int,float,double),主要有最大值,最小值,总和,总数,平均数 collect(Collectors.toList()) -> 转换成集合 collect(Collectors.joining(分隔符)) -> 将字符串内容合并到一起 /** 代码示例 */ /** Stream 得到集合中元素值大于等于7的元素数量 */ Listnumbers = Arrays.asList(1, 2, 2752, 2200, 7857, 6, 7, 8, 45, 54, 78, 857, 3, 357857, 86, 200780); numbers.stream() .filter(obj -> obj % 2 == 0) .limit(5).map(obj -> obj << 2) .sorted((o1, o2) -> o2 - o1) .forEach(integer -> { System.out.print(integer+"\t"); }); /** 使用Join */ List stringList = Arrays.asList("张三","李四","王五","赵六","钱七","胡八"," "); String collect = stringList.stream() .collect(Collectors.joining("先生,")) .trim(); // 取出字符串尾部的 ',' System.out.println(collect.substring(0,collect.length()-1)); ========控制台出入如下========= 11008 8800 32 24 8 张三先生,李四先生,王五先生,赵六先生,钱七先生,胡八先生
5 时间API
/** 月份支持 获取单独月份的支持 */ Month /*月份天数支持 可以获取月日格式的时间 */ MonthDay /**年份支持 可以获取年份*/ Year /*年份月支持 获取年月格式的时间*/ YearMonth /*时间戳操作 sql包中的获取时间戳中的方法*/ TimeStamp /*瞬时时间 获取时间戳格式的时间*/ Instant /*星期支持 星期天数的格式时间获取*/ DayOfWeek /*日期支持 只获取基本的日期格式的时间。如【年-月-日】*/ LocalDate /*日期时间支持 获取日期时间支持,不包含时区与星期。,如【年-月-日T时:分:秒.Nano秒】,其中T分隔符*/ LocalDateTime /*时间支持 只支持时间,不封装时区及任何时间信息*/ LocalTime /*日期时间转换器 提供日期时间格式的转换*/ DateTimeFormatter /*单线程日期时间转换器 只有一个返回字符串的静态方法*/ DateTimeFormatterBuilder
6 重复注解与类型注解
/** 重复注解,可以重复使用,原理是用了注解容器 **/ @Retention(RetentionPolicy.RUNTIME) @Repeatable(Annos.class) public @interface Anno { String value(); } @Retention(RetentionPolicy.RUNTIME) @interface Annos { Anno[] value(); }
使用重复注解的原理使用了注解容器,实际上被声明的类上的注解是容器注解
/** 类型注解主要就是泛型与声明类型的时候可以使用,保证了程序的健壮性 */ /** 定义一个可以使用在类型上的注解 */ @Retention(RetentionPolicy.RUNTIME) // TYPE_USE 用于类型 TYPE_PARAMETER 用于表示泛型 @Target(ElementType.TYPE_USE) public @interface MyTest { String value() default ""; }
7 concurrent并发包
// JUC包是jdk1.8为并发编程提供的工具包 提供了一些并发工具实现,后续补充
8 默认方法
在JDK8之前,一旦修改了接口中的方法,所有实现类都必须改动。
为了不影响之前的版本,提供在接口中定义默认方法的实现。
在方法前修饰default,并在代码域中编写默认内容
public interface Vehicle { /** 默认方法 */ default void print() { System.out.println("我是一辆车!"); } /** 静态方法 */ static void hornBlock() { System.out.print("我要超车了!"); } }
9 Base64编码
// 编码 private static String printEncoding(String str) { Base64.Encoder encoder = Base64.getEncoder(); byte[] encode = encoder.encode(str.getBytes()); return new String(encode); } // 解码 private static String printDecoding(String str) { Base64.Decoder decoder = Base64.getDecoder(); byte[] decode = decoder.decode(str.getBytes()); return new String(decode); }
10 内置函数式接口的应用
/** 菜鸟教程实例 */ https://www.runoob.com/java/java8-functional-interfaces.html /** 方法调用 */ public static void main(String[] args) { /** BiConsumer接收两个参数,不返回任何结果 */ getSomeSubject((s, integer) -> System.out.println(integer),"张三",12); /** BiFunction 接收两个参数,返回一个结果 */ String someSubject = getSomeSubject((num1, num2) -> { return num1*num2+""; },12,10); System.out.println("返回的结果为:"+someSubject); } // 方法定义 private static String getSomeSubject(BiFunction function,Integer num1,Integer num2) { return function.apply(num1,num2); } private static void getSomeSubject(BiConsumer consumer,String name,Integer age) { consumer.accept(name,age); }
感谢你的关注!有更多建议或疑问欢迎下方讨论…
到此这篇关于一文详解JDK8常用10个更新特性的文章就介绍到这了,更多相关内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!
原文地址:https://blog.csdn.net/qq_45903258/article/details/132582185