Java8新特性
标签:Java基础

Java8

1. 函数式编程

传统的命令式编程喜欢大量使用可变对象和指令。我们常常创建对象或者变量,并且修改它们的状态或者值,或者提供一系列指令来让程序执行。而对于申明式(函数式)编程,不需要提供明确的指令操作,所有细节都被封装好了,只需要提出需求就好。

1.1 代码更少

命令式编程与函数式编程例子:

    public static void main(String[] args) {
        int[] ints={1,2,3,4,5,6,7};
        System.out.println("命令式:");
        for (int i = 0; i < ints.length; i++) {
            System.out.print(ints[i]);
        }
        System.out.println("\n函数式:");
        Arrays.stream(ints).forEach(System.out::print);
    }

结果:

命令式:
1234567
函数式:
1234567

我们可以看见函数式编程比命令式编程所用代码更少

1.2 不变性

System.out.println("\n不变性:");
Arrays.stream(ints).map(x->x+1).forEach(System.out::print);
System.out.println();
Arrays.stream(ints).forEach(System.out::print);

最后结果为:

不变性:
2345678
1234567

我们在第二行对数组中的每个值进行加一,但是最后再次遍历的时候,数组却没改变。

1.3 易于并行

由于对象都是不变的,因此函数式编程更加易于并行,而且不用担心线程安全的问题发生。

2. 函数式编程基础

2.1 FunctionalInterface注解

Java8 提供了函数式接口概念,所谓函数式接口,简单的说就是定义了单一抽象方法的接口。

@FunctionalInterface
public interface IntHandler {
    void handle(int i);
}

该接口被定义成只含有一个抽象方法handle(),它符合函数式接口的定义。如果一个函数满足函数式接口的定义,那么即使不标注 @FunctionalInterface,编译器也会把它当做函数式接口的。

函数式接口只能有一个抽象方法而不是只能有一个方法,一是因为Java8中接口存在实例方法,而是因为任何被 java.lang.Object实现的方法,都不能被视为抽象方法。

@FunctionalInterface
public interface IntHandler {
    boolean equals(Object obj);
}

上面这种就不是,equals是Object的方法

@FunctionalInterface
public interface IntHandler {
    void handle(int i);
    @Override
    boolean equals(Object obj);
}

上面这种就是

2.2 接口默认方法

在Java8之前,接口只能含有抽象方法,Java8之后,接口可以含有若干个实例方法

public interface IPeople {
    void eat();
    default void say(){
        System.out.println("people say");
    }
}
public interface IStudent {
    default void say(){
        System.out.println("student say");
    }
}

上面定义了两个接口,都含有函数say,都提供了默认实现

public class AAA implements IPeople,IStudent {
    @Override
    public void eat() {
        System.out.println("eat");
    }

    @Override
    public void say() {
//        需要指定
        IPeople.super.say();
    }

    public static void main(String[] args) {
        AAA aaa=new AAA();
        aaa.eat();
        aaa.say();
    }
}

由于都有默认实现,所以这个时候要指定用哪一个了,否则会报错。

3. 方法引用

方法引用是用来简化Java8中的lambda表达式的一种手段,它通过类名和方法名来定位到一个静态方法或者实例方法。

 - 静态方法引用:`ClassName::methodName`
 - 实例上的实例方法引用:`instanceReference::methodName`
 - 超类上的实例方法引用:`super::methodName`
 - 类型上的实例方法引用:`ClassName::methodName`
 - 构造方法引用:`Class::new`
 - 数组构造方法引用:`TypeName[]::new`
 
 如上面的`System.out::print`,`System.out`是`PrintStrem`实例。

4. Lambda表达式

语法格式:

(parameters) -> expression
或
(parameters) ->{ statements; }

以下是lambda表达式的重要特征:

例子:

public class Lambda {
    public static void main(String[] args) {
        Lambda lambda = new Lambda();

        // 类型声明
        MathOperation addition = (int a, int b) -> a + b;
        // 不用类型声明
        MathOperation subtraction = (a, b) -> a - b;
        // 大括号中的返回语句
        MathOperation multiplication = (int a, int b) -> {
            return a * b;
        };
        // 没有大括号及返回语句
        MathOperation division = (int a, int b) -> a / b;

        System.out.println("10+5=" + lambda.operate(10, 5, addition));
        System.out.println("10-5=" + lambda.operate(10, 5, subtraction));
        System.out.println("10*5=" + lambda.operate(10, 5, multiplication));
        System.out.println("10/5=" + lambda.operate(10, 5, division));
        
        
        // 不用括号
        GreetingService greetingService = message -> System.out.println("hello" + message);
        // 用括号
        GreetingService greetingService1 = (message) -> System.out.println("aaa" + message);
        greetingService.sayMessage("aaa");
        greetingService1.sayMessage("bbb");
        

//        lambda 表达式只能引用标记了 final 的外层局部变量,这就是说不能在 lambda 内部修改定义在域外的局部变量,否则会编译错误。
        final int num1 = 5;
        Greeting greeting = num -> System.out.println(num + num1);

        greeting.sayMessage(num1);

        System.out.println(num1);
    }

    interface MathOperation {
        int operation(int a, int b);
    }

    private int operate(int a, int b, MathOperation mathOperation) {
        return mathOperation.operation(a, b);
    }
    
    
    interface GreetingService {
        void sayMessage(String message);
    }

    interface Greeting {
        void sayMessage(int num);
    }
}

执行结果:

10+5=15
10-5=5
10*5=50
10/5=2
helloaaa
aaabbb
10
5
序号 特性
1 Lambda 表达式
2 方法引用
3 函数式接口
4 默认方法
5 Stream
6 Optional 类
7 Nashorn, JavaScript 引擎
8 新的日期时间 API
9 Base64
  • 5 min read

CONTRIBUTORS


  • 5 min read