乐趣区

关于java:JAVA的函数式接口

函数式编程

  函数式编程 (英语:functional programming)或称 函数程序设计 泛函编程,是一种编程范式,它将电脑运算视为函数运算,并且防止应用程序状态以及易变对象。
  比起指令式编程,函数式编程更加强调程序执行的后果而非执行的过程,提倡利用若干简略的执行单元让计算结果一直渐进,逐层推导简单的运算,而不是设计一个简单的执行过程。
  纯函数式编程语言通常不容许间接应用程序状态以及易变对象。

函数式编程不须要思考 ” 死锁 ”(deadlock),因为它不批改变量,所以基本不存在 ” 锁 ” 线程的问题。不用放心一个线程的数据,被另一个线程批改,所以能够很释怀地把工作摊派到多个线程,部署 ” 并发编程 ”

OO(object oriented,面向对象)是形象数据,FP(functional programming,函数式编程)是形象行为。

Lambda 表达式

  1. Lambda 表达式是应用最小可能语法编写的函数定义:
  2. Lambda 表达式产生函数,而不是类。在 JVM(Java Virtual Machine,Java 虚拟机)上,一切都是一个类,因而在幕后执行各种操作使 Lambda 看起来像函数 —— 但作为程序员,你能够快乐地伪装它们“只是函数”。
  3. Lambda 语法尽可能少,这正是为了使 Lambda 易于编写和应用。

函数式接口

办法援用和 Lambda 表达式必须被赋值,同时编译器须要辨认类型信息以确保类型正确。Lambda 表达式特地引入了新的要求。代码示例:

x -> x.toString()

咱们分明这里返回类型必须是 String,但 x 是什么类型呢?

Lambda 表达式蕴含类型推导(编译器会主动推导出类型信息,防止了程序员显式地申明)。编译器必须可能以某种形式推导出 x 的类型。

上面是第 2 个代码示例:

(x, y) -> x + y

当初 xy 能够是任何反对 + 运算符连贯的数据类型,能够是两个不同的数值类型或者是 1 个 String 加任意一种可主动转换为 String 的数据类型(这包含了大多数类型)。然而,当 Lambda 表达式被赋值时,编译器必须确定 xy 的确切类型以生成正确的代码。

该问题也实用于办法援用。假如你要传递 System.out :: println 到你正在编写的办法,你怎么晓得传递给办法的参数的类型?

为了解决这个问题,Java 8 引入了 java.util.function 包。它蕴含一组接口,这些接口是 Lambda 表达式和办法援用的指标类型。每个接口只蕴含一个形象办法,称为函数式办法。

在编写接口时,能够应用 @FunctionalInterface 注解强制执行此“函数式办法”模式。一个 函数式接口 即便不加 @FunctionalInterface 注解,也能够与 lambda 配合应用,但这样的函数式接口是 容易出错 的:如有某个人在接口定义中减少了另一个办法,这时,这个接口就不再是函数式的了,并且编译过程也会失败。为了克服函数式接口的这种 脆弱性 并且可能 明确申明 接口作为函数式接口的用意,倡议显式应用该注解。

java.util.function 包旨在创立一组残缺的指标接口,使得咱们个别状况下不需再定义本人的接口。这次要是因为根本类型会产生一小部分接口。如果你理解命名模式,顾名思义就能晓得特定接口的作用。

以下是根本命名准则:

  1. 如果只解决对象而非根本类型,名称则为‘Supplier’,ConsumerPredicate,‘Operator’,Function 等。参数类型通过泛型增加。
  2. 如果接管的参数是根本类型,则由名称的第一局部示意,如 LongConsumerDoubleFunctionIntPredicate 等,但根本 Supplier 类型例外。
  3. 如果返回值为根本类型,则用 To 示意,如 ToLongFunction <T>IntToLongFunction
  4. 如果返回值类型与参数类型统一,则是一个运算符:单个参数应用 UnaryOperator,两个参数应用 BinaryOperator
  5. 如果接管两个参数且返回值为布尔值,则是一个谓词(Predicate)。
  6. 如果接管的两个参数类型不同,则名称中有一个 Bi

下表形容了 java.util.function 中的指标类型(包含例外情况):

特色 函数式办法名 示例
无参数;
无返回值
Runnable
(java.lang)
run()
Runnable
无参数;
返回类型任意
Supplier
get()
getAs 类型()
Supplier<T>
BooleanSupplier
IntSupplier
LongSupplier
DoubleSupplier
无参数;
返回类型任意
Callable
(java.util.concurrent)
call()
Callable<V>
1 参数;
无返回值
Consumer
accept()
Consumer<T>
IntConsumer
LongConsumer
DoubleConsumer
2 参数 Consumer BiConsumer
accept()
BiConsumer<T,U>
2 参数 Consumer
1 援用;
1 根本类型
Obj 类型 Consumer
accept()
ObjIntConsumer<T>
ObjLongConsumer<T>
ObjDoubleConsumer<T>
1 参数;
返回类型不同
Function
apply()
To 类型 类型 To 类型
applyAs 类型()
Function<T,R>
IntFunction<R>
LongFunction<R>
DoubleFunction<R>
ToIntFunction<T>
ToLongFunction<T>
ToDoubleFunction<T>
IntToLongFunction
IntToDoubleFunction
LongToIntFunction
LongToDoubleFunction
DoubleToIntFunction
DoubleToLongFunction
1 参数;
返回类型雷同
UnaryOperator
apply()
UnaryOperator<T>
IntUnaryOperator
LongUnaryOperator
DoubleUnaryOperator
2 参数类型雷同;
返回类型雷同
BinaryOperator
apply()
BinaryOperator<T>
IntBinaryOperator
LongBinaryOperator
DoubleBinaryOperator
2 参数类型雷同;
返回整型
Comparator
(java.util)
compare()
Comparator<T>
2 参数;
返回布尔型
Predicate
test()
Predicate<T>
BiPredicate<T,U>
IntPredicate
LongPredicate
DoublePredicate
参数根本类型;
返回根本类型
类型 To 类型 Function
applyAs 类型()
IntToLongFunction
IntToDoubleFunction
LongToIntFunction
LongToDoubleFunction
DoubleToIntFunction
DoubleToLongFunction
2 参数类型不同 Bi 操作
(不同办法名)
BiFunction<T,U,R>
BiConsumer<T,U>
BiPredicate<T,U>
ToIntBiFunction<T,U>
ToLongBiFunction<T,U>
ToDoubleBiFunction<T>

此表仅提供些惯例计划。通过上表,你应该或多或少能自行推导出更多行的函数式接口。

按此命名标准,能够举一些申明示例:


        Runnable runnable = () -> {};
        Callable<Integer> callable = () -> (new Random().nextInt());

        Supplier<Integer> supplier = () -> (new Random().nextInt());
        IntSupplier intSupplier = () -> (new Random().nextInt());

        Consumer<String> consumer = s -> System.out.print(s);
        Consumer<String> consumer1 = System.out::println;
        BiConsumer<Integer,Long> biConsumer = (i,l) -> System.out.print(i+l);
        ObjIntConsumer<Result> objIntConsumer = (r,i) -> System.out.print(r.getMessage() + i);

        //Operator 只反对根本类型
        UnaryOperator<Integer> unaryOperator = i -> i++;
        BinaryOperator<Integer> binaryOperator = (i1,i2) -> i1+i2;

        // 因为个别都用来比拟援用类型,所以没有根本类型的命名形式
        // 如果不是用作比拟目标,能够应用 Function
        Comparator<Result> comparator = (r1,r2) -> r1.getCode() - r2.getCode(); //Comparator.comparingInt(Result::getCode)

        Predicate<Integer> predicate = i -> i > 0;
        IntPredicate intPredicate = i -> i > 0;
        BiPredicate<Integer,Result> biPredicate = (i,r) -> i > r.getCode();


        Function<String,Integer> function =  s -> Integer.parseInt(s); //Integer::parseInt
        ToIntFunction<String> toIntFunction = Integer::parseInt;
        IntFunction<String> intFunction = Integer::toString;
        BiFunction<Integer,Long,String> biFunction = (i,l) -> "" + i + l;
退出移动版