1. 程式人生 > 程式設計 >java中functional interface的分類和使用詳解

java中functional interface的分類和使用詳解

java 8引入了lambda表示式,lambda表示式實際上表示的就是一個匿名的function。

在java 8之前,如果需要使用到匿名function需要new一個類的實現,但是有了lambda表示式之後,一切都變的非常簡介。

我們看一個之前講執行緒池的時候的一個例子:

//ExecutorService using class
 ExecutorService executorService = Executors.newSingleThreadExecutor();
 executorService.submit(new Runnable() {
  @Override
  public void run() {
  log.info("new runnable");
  }
 });

executorService.submit需要接收一個Runnable類,上面的例子中我們new了一個Runnable類,並實現了它的run()方法。

上面的例子如果用lambda表示式來重寫,則如下所示:

//ExecutorService using lambda
 executorService.submit(()->log.info("new runnable"));

看起是不是很簡單,使用lambda表示式就可以省略匿名類的構造,並且可讀性更強。

那麼是不是所有的匿名類都可以用lambda表示式來重構呢?也不是。

我們看下Runnable類有什麼特點:

@FunctionalInterface
public interface Runnable

Runnable類上面有一個@FunctionalInterface註解。這個註解就是我們今天要講到的Functional Interface。

Functional Interface

Functional Interface是指帶有 @FunctionalInterface 註解的interface。它的特點是其中只有一個子類必須要實現的abstract方法。如果abstract方法前面帶有default關鍵字,則不做計算。

其實這個也很好理解,因為Functional Interface改寫成為lambda表示式之後,並沒有指定實現的哪個方法,如果有多個方法需要實現的話,就會有問題。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}

Functional Interface一般都在java.util.function包中。

根據要實現的方法引數和返回值的不同,Functional Interface可以分為很多種,下面我們分別來介紹。

Function:一個引數一個返回值

Function介面定義了一個方法,接收一個引數,返回一個引數。

@FunctionalInterface
public interface Function<T,R> {

 /**
 * Applies this function to the given argument.
 *
 * @param t the function argument
 * @return the function result
 */
 R apply(T t);

一般我們在對集合類進行處理的時候,會用到Function。

Map<String,Integer> nameMap = new HashMap<>();
 Integer value = nameMap.computeIfAbsent("name",s -> s.length());

上面的例子中我們呼叫了map的computeIfAbsent方法,傳入一個Function。

上面的例子還可以改寫成更短的:

Integer value1 = nameMap.computeIfAbsent("name",String::length);

Function沒有指明引數和返回值的型別,如果需要傳入特定的引數,則可以使用IntFunction,LongFunction,DoubleFunction:

@FunctionalInterface
public interface IntFunction<R> {

 /**
 * Applies this function to the given argument.
 *
 * @param value the function argument
 * @return the function result
 */
 R apply(int value);
}

如果需要返回特定的引數,則可以使用ToIntFunction,ToLongFunction,ToDoubleFunction:

@FunctionalInterface
public interface ToDoubleFunction<T> {

 /**
 * Applies this function to the given argument.
 *
 * @param value the function argument
 * @return the function result
 */
 double applyAsDouble(T value);
}

如果要同時指定引數和返回值,則可以使用DoubleToIntFunction,DoubleToLongFunction,IntToDoubleFunction,IntToLongFunction,LongToIntFunction,LongToDoubleFunction:

@FunctionalInterface
public interface LongToIntFunction {

 /**
 * Applies this function to the given argument.
 *
 * @param value the function argument
 * @return the function result
 */
 int applyAsInt(long value);
}

BiFunction:接收兩個引數,一個返回值

如果需要接受兩個引數,一個返回值的話,可以使用BiFunction:BiFunction,ToDoubleBiFunction,ToIntBiFunction,ToLongBiFunction等。

@FunctionalInterface
public interface BiFunction<T,U,R> {

 /**
 * Applies this function to the given arguments.
 *
 * @param t the first function argument
 * @param u the second function argument
 * @return the function result
 */
 R apply(T t,U u);

我們看一個BiFunction的例子:

//BiFunction
 Map<String,Integer> salaries = new HashMap<>();
 salaries.put("alice",100);
 salaries.put("jack",200);
 salaries.put("mark",300);

 salaries.replaceAll((name,oldValue) ->
  name.equals("alice") ? oldValue : oldValue + 200);

Supplier:無參的Function

如果什麼引數都不需要,則可以使用Supplier:

@FunctionalInterface
public interface Supplier<T> {

 /**
 * Gets a result.
 *
 * @return a result
 */
 T get();
}

Consumer:接收一個引數,不返回值

Consumer接收一個引數,但是不返回任何值,我們看下Consumer的定義:

@FunctionalInterface
public interface Consumer<T> {

 /**
 * Performs this operation on the given argument.
 *
 * @param t the input argument
 */
 void accept(T t);

看一個Consumer的具體應用:

//Consumer
nameMap.forEach((name,age) -> System.out.println(name + " is " + age + " years old"));

Predicate:接收一個引數,返回boolean

Predicate接收一個引數,返回boolean值:

@FunctionalInterface
public interface Predicate<T> {

 /**
 * Evaluates this predicate on the given argument.
 *
 * @param t the input argument
 * @return {@code true} if the input argument matches the predicate,* otherwise {@code false}
 */
 boolean test(T t);

如果用在集合類的過濾上面那是極好的:

//Predicate
 List<String> names = Arrays.asList("A","B","C","D","E");
 List<String> namesWithA = names.stream()
  .filter(name -> name.startsWith("A"))
  .collect(Collectors.toList());

Operator:接收和返回同樣的型別

Operator接收和返回同樣的型別,有很多種Operator:UnaryOperator BinaryOperator ,DoubleUnaryOperator,IntUnaryOperator,LongUnaryOperator,DoubleBinaryOperator,IntBinaryOperator,LongBinaryOperator等。

@FunctionalInterface
public interface IntUnaryOperator {

 /**
 * Applies this operator to the given operand.
 *
 * @param operand the operand
 * @return the operator result
 */
 int applyAsInt(int operand);

我們看一個BinaryOperator的例子:

//Operator
 List<Integer> values = Arrays.asList(1,2,3,4,5);
 int sum = values.stream()
  .reduce(0,(i1,i2) -> i1 + i2);

Functional Interface是一個非常有用的新特性,希望大家能夠掌握。

本文的例子:https://github.com/ddean2009/learn-java-streams/tree/master/functional-interface

總結

到此這篇關於java中functional interface的分類和使用詳解的文章就介紹到這了,更多相關java中functional interface的分類和使用內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!