java8 - java9 新特性 (一)

2019-10-05  本文已影响0人  wangxg_de27

参考传智视频,整理中。。。

01_课程介绍

  1. 重点讲解java8 和java9当中的新特性
  2. 课程定位:
    适合有一定java编程经验的同学,渴望了解最新java前沿技术的同学,快速入门
  3. 课程内容:
    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.一些参数

  1. 一个箭头
  2. 一些代码**

如果参数有多个,则使用逗号分隔; 如果没有参数,则留空
箭头是固定写法
大括号相当于方法体

省略规则

  1. 参数的类型可以省略,但是只能同时省略所有参数的类型,或者干脆都不省略,不能致谢个别参数的类型
  2. 如果参数有且仅有一个,那么小括号可以省略
  3. 如果大括号之内的语句有且仅有一个,那么无论有没有返回值,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_编程思想转换

如何进行软件开发

  1. 自己编写二进制
  2. 汇编语言
  3. 面向过程
  4. 面向对象
  5. 函数式编程思想

面向对象强调“一切皆对象“,如果要想做事情,必须找到对象来做
函数式编程思想强调”做什么,而不是怎么做“

05_体验Lambda的更优写法

public static void main(String[] args){
    new Thread().start(() -> System.out.println("执行了。。。"));
}

06_复习并分析匿名内部类语法

Lambda分析

Runnable接口当中的run方法语义分析

public void run(){
        //方法体
}
  1. 参数列表为空,不需要任何条件就可以执行该方法
  2. 没有返回值,方法不产生任何数据结果
  3. 方法体大括号,这才是关键的方法内容所在
() -> System.out.println("线程任务执行”);
  1. 小括号,不需要任何参数,即可直接执行
  2. 箭头指向后面要做的事情
  3. 尖肉后面就好比方法体大括号,代表具体要做的内容

07_Lambda表达式的标准格式

Lambda表达式的标准格式
三要素:

  1. 一些参数
  2. 一个箭头
  3. 一些代码

(参数类型 参数名称) -> { 一些代码}

  1. 如果参数有多个,那么使用逗号分隔,如果参数没有,则留空
  2. 箭头是固定写法
  3. 大括号相当于方法体

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表达式和匿名内部类存在根本区别,并非语法糖
区别:

  1. 所需的类型不一样
    如果是匿名内部类,那么用接口、抽象类、普通的类
    如果是Lambda表达式,则必须是接口
  2. 使用的限制不同
    如果接口当中有且仅有一个抽象方法,那么可以使用Lambda表达式,也可以使用匿名内部类
    但是如果接口当中抽象方法不唯一,则只能使用匿名内部类,不能使用Lambda表达式
  3. 实现原理不同
    匿名内部类,其实就是一个类,编译之后,直接产生一个单独的.class字节码文件
    Lambda表达式,编译之后,没有单独的.class字节码文件,对应的字节码会再运行的时候才会动态生成

16_接口的组成部分

  1. 常量
  2. 抽象方法
  3. 默认方法 (修饰符default) java8
  4. 静态方法 java8
  5. 私有方法 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 新特性:

  1. 常量:public static final (都可以省略)
  2. 抽象方法:public abstract (都可以省略)
    3. 默认方法:public default (public可以省略,default不能省略,必须有方法体)
    4. 静态方法:public static (public可以省略,static不能省略,必须有方法体)

java 9 新特性:

  1. 常量:public static final (都可以省略)
  2. 抽象方法:public abstract (都可以省略)
  3. 默认方法:public default (public可以省略,default不能省略,必须有方法体)
  4. 静态方法:public static (public可以省略,static不能省略,必须有方法体)
    5. 私有方法:
    a. 私有的成员方法:private (private 不能省略)
    b. 私有的静态方法:private static (private static 不能省略)

Lambda表达式必须有上下文推导:
1.根据调用方法的参数推导得知Lambda对应的接口
2.根据局部变量的赋值来推导得知相应的接口

上一篇下一篇

猜你喜欢

热点阅读