一. 简介

      函数式编程并不是Java新提出的概念,其与指令编程相比,强调函数的计算比指令的计算更重要;与过程化编程相比,其中函数的计算可以随时调用。在Java8出现之前,我们关注的往往是某一类对象应该具有什么样的属性,当然这也是面向对象的核心--对数据进行抽象。但是java8出现以后,这一点开始出现变化,似乎在某种场景下,更加关注某一类共有的行为(这似乎与之前的接口有些类似),这也就是java8提出函数式编程的目的。如下图所示,展示了面向对象编程到面向行为编程的变化:

java函数性能测试工具 java函数式编程性能_Java8新特性

      为此,Java 8引入了很多新特性,包括函数式接口、默认方法、Optional类等,本文将介绍这几个新特性。

 

二. 函数式接口

      Java 8 引入的一个核心概念是函数式接口(Functional Interfaces)。通过在接口里面添加一个方法,这个方法可以直接从接口中运行。如果一个接口定义唯一一个方法,那么这个接口就成为函数式接口。同时,引入了一个新的注解:@FunctionalInterface。可以把他它放在一个接口前,表示这个接口是一个函数式接口。这个注解是非必须的,只要接口只包含一个方法的接口,虚拟机会自动判断,不过最好在接口上使用注解 @FunctionalInterface 进行声明。在接口中添加了 @FunctionalInterface 的接口,只允许有一个方法,否则编译器也会报错。

      函数式接口通过一个单一的功能来表现。例如,带有单个compareTo方法的比较接口,被用于比较的场合。Java 8 定义了大量的函数式接口来广泛地用于lambda表达式。

     Java 8 在java.util.function中增加了不少新的函数式通用接口,例如:

      ①Function<T, R>:将 T 作为输入,返回 R 作为输出,他还包含了和其他函数组合的默认方法。                                   

      ②Predicate<T> :将 T 作为输入,返回一个布尔值作为输出,该接口包含多种默认方法来将 Predicate 组合成其他复杂的逻辑(与、或、非)。

      ③Consumer<T> :将 T 作为输入,不返回任何内容,表示在单个参数上的操作。

      我们在实际使用过程中,加有@FunctionalInterface注解的方法均是此类接口。下面给出一个示例,更多方法使用可具体查看Java 8官方API手册java.lang.Annotation Type FunctionalInterface 。

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

public class FunctionalStarter {

	public static void main(String args[]){
	      List<Integer> list = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);

	      System.out.println("All of the numbers:");
	      eval(list, n->true);

	      System.out.println("Even numbers:");
	      eval(list, n-> n%2 == 0 );

	      System.out.println("Numbers that greater than  5:");
	      eval(list, n -> n > 5 );
	   }

	   public static void eval(List<Integer> list, Predicate<Integer> predicate) {
	      for(Integer n: list) {
	         if(predicate.test(n)) {
	            System.out.println(n);
	         }
	      }
	   }

}

 

三. 默认方法

      Java 8在接口方面引入了一个关于默认方法实现的新概念。它也是作为一种向后兼容能力而出现,旧的接口也能用到Lambda表达式中。例如,List或Collection接口是没有forEach方法的声明的。但是,通过这些默认方法能够就能轻易地打破集合框架实现的限制。Java 8引入默认方式使得List和Collection接口能够拥有forEach方法的默认实现。实现了这些接口的类也不必再实现相同的功能了。

      语法如下所示:

public interface boy {
   default void print(){
      System.out.println("I am a boy.");
   }
}

1. 多个默认值

      接口中有了默认方法之后,在同一个类里面实现两个带有相同默认方法的接口就可行了。下面的代码演示了如何解决这种含糊不清的情况。

      首先是同一个类里面的两个接口:

public interface younger {
   default void print(){
      System.out.println("I am a younger.");
   }
}

public interface learner{
   default void print(){
      System.out.println("I am a learner.");
   }
}

      第一个解决办法就是创建一个自有的方法,来重写默认的实现。就像这样:

public class student implements younger, learner {
   public void print(){
      System.out.println("I am a younger and a learner, so I am  a student.");
   }
}

      另外一个解决办法是使用超类super来调用特定接口的默认方法:

public class student implements younger, learner {
   public void print(){
      learner.super.print();
   }
}

2. 静态默认方法

      我们也可以为这个接口增加静态的辅助方法(helper),就像下面这样:

public interface Younger {
   default void print(){
      System.out.println("I am a younger.");
   }

   static void sayHi(){
      System.out.println("Young is the capital.");
   }
}

3. 一个默认方法的例子

      下面我们通过一个例子来掌握如何使用默认方法:

public class DefaultStarter {
	public static void main(String args[]) {
		Younger younger = new Student();
		younger.print();
	}
}

interface Younger {
	default void print() {
		System.out.println("I am a younger.");
	}

	static void sayHi() {
		System.out.println("Young is the capital.");
	}
}

interface Learner {
	default void print() {
		System.out.println("I am a learner.");
	}
}

class Student implements Younger, Learner {
	public void print() {
        Younger.super.print();
        Learner.super.print();
        Younger.sayHi();
        System.out.println("I am a student!");
    }
}

      运行结果:

I am a younger.
I am a learner.
Young is the capital.
I am a student!

 

四. Optional类

      Optional是一个容器对象,用于容纳非空对象。Optional对象通过缺失值值代表null。这个类有许多实用的方法来促使代码能够处理一些像可用或者不可用的值,而不是检查那些空值(null)。

      在Java官方文档的解释中,它是一个可以为null的容器对象。如果值存在则 isPresent() 方法会返回 true ,调用 get()方法会返回该对象。

1. 类的声明及方法

      下面是java.util.Optional<T>类的声明:

public final class Optional<T> extends Object

      这个类继承了java.lang.Object类大多数方法,具体可看官方API手册。

2. 一个Optional类的例子

public class OptionalStarter {

	public Integer sum(Optional<Integer> a, Optional<Integer> b) {

		// isPresent 用于检查值是否存在
		System.out.println("First parameter is present: " + a.isPresent());
		System.out.println("Second parameter is present: " + b.isPresent());

		// 如果当前返回的是传入的默认值,orElse 将返回它
		Integer value1 = a.orElse(new Integer(0));

		// get 用于获得值,条件是这个值必须存在
		Integer value2 = b.get();
		return value1 + value2;
	}

	public static void main(String[] args) {
		OptionalStarter starter = new OptionalStarter();
		Integer value1 = null;
		Integer value2 = new Integer(5);
		
		// ofNullable 允许传参时给出 null
		Optional<Integer> a = Optional.ofNullable(value1);

		// 如果传递的参数为null,那么 of 将抛出空指针异常(NullPointerException)
		Optional<Integer> b = Optional.of(value2);
		System.out.println(starter.sum(a, b));

	}

}

      运行结果:

First parameter is present: false
Second parameter is present: true
5