java8 - java9 新特性 (一)
参考传智视频,整理中。。。
01_课程介绍
- 重点讲解java8 和java9当中的新特性
- 课程定位:
适合有一定java编程经验的同学,渴望了解最新java前沿技术的同学,快速入门 - 课程内容:
day01 lambda表达式,函数式接口、接口更新
day02 方法引用、常用函数式接口
day03 Stream流式处理api、模块化
02_Java版本特性更新历史
版本号 | 年份/代号 | 新特性(部分举例) |
---|---|---|
1.0 | 1996年 | |
1.1 | 1997年 | JDBC |
1.2 | 1998年 / Playground(运动场) | 集合、字符串池 |
1.3 | 2000年 / Kestrel(美洲红隼) | JDBC |
1.4 | 2004年 / Merlin(灰背隼) | XML、正则、JDBC3.0、断言、NIO |
5.0 | 2004年 / Tigger (老虎) | 泛型、注解、可变参数、枚举 |
6.0 | 2006年 / Mustang (野马) | 脚本、JDBC 4.0 |
7.0 | 2011年 / Dolphin (海豚) | NIO2.0 、try-with-resources |
8.0 | 2014年3月 / Spider (蜘蛛) | 接口更新、lambda表达式、方法引用、Stream API、函数式接口、Hashorn、JavaFX、DateTime |
9.0 | 2017年9月 | Jigsaw模块化、Jshell、接口小更新 |
Lambda标准格式
**1.一些参数
- 一个箭头
- 一些代码**
如果参数有多个,则使用逗号分隔; 如果没有参数,则留空
箭头是固定写法
大括号相当于方法体
省略规则
- 参数的类型可以省略,但是只能同时省略所有参数的类型,或者干脆都不省略,不能致谢个别参数的类型
- 如果参数有且仅有一个,那么小括号可以省略
- 如果大括号之内的语句有且仅有一个,那么无论有没有返回值,return、大括号和分好,都可以省略
03_面向对象的Runnable接口写法
public static void main(String[] args) {
//匿名内部类对象
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("多线程执行!!!");
}
};
new Thread(runnable).start();
//Lambda表达式使用
new Thread(() -> System.out.println("111")).start();
}
day01_04_编程思想转换
如何进行软件开发
- 自己编写二进制
- 汇编语言
- 面向过程
- 面向对象
- 函数式编程思想
面向对象强调“一切皆对象“,如果要想做事情,必须找到对象来做
函数式编程思想强调”做什么,而不是怎么做“
05_体验Lambda的更优写法
public static void main(String[] args){
new Thread().start(() -> System.out.println("执行了。。。"));
}
06_复习并分析匿名内部类语法
Lambda分析
Runnable接口当中的run方法语义分析
public void run(){
//方法体
}
- 参数列表为空,不需要任何条件就可以执行该方法
- 没有返回值,方法不产生任何数据结果
- 方法体大括号,这才是关键的方法内容所在
() -> System.out.println("线程任务执行”);
- 小括号,不需要任何参数,即可直接执行
- 箭头指向后面要做的事情
- 尖肉后面就好比方法体大括号,代表具体要做的内容
07_Lambda表达式的标准格式
Lambda表达式的标准格式
三要素:
- 一些参数
- 一个箭头
- 一些代码
(参数类型 参数名称) -> { 一些代码}
- 如果参数有多个,那么使用逗号分隔,如果参数没有,则留空
- 箭头是固定写法
- 大括号相当于方法体
08_练习使用Lambda的标准格式
1、接口 Cook.java
/**
* lambda表达式的必要前提
* 1. 必须有一个接口
* 2.接口当中必须保证有且有个抽象方法
*/
public interface Cook {
/*
* 唯一的抽象方法
*/
void makeFood();
}
2、实现类
public class CookImpl implements Cook {
@Override
public void makeFood() {
System.out.println("makeFood.......");
}
}
3、内部类实现
public class Demo02_InnerClass {
public static void main(String[] args) {
method(new Cook() {
@Override
public void makeFood() {
System.out.println("makeFood...内部类实现。。。");
}
});
}
private static void method(Cook cook){
cook.makeFood();
}
}
public class Demo02_Lambda {
public static void main(String[] args) {
method(() -> System.out.println("makeFood... Lambda实现方式。。。"));
}
private static void method(Cook cook){
cook.makeFood();
}
}
09_Lambda表达式的参数和返回值
1、实体类
public class Person(){
private String name;
private int age;
//setter/getter、 构造方法、toString()省略
}
2、测试类
方式一:
使用匿名内部类排序
public class SortTest{
public static void main(String[] args) {
Person[] arrays = {
new Person("刘备", 30),
new Person("张飞", 25),
new Person("张苞", 3),
new Person("关羽", 27),
};
System.out.println(Arrays.toString(arrays));
Arrays.sort(arrays, new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return o1.getAge() - o2.getAge();
}
});
System.out.println("-------------------------------------排序后---------------------------------");
System.out.println(Arrays.toString(arrays));
}
方式二:
Lambda方式
public class Demo02_Lambda {
public static void main(String[] args) {
Person[] arrays = {
new Person("刘备", 30),
new Person("张飞", 25),
new Person("张苞", 3),
new Person("关羽", 27),
};
System.out.println(Arrays.toString(arrays));
Arrays.sort(arrays,(Person o1, Person o2) -> {
return o1.getAge() - o2.getAge();
});
System.out.println("-------------------------------------排序后---------------------------------");
System.out.println(Arrays.toString(arrays));
}
}
10_练习使用Lambda的参数和返回值
public interface Calculator {
//两数求和
int sum(int a, int b);
}
//测试类
public class CalculatorLambdaTest {
public static void main(String[] args) {
method( (a, b) -> { return a + b ;});
}
private static void method(Calculator calc){
int result = calc.sum(1,2);
System.out.println(result);
}
}
11_Lambda表达式的省略格式
上面的表达式可以再简写
public class CalculatorLambdaFormat {
public static void main(String[] args) {
// 带有参数类型
//1.method( ( int a, int b) -> { return a + b ;});
//省略参数类型
//2.method( ( a, b) -> { return a + b ;});
//大括号语句有且只有一个,可省略大括号、return、分号
//3.method( (a , b) -> a + b);
method( (a , b) -> a + b);
}
private static void method(Calculator calc){
int result = calc.sum(1,2);
System.out.println(result);
}
}
Lambda表达式的省略规则:
1.参数的类型可以省略,但是只能同时省略所有参数的类型,或者干脆都不省略,不能致谢个别参数的类型
2.如果参数有且仅有一个,那么小括号可以省略
3.如果大括号之内的语句有且仅有一个,那么无论有没有返回值,return、大括号和分好,都可以省略
12_练习使用Lambda的省略格式
/**
* lambda表达式的必要前提
* 1. 必须有一个接口
* 2.接口当中必须保证有且有个抽象方法
*/
public interface Cook {
void makeFood();
}
//测试类
public class Demo01_Lambda {
public static void main(String[] args) {
method( () -> System.out.println("makeFood...."));
}
private static void method(Cook cook){
cook.makeFood();
}
}
13_Lambda的使用前提
1.必须保证有一个接口,而且其中的抽象方法有且仅有一个
2.必须具有上下文环境,才能推导出来Lambda对应的接口
14_函数式接口的定义和使用
函数式接口: 接口当中有且仅有一个抽象方法
@FunctionalInterface注解:用来检测一个接口是不是函数式接口
编译的时候,写上这个注解:
1.如果是函数式接口,那么编译通过。
2.如果不是函数式接口,那么编译失败
注意事项:
@FunctionalInterface注解是可选的,就算不用这个注解,只要保证接口满足函数式接口的定义要求,也照样是函数式接口
@FunctionalInterface
public interface MyInterface {
void method();
}
15_Lambda与匿名内部类的区别
语法糖
Lambda表达式并不是匿名内部类的“语法糖”
语法糖:代码的写法更加简便,但其实原理不便。
例如:
1.方法当中的可变参数,底层仍然是一个数组
2.增强for循环用于java.lang.Iterable实现类型时,底层仍然是一个迭代器
3.自动装箱、自动拆箱
Lambda表达式和匿名内部类存在根本区别,并非语法糖
区别:
- 所需的类型不一样
如果是匿名内部类,那么用接口、抽象类、普通的类
如果是Lambda表达式,则必须是接口 - 使用的限制不同
如果接口当中有且仅有一个抽象方法,那么可以使用Lambda表达式,也可以使用匿名内部类
但是如果接口当中抽象方法不唯一,则只能使用匿名内部类,不能使用Lambda表达式 - 实现原理不同
匿名内部类,其实就是一个类,编译之后,直接产生一个单独的.class字节码文件
Lambda表达式,编译之后,没有单独的.class字节码文件,对应的字节码会再运行的时候才会动态生成
16_接口的组成部分
- 常量
- 抽象方法
- 默认方法 (修饰符default) java8
- 静态方法 java8
- 私有方法 java8
17_接口默认方法的问题引出
案例1:默认方法使用
public interface MyInterface {
void method1();
void method2();
//现在需要重新定义一个方法,子类MyInterfaceImplA、MyInterfaceImplB都需要实现
//void methodNew();
}
public class MyInterfaceImplA implements MyInterface{
@Override
public void method1() {
}
@Override
public void method2() {
}
//重写接口的抽象方法
@Override
public void methodNew(){
}
}
public class MyInterfaceImplB implements MyInterface{
@Override
public void method1() {
}
@Override
public void method2() {
}
//重写接口的抽象方法
@Override
public void methodNew(){
}
}
接口升级:本来是2个抽象方法,现在需要编程3个抽象方法
接口的实现类当中必须对接口所有的抽象方法都要覆盖重写,除非实现类是一个抽象类
根据设计模式当中的开闭原则:对扩展开放,对修改关闭
从java8开始,接口当中允许定义default默认方法
常量的修饰符:public static final (都可以省略)
抽象方法的修饰符:public abstract (都可以省略)
默认方法的修饰符:public default void(public可以省略,default不能省略)
可使用java8提供的默认方法,解决接口中无须让各个实现类不重写接口中的抽象方法,使用默认方法
public interface MyInterface {
void method1();
void method2();
//现在需要重新定义一个方法
//void methodNew();
}
public class MyInterfaceImplA implements MyInterface{
@Override
public void method1() {
}
@Override
public void method2() {
}
}
public class MyInterfaceImplB implements MyInterface{
@Override
public void method1() {
}
@Override
public void method2() {
}
}
测试方法
public class Demo {
public static void main(String[] args) {
MyInterface myInterface = new MyInterfaceImplA();
//myInterface.method1();
//myInterface.method2();
myInterface.methodNew();
}
}
18_接口默认方法的定义和使用
/**
* 接口的实现类当中必须对接口所有的抽象方法都要覆盖重写,除非实现类是一个抽象类
* 接口升级:本来是2个抽象方法,现在需要编程3个抽象方法
*
* 设计模式当中的开闭原则:对扩展开放,对修改关闭
*
* 从java8开始,接口当中允许定义default默认方法
* 常量的修饰符:public static final (都可以省略)
* 抽象方法的修饰符:public abstract (都可以省略)
* 默认方法的修饰符:public default void(public可以省略,default不能省略)
*
* 默认方法可以有方法体实现
* 默认方法也可以进行覆盖重写,去掉default关键字,重新指定大括号方法体
*/
public interface MyInterface {
void method1();
void method2()
public default void methodNew(){
System.out.println("默认方法");
};
}
public class Demo01 {
public static void main(String[] args) {
MyInterface myInterface = new MyInterfaceImplA();
//myInterface.method1();
//myInterface.method2();
myInterface.methodNew();
}
}
19_接口静态方法的定义和使用
public interface Animal{
public abstract void eat();// 抽象方法
public static Animal getAnimal(){
return new Cat();
}
}
public class Cat implements Animal{
public void eat(){
}
}
public class Dog implements Animal{
public void eat(){
}
}
public class Demo{
public static void main(String[] args){
Animal animal = Animal.getAnimal();
animal.eat();
}
}
image.png
20_接口静态方法在Java9中的应用
集合接口的工厂静态方法:of
java8 当中接口中可以定义的静态方法
这个特性在java9中得以广泛应用
public static void main(String[] args) {
//普通写法
List<String> list = new ArrayList<>();
list.add("曹操");
list.add("刘备");
list.add("关羽");
list.add("张飞");
System.out.println(list);
//匿名内部类
List<String> list2 = new ArrayList<String>(){
{
add("曹操");
add("刘备");
add("关羽");
add("张飞");
}
};
System.out.println(list2);
//java 9 写法
//静态
//list
List<String> list3 = List.of("aa","bb","cc","dd");
System.out.println(list3);
//set
Set<String> set = Set.of("aa","bb","cc","dd");
System.out.println(set);
//map
Map<String,Object> map = Map.of("k1","v1");
System.out.println(map);
}
21_接口私有方法的定义和使用
22_接口的组成梳理
在java 9当中,定义一个接口,基本组成都有:
java7或者更老的版本中:
1. 常量:public static final (都可以省略)
2. 抽象方法:public abstract (都可以省略)
java 8 新特性:
- 常量:public static final (都可以省略)
- 抽象方法:public abstract (都可以省略)
3. 默认方法:public default (public可以省略,default不能省略,必须有方法体)
4. 静态方法:public static (public可以省略,static不能省略,必须有方法体)
java 9 新特性:
- 常量:public static final (都可以省略)
- 抽象方法:public abstract (都可以省略)
- 默认方法:public default (public可以省略,default不能省略,必须有方法体)
- 静态方法:public static (public可以省略,static不能省略,必须有方法体)
5. 私有方法:
a. 私有的成员方法:private (private 不能省略)
b. 私有的静态方法:private static (private static 不能省略)
Lambda表达式必须有上下文推导:
1.根据调用方法的参数推导得知Lambda对应的接口
2.根据局部变量的赋值来推导得知相应的接口