zoukankan      html  css  js  c++  java
  • on java 8 第十三章 函数式编程

    函数式编程的中心思想:是把函数作为参数传递给另一个函数,或把函数作为一个返回值。

    只是为了使程序适合有限的内存,程序员通过修改内存中的代码来节省代码空间,以便在程序执行时执行不同的操作。这种技术被称为自修改代码 (self-modifying code)

    OO(object oriented,面向对象)是抽象数据,

    FP(functional programming,函数式编程)是抽象行为

    纯粹的函数式语言在安全性方面更进一步。它强加了额外的约束,即所有数据必须是不可变的:设置一次,永不改变。

    “不可变对象和无副作用”范式解决了并发编程中最基本和最棘手的问题之一

    因此,经常提出纯函数式语言作为并行编程的解决方案(还有其他可行的解决方案)。

    1 新旧对比

    package functional;
    
    interface Strategy {
        String approach(String msg);
    }
    
    class Soft implements Strategy {
    
        @Override
        public String approach(String msg) {
            return msg.toLowerCase() + "?";
        }
    }
    
    class Unrealted {
        static String twice(String msg) {
            return msg + " " + msg;
        }
    }
    
    public class Strategize {
        Strategy strategy;
        String msg;
        Strategize(String msg){
            strategy = new Soft(); // [1]在 Strategize 中,Soft 作为默认策略,在构造函数中赋值。
            this.msg = msg;
        }
    
        void communicate(){
            System.out.println(strategy.approach(msg));
        }
        void changeStategy(Strategy strategy){
            this.strategy = strategy;
        }
    
        public static void main(String[] args) {
            Strategy[] strategies = {
                    new Strategy() {// [2]匿名内部类
                        @Override
                        public String approach(String msg) {
                            return msg.toUpperCase() + "!";
                        }
                    },
                    msg -> msg.substring(0,5),// [3]Java 8 的 Lambda 表达式
                    // 由箭头 -> 分隔开参数和函数体,箭头左边是参数,箭头右侧是从 Lambda 返回的表达式,即函数体。这实现了与定义类、匿名内部类相同的效果,但代码少得多。
                    Unrealted::twice// [4]Java 8 的方法引用,由 :: 区分。在 :: 的左边是类或对象的名称,在 :: 的右边是方法的名称,但没有参数列表。
            };
            Strategize s = new Strategize("Hello there");
            s.communicate();
            for (Strategy newStrategy : strategies){//遍历数组中的所有 Strategy
                s.changeStategy(newStrategy);// [5]将每个 Strategy 放入 变量 s 中
                s.communicate();// [6]产生不同的行为,具体取决于此刻正在使用的策略代码对象.我们传递的是行为,而非仅数据。
            }
        }
    }
    
    /*
    hello there?
    HELLO THERE!
    Hello
    Hello there Hello there
     */
    

    2 Lambda表达式

    package functional;
    
    interface Description {
        String brief();
    }
    
    interface Body {
        String detailed(String head);
    }
    
    interface Multi {
        String twoArg(String head, Double d);
    }
    
    public class LambdaExpressions {
        static Body bod = h -> h + " No Parens!"; //当只用一个参数,可以不需要括号 ()。 然而,这是一个特例。
        static Body bod2 = (h) -> h + " More details"; //正常情况使用括号 () 包裹参数。 为了保持一致性,也可以使用括号 () 包裹单个参数,虽然这种情况并不常见。
    
    
        static Description desc = () -> "Short info"; //如果没有参数,则必须使用括号 () 表示空参数列表。
        static Multi mult = (h, n) -> h + n; // 对于多个参数,将参数列表放在括号 () 中。
    
        //到目前为止,所有 Lambda 表达式方法体都是单行。 该表达式的结果自动成为 Lambda 表达式的返回值,在此处使用 return 关键字是非法的。 这是 Lambda 表达式缩写用于描述功能的语法的另一种方式。
        static Description moreLines = () -> { //如果在 Lambda 表达式中确实需要多行,则必须将这些行放在花括号中。 在这种情况下,就需要使用 return。
            System.out.println("moreLines()");
            return "from moreLines()";
        };
    
        public static void main(String[] args) {
            System.out.println(bod.detailed("Oh"));
            System.out.println(bod2.detailed("Hi"));
            System.out.println(desc.brief());
            System.out.println(mult.twoArg("pi ", 3.14159));
            System.out.println(moreLines.brief());
        }
    }
    /*
    Oh No Parens!
    Hi More details
    Short info
    pi 3.14159
    moreLines()
    from moreLines()
     */
    
    

    2.1 递归

    递归方法必须是实例变量或静态变量,否则会出现编译时错误。

    package functional;
    
    interface IntCall{
        int call(int arg);
    }
    
    

    阶乘函数

    package functional;
    
    public class RecursiveFactorial {
        static IntCall fact; //fact 是一个静态变量
    
        public static void main(String[] args) {
            fact = n -> n == 0 ? 1: n* fact.call(n-1);
            for (int i = 0; i <=10; i++)
                System.out.println(fact.call(i));
        }
    }
    /*
    1
    1
    2
    6
    24
    120
    720
    5040
    40320
    362880
    3628800
     */
    
    package functional;
    
    public class RecursiveFibonacci {
        IntCall fib; //实例变量
    
        RecursiveFibonacci() {
            fib = n -> n == 0 ? 0 :
                    n == 1 ? 1 :
                            fib.call(n - 1) + fib.call(n - 2);
        }
    
        int fibonacci(int n) {
            return fib.call(n);
        }
    
        public static void main(String[] args) {
            RecursiveFibonacci rf = new RecursiveFibonacci();
            for (int i = 0; i <= 10; i++)
                System.out.println(rf.fibonacci(i));
        }
    }
    
    /*
    0
    1
    1
    2
    3
    5
    8
    13
    21
    34
    55
     */
    

    3 方法引用

    Java 8 方法引用没有历史包袱。方法引用组成:类名或对象名,后面跟 :: ,然后跟方法名称。

    package functional;
    
    interface Callable { // [1]
        void call(String s);
    }
    
    class Describe {
        void show(String msg) {// [2] show() 的签名(参数类型和返回类型)符合 Callable 的 call() 的签名。
            System.out.println(msg);
        }
    }
    
    public class MethodReferences {
        static void hello(String name) {// [3]  hello() 也符合 call() 的签名。
            System.out.println("Hello," + name);
        }
    
        static class Description {
            String about;
    
            Description(String desc) {
                about = desc;
            }
    
            void help(String msg) {  // [4] //help() 也符合,它是静态内部类中的非静态方法。
                System.out.println(about + " " + msg);
            }
        }
    
        static class Helper {
            static void assist(String msg) {// [5] //assist() 是静态内部类中的静态方法。
                System.out.println(msg);
            }
        }
    
        public static void main(String[] args) {
            Describe d = new Describe();
            Callable c = d::show; // [6]  我们将 Describe 对象的方法引用赋值给 Callable ,它没有 show() 方法,而是 call() 方法。 但是,Java 似乎接受用这个看似奇怪的赋值,因为方法引用符合 Callable 的 call() 方法的签名。
            c.call("call()"); // [7] 可以通过调用 call() 来调用 show(),因为 Java 将 call() 映射到 show()。
    
            c = MethodReferences::hello; // [8] 静态方法引用
            c.call("Bob");
    
            c = new Description("valueable")::help; // [9] 这是 [6] 的另一个版本:对已实例化对象的方法的引用,有时称为绑定方法引用。
            c.call("information");
    
            c = Helper::assist;  // [10] 获取静态内部类的方法引用的操作与 [8] 中外部类方式一样
            c.call("Help!");
        }
    }
    /*
    call()
    Hello,Bob
    valueable information
    Help!
     */
    
    

    3.1 Runnable接口

    package functional;
    
    class Go{
        static void go(){
            System.out.println("Go::go()");
        }
    }
    public class RunnableMethodReference {
        public static void main(String[] args) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("Anonymous");
                }
            }).start();
    
            new Thread(() -> System.out.println("lambda")).start();//Lambda 表达式
    
            new Thread(Go::go).start();//方法引用
        }
    }
    /*
    Anonymous
    lambda
    Go::go()
     */
    
    

    3.2 未绑定的方法引用

    未绑定的方法引用是指没有关联对象的普通(非静态)方法。 使用未绑定的引用之前,我们必须先提供对象

    package functional;
    
    class X {
        String f() {
            return "X::f()";
        }
    }
    
    interface MakeString {
        String make();
    }
    
    interface TransformX {
        // 使用未绑定的引用时,函数方法的签名(接口中的单个方法)不再与方法引用的签名完全匹配。
        // 理由是:你需要一个对象来调用方法。
        String transform(X x);
    }
    
    
    public class UnboundMethodReference {
        public static void main(String[] args) {
            // 即使 make() 与 f() 具有相同的签名,编译也会报“invalid method reference”(无效方法引用)错误。
            // 这是因为实际上还有另一个隐藏的参数:我们的老朋友 this。 你不能在没有 X 对象的前提下调用 f()。
            // 因此,X :: f 表示未绑定的方法引用,因为它尚未“绑定”到对象
    //        MakeString ms = X::f; // [1]
            TransformX sp = X::f;
            X x =new X();
            System.out.println(sp.transform(x));// [2] [2] 的结果有点像脑筋急转弯。 我接受未绑定的引用并对其调用 transform(),将其传递给 X,并以某种方式导致对 x.f() 的调用。 Java 知道它必须采用第一个参数,这实际上就是 this,并在其上调用方法。
            System.out.println(x.f());// 同等效果
        }
    }
    /*
    X::f()
    X::f()
     */
    
    

    未绑定的方法与多参数的结合运用

    package functional;
    
    class This {
        void two(int i, double d) {
        }
    
        void three(int i, double d, String s) {
        }
    
        void four(int i, double d, String s, char c) {
        }
    }
    
    interface TwoArgs {
        void call2(This athis, int i, double d);
    }
    
    interface ThreeArgs {
        void call3(This athis,int i,double d, String s);
    }
    
    interface FourArgs{
        void call4(This athis,int i,double d,String s, char c);
    }
    
    public class MultiUnbound {
        public static void main(String[] args) {
            TwoArgs twoArgs = This::two;
            ThreeArgs threeArgs = This::three;
            FourArgs fourArgs = This::four;
            This athis = new This();
            twoArgs.call2(athis,11,3.14);
            threeArgs.call3(athis,11,3.14,"Three");
            fourArgs.call4(athis,11,3.14,"Four",'Z');
        }
    }
    
    

    3.2 构造函数引用

    package functional;
    
    class Dog {
        String name;
        int age = -1; // For "unknown"
    
        Dog() {
            name = "stray";
        }
    
        Dog(String nm) {
            name = nm;
        }
    
        Dog(String nm, int yrs) {
            name = nm;
            age = yrs;
        }
    }
    
    interface MakeNoArgs {
        Dog make();
    }
    
    interface Make1Arg {
        Dog make(String nm);
    }
    
    interface Make2Args {
        Dog make(String nm, int age);
    }
    
    public class CtorReference {
        public static void main(String[] args) {
            MakeNoArgs mna = Dog::new;// [1]
            Make1Arg m1a = Dog::new;// [2]
            Make2Args m2a = Dog::new;// [3]
    
            Dog dn = mna.make();
            Dog d1 = m1a.make("Comet");
            Dog d2 = m2a.make("Ralph",4);
        }
    }
    //我们如何对 [1],[2] 和 [3] 中的每一个使用 Dog :: new。 这 3 个构造函数只有一个相同名称::: new,但在每种情况下都赋值给不同的接口。编译器可以检测并知道从哪个构造函数引用。
    //
    //编译器能识别并调用你的构造函数( 在本例中为 make())。
    
    

    4 函数式接口

    每个接口只包含一个抽象方法,称为函数式方法。

    package functional;
    
    @FunctionalInterface
    interface Functional{
        String goodbye(String arg);
    }
    
    interface FunctionalNoAnn{
        String goodbye(String arg);
    }
    
    /*
    @FunctionalInterface
    interface NotFunctional{
        String goodbye(String arg);
        String hello(String arg);
    }
    产生错误信息:
            NotFunctional is not a functional interface
    multiple non-overriding abstract methods
            found in interface NotFunctional
    */
    
    public class FunctionalAnnotation {
        public String goodbye(String arg){
            return "Goodbye, " + arg;
        }
    
        public static void main(String[] args) {
            FunctionalAnnotation fa = new FunctionalAnnotation();
            // Java 8 在这里添加了一点小魔法:
            // 如果将方法引用或 Lambda 表达式赋值给函数式接口(类型需要匹配),
            // Java 会适配你的赋值到目标接口。
            // 编译器会自动包装方法引用或 Lambda 表达式到实现目标接口的类的实例中。
            Functional f = fa::goodbye;
            FunctionalNoAnn fna = fa::goodbye;
    //        Functional fac = fa;// Incompatible
            Functional f1 = a -> "Goodbye, " + a;
            FunctionalNoAnn fnal = a -> "Goodbye, " + a;
        }
    }
    
    

    基本命名准则:

    如果只处理对象而非基本类型,名称则为 Function,Consumer,Predicate 等。参数类型通过泛型添加。

    如果接收的参数是基本类型,则由名称的第一部分表示,如 LongConsumer,DoubleFunction,IntPredicate 等,但基本 Supplier 类型例外。

    如果返回值为基本类型,则用 To 表示,如 ToLongFunction 和 IntToLongFunction。

    如果返回值类型与参数类型一致,则是一个运算符:单个参数使用 UnaryOperator,两个参数使用 BinaryOperator。

    如果接收两个参数且返回值为布尔值,则是一个谓词(Predicate)。

    如果接收的两个参数类型不同,则名称中有一个 Bi。

    下面枚举了基于 Lambda 表达式的所有不同 Function 变体的示例

    package functional;
    
    import java.util.function.*;
    
    class Foo{}
    
    class Bar{
        Foo f;
        Bar(Foo f){this.f = f;}
    }
    
    class IBaz{
        int i;
        IBaz(int i){
            this.i = i;
        }
    }
    
    class LBaz{
        long l;
        LBaz(long l){
            this.l = l;
        }
    }
    class DBaz{
        double d;
        DBaz(double d){
            this.d = d;
        }
    }
    public class FunctionVariants {
        static Function<Foo,Bar> f1 = f -> new Bar(f);
        static IntFunction<IBaz> f2 = i -> new IBaz(i);
        static LongFunction<LBaz> f3 = l ->new LBaz(l);
        static DoubleFunction<DBaz> f4 = d -> new DBaz(d);
        static ToIntFunction<IBaz> f5 = ib -> ib.i;
        static ToLongFunction<LBaz> f6 = lb -> lb.l;
        static ToDoubleFunction<DBaz> f7 = db -> db.d;
        static IntToLongFunction f8 = i -> i;
        static IntToDoubleFunction f9 = i -> i;
        static LongToIntFunction f10 = l -> (int)l;
        static LongToDoubleFunction f11 = l -> l;
        static DoubleToIntFunction f12 = d -> (int)d;
        static DoubleToLongFunction f13 = d -> (long)d;
    
        public static void main(String[] args) {
            Bar b = f1.apply(new Foo());
            IBaz ib = f2.apply(11);
            LBaz lb = f3.apply(11);
            DBaz db = f4.apply(11);
            int i = f5.applyAsInt(ib);
            long l = f6.applyAsLong(lb);
            double d = f7.applyAsDouble(db);
            l = f8.applyAsLong(12);
            d = f9.applyAsDouble(12);
            i = f10.applyAsInt(12);
            d = f11.applyAsDouble(12);
            i = f12.applyAsInt(13.0);
            l = f13.applyAsLong(13.0);
        }
    }
    
    

    方法引用

    package functional;
    
    import java.util.function.BiConsumer;
    
    class In1{}
    class In2{}
    
    public class MethodConversion {
        static void accept(In1 i1,In2 i2){ // 只要参数类型、返回类型与 BiConsumer 的 accept() 相同即可。
            System.out.println("accept()");
        }
        static void someOtherName(In1 i1,In2 i2){ //只要参数类型、返回类型与 BiConsumer 的 accept() 相同即可。
            System.out.println("someOtherName()");
        }
    
        public static void main(String[] args) {
            BiConsumer<In1,In2> bic;
    
            bic = MethodConversion::accept;
            bic.accept(new In1(),new In2());
    
            bic = MethodConversion::someOtherName;
            bic.accept(new In1(),new In2());
        }
    }
    /*
    accept()
    someOtherName()
     */
    
    

    基于类的函数式,应用于方法引用

    创建最简单的函数式签名

    package functional;
    
    import java.util.Comparator;
    import java.util.function.*;
    
    class AA{}
    class BB{}
    class CC{}
    
    public class ClassFunctionals {
        static AA f1(){return new AA();}
        static int f2(AA aa1, AA aa2){ return 1;}
        static void f3(AA aa){}
        static void f4(AA aa, BB bb){}
        static CC f5(AA aa){return new CC();}
        static CC f6(AA aa, BB bb){return new CC();}
        static boolean f7(AA aa){return true;}
        static boolean f8(AA aa, BB bb){return true;}
        static AA f9(AA aa){return new AA();}
        static AA f10(AA aa1,AA aa2){return new AA();}
    
        public static void main(String[] args) {
            Supplier<AA> s = ClassFunctionals::f1;
            s.get();
            Comparator<AA> c = ClassFunctionals::f2;
            c.compare(new AA(),new AA());
            Consumer<AA> cons = ClassFunctionals::f3;
            cons.accept(new AA());
            BiConsumer<AA,BB> bicons = ClassFunctionals::f4;
            bicons.accept(new AA(),new BB());
            Function<AA,CC> f = ClassFunctionals::f5;
            CC cc = f.apply(new AA());
            BiFunction<AA,BB,CC> bif = ClassFunctionals::f6;
            cc = bif.apply(new AA(),new BB());
            Predicate<AA> p = ClassFunctionals::f7;
            boolean result = p.test(new AA());
            BiPredicate<AA,BB> bip = ClassFunctionals::f8;
            result = bip.test(new AA(),new BB());
            UnaryOperator<AA> uo = ClassFunctionals::f9;
            AA aa = uo.apply(new AA());
            BinaryOperator<AA> bo = ClassFunctionals::f10;
            aa = bo.apply(new AA(),new AA());
        }
    }
    
    

    4.1 多参数函数式接口

    package functional;
    
    @FunctionalInterface
    public interface TriFunction<T,U,V,R> {
        R apply(T t, U u, V v);
    }
    

    验证 测试了方法引用和 Lambda 表达式

    package functional;
    
    public class TriFunctionTest {
        static int f(int i,long l,double d){return 99;}
    
        public static void main(String[] args) {
            TriFunction<Integer,Long,Double,Integer> tf = TriFunctionTest::f;
            tf = (i,l,d) -> 12;
        }
    }
    
    

    4.2 缺少基本类型的函数

    package functional;
    
    import java.util.function.BiConsumer;
    
    public class BitConsumerPermutations {
        static BiConsumer<Integer,Double> bicid =(i,d) -> System.out.printf("%d, %f%n",i,d); // %n 跨平台
        static BiConsumer<Double,Integer> bicdi = (d,i) -> System.out.printf("%d, %f%n",i,d);
        static BiConsumer<Integer,Long> bicil = (i,  l) -> System.out.printf("%d, %d%n",i,l);
    
        public static void main(String[] args) {
            bicid.accept(47,11.34);
            bicdi.accept(22.45,92);
            bicil.accept(1,11L);
        }
    }
    /*
    47, 11.340000
    92, 22.450000
    1, 11
     */
    
    
    package functional;
    
    import java.util.function.Function;
    import java.util.function.IntToDoubleFunction;
    
    public class FunctionWithWrapped {
        public static void main(String[] args) {
    //        Function<Integer,Double> fid = i -> i; // Integer cannot be converted to Double
            Function<Integer,Double> fid = i -> (double)i;
            IntToDoubleFunction fid2 = i -> i;
        }
    }
    

    5 高阶函数

    高阶函数(Higher-order Function)只是一个消费或产生函数的函数。

    产生函数
    
    package functional;
    
    import java.util.function.Function;
    
    interface FuncSS extends Function<String,String> {} // [1] 继承
    
    public class ProduceFunction {
        static FuncSS produce(){
            return s -> s.toLowerCase(); // [2] lambda表达式
        }
    
        public static void main(String[] args) {
            FuncSS f = produce();
            System.out.println(f.apply("YELLING"));
        }
    }
    
    

    消费函数

    package functional;
    
    import java.util.function.Function;
    
    class One{}
    class Two{}
    
    public class ConsumeFunction {
        static Two consume(Function<One,Two> onetwo){
            return onetwo.apply(new One());
        }
    
        public static void main(String[] args) {
            Two two = consume(one -> new Two());
        }
    }
    
    
    package functional;
    
    import java.util.function.Function;
    
    class I {
        public I(){
            System.out.println("Create I");
        }
        @Override
        public String toString(){
            return "I";
        }
    }
    
    class O{
        public O(){
            System.out.println("Create O");
        }
        @Override
        public String toString(){
            return "O";
        }
    }
    public class TransformFunction {
        static Function<I,O> transform(Function<I,O> in){
            System.out.println("2");
            return in.andThen(o -> {
                System.out.println(o);
                return o;
            });
        }
    
        public static void main(String[] args) {
            System.out.println("1");
            Function<I,O> f2 = transform(i -> {
                System.out.println("lalla");
                System.out.println(i);
                return new O();
            });
            System.out.println("3");
            O o = f2.apply(new I());
        }
    }
    /*
    1
    2
    3
    Create I
    lalla
    I
    Create O
     */
    
    

    6 闭包

    6.1 作为闭包的内部类

    使用匿名内部类重写之前的例子

    package functional;
    
    import java.util.function.IntSupplier;
    
    public class AnonymousClosure {
        IntSupplier makeFun(int x){
            int i = 0;
            // 同样规则的应用:
            // i++; // 非等同 final 效果
            // x++; // 同上
            return new IntSupplier() {
                @Override
                public int getAsInt() {
                    return x + i ;
                }
            };
        }
    }
    
    

    7 函数组合

    package functional;
    
    import java.util.function.Function;
    
    public class FunctionComposition {
        static Function<String,String> f1 = s -> {
            System.out.println(s);
            return s.replace('A','_');
        },
        f2 = s -> s.substring(3),
        f3 = s -> s.toLowerCase(),
        f4 = f1.compose(f2).andThen(f3); // 创建的新函数 f4。它调用 apply() 的方式与常规几乎无异.
       // 当 f1 获得字符串时,它已经被f2 剥离了前三个字符。这是因为 compose(f2) 表示 f2 的调用发生在 f1 之前。
    
        public static void main(String[] args) {
            System.out.println(f4.apply("GO AFTER ALL AMBULANCES"));
        }
    }
    /*
    AFTER ALL AMBULANCES
    _fter _ll _mbul_nces
     */
    
    
    package functional;
    
    import java.util.function.Predicate;
    import java.util.stream.Stream;
    
    public class PredicateComposition {
        static Predicate<String>
                p1 = s -> s.contains("bar"),
        p2 = s -> s.length() < 5,
        p3 = s -> s.contains("foo"),
        p4 = p1.negate().and(p2).or(p3);
    
        public static void main(String[] args) {
            Stream.of("bar","foobar","foobaz","fongopuckey")
                    .filter(p4)
                    .forEach(System.out::println);
        }
    }
    /*
    foobar
    foobaz
     */
    

    8 柯里化和部分求值

    柯里化(Currying)名称来自于其发明者之一 Haskell Curry

    将一个多参数的函数,转换为一系列单参数函数。

    package functional;
    
    import java.util.function.Function;
    
    public class CurryingAndPartials {
        // 未柯里化
        static String uncurried(String a,String b){
            return a + b;
        }
    
        public static void main(String[] args) {
            // 柯里化的函数
            Function<String,Function<String,String>> sum = a -> b -> a + b; //[1] 这一连串的箭头很巧妙。注意,在函数接口声明中,第二个参数是另一个函数。
    
            System.out.println(uncurried("Hi","Ho"));
    
            Function<String,String> hi = sum.apply("Hi"); // [2]柯里化的目的是能够通过提供一个参数来创建一个新函数,所以现在有了一个“带参函数”和剩下的 “无参函数” 。实际上,你从一个双参数函数开始,最后得到一个单参数函数。
            System.out.println(hi.apply("Ho"));
    
            //部分应用:
            Function<String,String> sumHi = sum.apply("Hup ");
            System.out.println(sumHi.apply("Ho"));
            System.out.println(sumHi.apply("Hey"));
        }
    }
    /*HiHo
    HiHo
    Hup Ho
    Hup Hey
     */
    
    

    通过添加级别来柯里化一个三参数函数

    package functional;
    
    import java.util.function.Function;
    
    public class Curry3Args {
        public static void main(String[] args) {
            Function<String,
                    Function<String,
                            Function<String,String>>> sum =
                    a -> b -> c -> a + b + c;
            Function<String,
                    Function<String,String>> hi = sum.apply("Hi ");
            Function<String,String> ho = hi.apply("Ho ");
            System.out.println(ho.apply("Hup"));
        }
    }
    /*
    对于每个级别的箭头级联(Arrow-cascading),你在类型声明中包裹了另一个 Function。
    Hi Ho Hup
     */
    
    

    处理基本类型和装箱时,请使用适当的 Function 接口

    package functional;
    
    import java.util.function.IntFunction;
    import java.util.function.IntUnaryOperator;
    
    public class CurriedIntAdd {
        public static void main(String[] args) {
            IntFunction<IntUnaryOperator> curriedIntAdd = a -> b -> a + b;
            IntUnaryOperator add4 = curriedIntAdd.apply(4);
            System.out.println(add4.applyAsInt(5));
        }
    }
    

    9 纯函数式编程

    要确保一切是 final 的,同时你的所有方法和函数没有副作用。因为 Java 在本质上并非是不可变语言,我们无法通过编译器查错。

    10 本章小结

  • 相关阅读:
    highcharts绘制股票k线
    利用meta标签将http请求换成https请求
    path.join 与 path.resolve 的区别
    【转】弧度和角度的转换
    块级元素和行内元素的区别 (block vs. inline)
    ubuntu下安装Apache + PHP + Mysql
    [读书笔记] CSS权威指南2: 结构和层叠
    [读书笔记] CSS权威指南1: 选择器
    [读书笔记] Head First 设计模式
    深入浅出React Native 3: 从零开始写一个Hello World
  • 原文地址:https://www.cnblogs.com/erinchen/p/12310374.html
Copyright © 2011-2022 走看看