JDK 1.8 新特性

文章目录

  • 1、JDK 1.8 新特性
    • 1.1、lambda表达式
    • 1.2、方法的引用
    • 1.3、默认方法
    • 1.4、管道流

1、JDK 1.8 新特性

1.1、lambda表达式

Java在1.8版本的时候,引入了Lambda表达式,Lambda表达式指的是应用在单一抽象方法接口环境下的一种简化定义形式,可以用于解决匿名内部类的定义复杂问题。

匿名内部类

  • 没有名字的内部类。
  • 匿名内部类中必须存在继承或实现。

匿名内部类的产生原因

public class Demo {
    public static void main(String[] args) {
    	// 创建对象
        MyRunnable runnable = new MyRunnableImpl();
        // 对象调用方法
        runnable.run();
    }
}
// 定义一个接口
interface MyRunnable {
    public void run();
}
// 接口的实现类
class MyRunnableImpl implements MyRunnable {
    @Override
    public void run() {
        System.out.println("Run...");
    }
}

结果
Run...

一个简单的接口,在我们再主方法中使用之前,需要先实现它的方法,这样很不方便,所以我们出现了匿名内部类的方式来解决这个问题。

public class Demo {
    /**
     * 匿名内部类
     */
    public static void main(String[] args) {
        new MyRunnable() {
            @Override
            public void run() {
                System.out.println("Run...");
            }
        }.run();
    }
}
// 定义接口
interface MyRunnable {
    public void run();
}

结果
Run...

我们直接使用了匿名内部类,不需要去再去创建一个接口实现类,然后再拿来实例化对象,结果一样,只是把重写的方法拿到我们需要用的地方去操作。缺点就是看起来没有不使用匿名内部类看起来更加直观。

Lambda方式

java为了简化代码量,让编程更加的便捷,引入了Lambda表达式。

public class Demo {
    public static void main(String[] args) {
        MyRunnable myRunnable = () -> {
            System.out.println("Run...");
        };
    }
}

// 定义接口
interface MyRunnable {
    public void run();
}

两者比较,Lambda表达式,更加的方便快捷,不用重写方法。lambda表达式本质是接口的子实现,lambda表达式简化了匿名内部类的写法,lambda表达式另一个叫法是函数式编程。接口增加@FunctionalInterface注解,视为函数式接口,加上这个注解的接口,如果不满足函数式接口的规范(只有一个抽象方法,但是可以有非抽象方法的接口),编译器就会报错。

lambda表达式重要特征

定义两个接口,一个一个参数,一个两个参数

// 定义接口
@FunctionalInterface
interface MathOperation {
    int operation(int a, int b);
}

// 定义接口
@FunctionalInterface
interface Number {
    int getNumber(int c);
}

(1)可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。

// 使用类型声明
MathOperation addition = (int a, int b) -> a + b;
// 不使用类型声明
MathOperation addition = (a, b) -> a + b;

(2)可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。

// 一个参数可以省略圆括号
Number number = b -> 2 * b;
// 多个参数不能省略圆括号且需要用逗号隔开
MathOperation addition = (a, b) -> a + b;

(3)可选的大括号:如果主体包含了一个语句,就不需要使用大括号。

// 主体包含了一个语句,就不需要使用大括号
MathOperation add = (int a, int b) -> a+b;
// 主体包含了多个语句,就必须使用大括号,使用大括号就需要返回一个数值。
MathOperation add = (int a, int b) -> {a++;return a+b;};

(4)可选的返回关键字(return):如果主体只有一个表达式返回值则编译器会自动返回值,使用大括号需要指定表达式返回了一个数值。

// 主体只有一个表达式返回值则编译器会自动返回值,下面等同于{return a + b;}
MathOperation add1 = (int a, int b) -> a + b;
// 表达式使用大括号需要指定表达式返回了一个数值。
MathOperation add = (int a, int b) -> {return a + b;};

lambda表达式变量的作用域问题

(1)lambda表达式引用外层成员变量,如果外层成员变量为final,则在lambda内部不能修改成员变量的值,如果外层成员变量不为final,则在lambda内部能修改成员变量的值。

// 外层成员变量为final
static final int number = 1;

public static void main(String[] args) {

String str = "str";
GreetingService service = message -> {
    number++;//不能修改成员变量的值,编译报错
    System.out.println("hello " + message + str);
};
service.sayMessage("yang");
}	
--------------------------------------------------------------------------------------------
//外层成员变量不为final
static int number = 1;

public static void main(String[] args) {

String str = "str";
GreetingService service = message -> {
    number++;//可以修改成员变量的值,编译通过
    System.out.println("hello " + message + str);
};
service.sayMessage("yang");
}		

(2)lambda 表达式的局部变量可以不用声明为 final,但是必须不可被后面的代码修改(即隐性的具有 final 的语义)

String str = "str";
GreetingService service = message -> System.out.println("hello " + message + str);
service.sayMessage("yang");
str = "11";	// 编译报错

(3)lambda表达式不允许声明一个与局部变量同名的参数或局部变量。

// 局部变量名称为str,lambda表达式参数为message可行
String str = "str";
GreetingService service = message -> System.out.println("hello" + message);
--------------------------------------------------------------------------------------------
// 局部变量名称为str,lambda表达式参数为str不行,编译报错
String str = "str";
GreetingService service = str-> System.out.println("hello" + str);

1.2、方法的引用

方法的引用方式用类名::方法名,其本质还是lambda表达式。

// Car类
class Car {
    // 静态方法,创建Car对象
    public static Car create(final Supplier<Car> supplier) {
        return supplier.get();
    }

    // 静态方法,碰撞
    public static void collide(final Car car) {
        System.out.println("Collided " + car.toString());
    }

    // 普通方法,跟随
    public void follow(final Car another) {
        System.out.println("Following the " + another.toString());
    }

    // 普通方法,维修
    public void repair() {
        System.out.println("Repaired " + this.toString());
    }

}

@FunctionalInterface
interface Supplier<T> {
    T get();
}

(1)引用构造方法:类名称::new

// 匿名内部类写法
Car dataInfo = Car.create(new Supplier<Car>() {
    @Override
    public Car get() {
        return new Car();
    }

});
//java8的lambda写法
Car car2 = Car.create(()->new Car());
System.out.println(car2);

//java的方法的引用
Car car3 = Car.create(Car::new);
System.out.println(car3);

(2)静态方法的引用:类名称::静态方法的名称

// 引用构造器
Car dataInfo2 = Car.create(Car::new);

List<Car> list = Arrays.asList(dataInfo2);
list.forEach(Car::collide);

(3)特定任意的对象引用方法:类名称::非静态方法的名称

// 引用构造器
Car dataInfo2 = Car.create(Car::new);

List<Car> list = Arrays.asList(dataInfo2);
list.forEach(Car::repair);

(4)特定对象的方法引用方法:instance::非静态的方法的名称

// 引用构造器
Car dataInfo2 = Car.create(Car::new);
List<Car> list = Arrays.asList(dataInfo2);

list.forEach(dataInfo2 ::follow);

1.3、默认方法

  • 在接口中可以放置有方法体的方法,但方法必须用default来修饰。
  • 在接口添加默认方法,是用来给所有的子类提供一个功能。
  • 在接口中还可以放置静态方法,静态方法需要有方法体。
public class Demo {

    public static void main(String[] args) {

        Vehicle v = new Car();
        v.y();
        Vehicle.c();
    }
}

interface Vehicle {
    /**
     * 在接口中可以放置有方法体的方法,但方法必须用default来修饰 在接口添加默认方法,是用来给所有的子类提供一个功能
     */
    default void y() {
        System.out.println("y");
    }

    /**
     * 在接口中还可以放置静态方法,静态方法需要有方法体
     */
    static void c() {
        System.out.println("c");
    }
}

class Car implements Vehicle {

}

结果
y
c

1.4、管道流

https://blog.csdn.net/yy139926/article/details/128704893

你可能感兴趣的:(java,java)