今日一语:当你发现编程的规律就是世界的规律时,你就是一名真正的程序员
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(Map<String,Integer> map, List<Integer> 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); 
}); 
/** 传入两个参数,无返回 */ 
Map<String,Integer> map = 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<T,R> T表示传入类型,R表示返回类型。
 比如表达式 person -> person.getAge(); 传入参数是 person,返回值是 person.getAge(),
 那么方法引用 Person::getAge 就对应着 Function<Person,Integer> 类型。
/** 所需函数式接口 */ 
@FunctionalInterface 
public interface Merchant<T> { T get(); 
} 
/** 接口使用类 */ 
public class Computer { public static Computer create(final Merchant<Computer> 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]
List<Computer> list = Arrays.asList(computer); 
list.forEach(Computer::getComputer); 
3)特定类的任意对象的方法引用 [Class::method]
List<Computer> list = Arrays.asList(computer);
list.forEach(Computer::getDate);
list.forEach(Computer::getTime); 
4)特定对象的方法引用 [instance::new]
List<Computer> list = 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的元素数量 */ 
List<Integer> numbers = 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<String> 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<T,U> 接收两个参数,不返回任何结果 */ 
getSomeSubject((s, integer) -> System.out.println(integer),"张三",12); 
/** BiFunction<T,U,R> 接收两个参数,返回一个结果 */ 
String someSubject = getSomeSubject((num1, num2) -> {return num1*num2+"";
},12,10); 
System.out.println("返回的结果为:"+someSubject); } 
// 方法定义 
private static String getSomeSubject(BiFunction<Integer,Integer,String> function,Integer num1,Integer num2) { return function.apply(num1,num2); 
} 
private static void getSomeSubject(BiConsumer<String,Integer> consumer,String name,Integer age) {consumer.accept(name,age); 
} 
感谢你的关注!有更多建议或疑问欢迎下方讨论…