035:Java8十大新特性
1 Java8集合框架源码分析课程介绍
本月的课程目标:
1.Java8新特性介绍 重点理解函数编程和Lambda
2.Java8下集合框架源码分析
Arraylist、Vector、LinkeList、HashTable、 HashMap、ConurrentHashMap源码分析
掌握以下结构:数组、链表、红黑树
3.Netty框架基本使用NIO、Bio编程模式 Tomat源码分析
4.Spring5中新特性响应式编程Web- Flux 需要掌握Netty和函数语法
2 Jdk1.8新特性概念课程介绍
课程内容:
1.Java8以上有那些新特性?你知道吗?
2.什么是函数编程?函数编程为webflux那些铺垫?
3.如何使用lambda表达式简化之前丑陋的代码
4.函数编程的推出?到底在业界有那些争议
JDK历史重大新特性
1.jdk5重大的革命是推出:注解、泛型、for-each、并发包出现、枚举
2.Jdk7重大的革命推出:switch中使用String
3.Jdk8中自Java5(2004)来发生重大的革命,推出了Lambda、函数编程等。
3 Jdk1.8新特性中接口默认关键字
Java8新特性
- Lambda表达式−Lambda允许把函数作为一个方法的参数(函数作为参数传递进方法中)。
- 方法引用−方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。
- 默认方法−默认方法就是一个在接口里面有了一个实现的方法。
- 新工具−新的编译工具,如:Nashorn引擎jjs、类依赖分析器jdeps。
- Stream API−新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。
- Date Time API−加强对日期与时间的处理。
- Optional类−Optional 类已经成为Java8类库的一部分,用来解决空指针异常。
- Nashorn, JavaScript引擎−Java 8提供了一个新的Nashorn javascript引擎,它允许我们在JVM上运行特定的javascript应用。
接口定义增强
在jdk1.8开始可以在接口使用default/static关键字定义方法,能够书写方法体
public interface UserService {
void addUser();// 抽象方法
/**
* java1.8之前 接口中不能定义普通方法
* java1.8开始推出default,接口中的方法使用default关键字修饰,可以书写方法体
* java1.8开始推出static,接口中的方法使用static关键字修饰,可以书写方法体
*/
default String defaultGetUser() {
return "mayikt";
}
/**
* 注意:使用static修饰的方法,不能被子类继承,不能通过实例调用,通过类名调用
*/
static void staticDelUser() {
System.out.println("delUser");
}
// 为什么要在Java中新增default和static关键字 能够书写方法体:为了函数编程做铺垫 */
}
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("addUser");
}
@Override
public String defaultGetUser() {
return "子类重写父类";
}
}
public class Test001 {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
String result = userService.defaultGetUser();
System.out.println("result:" + result);// result:子类重写父类
UserService.staticDelUser(); //delUser
}
}
4 Jdk1.8函数接口基本概念定义
函数式接口
两种实现的方式:
- 在接口中定义唯一一个的抽象方法
- @FunctionalInterface
1.两者实现起来并不冲突的,注解的作用主要的目的是为了强制约定一个接口只允许有一个抽象的方法
2.唯一一个抽象方法:可以存在static方法和default普通方法
@FunctionalInterface
public interface FunctionalMemberInterface {
public void addUser(String userName, String password);
// public String getUser(Long userId);
// jdk8 @FunctionalInterface 约定接口中只能有一个唯一的抽象方法
// 函数接口中支持default、static关键字修饰方法,允许存在Object类中equals方法
static void staticUser(){
System.out.println("staticUser");
}
default void defaultUser(){
System.out.println("default");
}
@Override
public boolean equals(Object obj);
}
常用的函数接口
多线程中:Runnable 也是一个函数接口 只有一个run抽象方法
Java排序类 Comparator接口
5 Jdk1.8新特性Lambda基本的使用
使用Lambda表达式调用接口
Lambda 左边(参数)->右边(主体内容)
@FunctionalInterface
public interface FunctionalPayInterface {
String getPay();
}
public class Test002 {
public static void main(String[] args) {
/**
* 什么是函数接口?
* 如果在接口中只有唯一一个抽象方法,该接口就可以称作为函数接口
* 定义的接口不能被new,如果没有子类的情况下,如何调用接口的方法--匿名内部类形式
*/
/**
* jdk1.8之前使用匿名内部类形式调用接口方法
*/
FunctionalMemberInterface functionalMemberInterface = new FunctionalMemberInterface() {
@Override
public void addUser(String userName, String password) {
System.out.println("userName:" + userName + ",password:" + password);
}
@Override
public boolean equals(Object obj) {
return false;
}
};
functionalMemberInterface.addUser("蚂蚁课堂666", "111111");//userName:蚂蚁课堂666,password:111111
/**
* 使用java8新特性lambda表达式简化匿名内部类
* 函数接口中,只有唯一一个自定义方法
*/
FunctionalMemberInterface functionalMemberInterface2 = (userName, password) -> {
System.out.println("userName:" + userName + ",password:" + password);
};
functionalMemberInterface2.addUser("蚂蚁课堂666", "222222");//userName:蚂蚁课堂666,password:222222
// lambda (参数列表) ->{方法主体}
FunctionalPayInterface functionalPayInterface = () -> {
System.out.println("使用lambda表达式调用functionalPayInterface方法");
return "蚂蚁课堂666";
};
String pay = functionalPayInterface.getPay();//使用lambda表达式调用functionalPayInterface方法
System.out.println("pay:" + pay); //pay:蚂蚁课堂666
FunctionalPayInterface functionalPayInterface2 = () -> "蚂蚁课堂1111";
String pay2 = functionalPayInterface2.getPay();
System.out.println("pay2:" + pay2); //pay2:蚂蚁课堂1111
}
}
6 实际项目中使用Lambda简化代码
场景1使用多线程
public class Test003 {
public static void main(String[] args) {
// jdk8之前使用多线程内部类的时候
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("子线程名称0:"+Thread.currentThread().getName());//子线程名称0:Thread-0
}
};
new Thread(runnable).start();//
// 使用lambda简化代码
Runnable runnableLambda = ()->{
System.out.println("子线程名称1:"+Thread.currentThread().getName());//子线程名称1:Thread-1
};
new Thread(runnableLambda).start();
new Thread(()->{System.out.println("子线程名称2:"+Thread.currentThread().getName());}).start();//子线程名称2:Thread-2
}
}
场景2 实际调用方法
@FunctionalInterface
public interface FunctionalRunnable {
public abstract void run();
}
public class Test004 {
public static void main(String[] args) {
addFunctionalRunnable(()->{
System.out.println("线程名称:"+Thread.currentThread().getName());//线程名称:main
});
}
public static void addFunctionalRunnable(FunctionalRunnable functionalRunnable){
functionalRunnable.run();
}
// lambda作用 简化传统匿名内部类写法
}
场景3 替代传统复杂循环
public class Test005 {
public static void main(String[] args) {
ArrayList<String> strings = new ArrayList<>();
strings.add("张三");
strings.add("李四");
strings.add("王五");
System.out.println("使用匿名内部类方式调用:");
strings.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println("S:" + s);
}
});
System.out.println("使用lambda表达式遍历集合:");
strings.forEach(t -> System.out.println("t:" + t));
System.out.println("使用方法引用形式遍历数据:");
strings.forEach(System.out::println);
}
}
运行结果:
7 Jdk1.8新特性之方法的引用
方法的引用
方法引用可以看作是调用特定方法的Lambda的一种快捷写法
左边 抽象方法 调用的类的实例 :: 右边是我们具体的方法
public class SmsService {
public SmsService(){
System.out.println("调用无参构造函数");
}
public void sendMsg() {
System.out.println(Thread.currentThread().getName() + ",异步形式开始发送短信");
}
public static void staticMsg() {
System.out.println("方法引用调用:" + Thread.currentThread().getName() + ",异步形式开始发送短信");
}
}
public class Test006 {
public static void main(String[] args) {
// 方法引用 在lambda表达式基础上做了一层简化
new Thread(() -> {
new SmsService().sendMsg();
}).start();
//使用方法引用形式调用方法
// 调用实例方法 实例对象::实用方法
SmsService smsService = new SmsService();
new Thread(smsService::sendMsg).start();
// 左边:抽象方法调用的类的实例 :: 右边:具体实例的方法
/* () -> {
* // 方法主体代码 new SmsService().sendMsg();
* }等同于Runnable接口
*/
Runnable runnable = smsService::sendMsg;
// 调用静态方法 类名::静态方法
new Thread(SmsService::staticMsg).start();
// 调用构造函数 类名::new
new Thread(SmsService::new).start();
}
}
运行结果:
8 方法的引用规范
方法引入规范:方法名称上参数类型必须要和函数接口方法参数类型保持一致。
@FunctionalInterface
public interface PayService {
void toPay(Long money);
}
public class Test007 {
public static void main(String[] args) {
PayService payService = (money) -> System.out.println(money);
PayService payService1 = (money) -> toPay1(money);
payService.toPay(10L);//10
payService1.toPay(20L);//20
// 方法引入 方法隶属::方法名称
PayService payService2 = Test001::toPay1;
payService2.toPay(30L);//30
}
public static void toPay1(Long money){
System.out.println(money);
}
// 方法引入规范:方法名称上的参数类型必须要和抽象方法上函数接口参数类型保持一致
}