Chapter XIII on java 8 Functional Programming

Functional programming central idea: the function is passed as a parameter to another function, or to function as a return value.

Limited only to suit the program memory, the programmer saves code space by modifying the code in memory, to perform different operations at the time of program execution. This technique is referred to as self-modifying code (self-modifying code)

OO (object oriented, object-oriented) are abstract data,

FP (functional programming, functional programming) is an abstract behavior

Pure functional language even further in terms of safety. It imposes additional constraints that all data must be immutable: once set, will never change.

"Immutable objects and no side effects" paradigm to solve the most fundamental and most difficult problems one concurrent programming

Therefore, often put forward as a pure functional languages ​​for parallel programming solutions (there are other possible solutions).

1 contrast old and new

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 Expressions

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 Recursion

Recursive method must be an instance or static variable, or a compile-time error occurs.

package functional;

interface IntCall{
    int call(int arg);
}

Factorial function

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 method references

Java 8 method cited no historical baggage. Method references: a class name or an object name followed by :: and then follow the method name.

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 Interface

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 reference method unbound

Unbound method reference is to the ordinary (non-static) method is not associated with the object. Before using unbound references, we must provide an object

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()
 */

Unbound method combined with the use of multi-parameter

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 Constructors references

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 Functional Interface

Each interface contains only an abstract method, referred to as functional method.

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;
    }
}

Basic naming guidelines:

If you only deal with objects instead of primitive types, the name was Function, Consumer, Predicate and so on. Add the parameter type by generics.

If the received parameters are the basic type, represented by the first part of the name, such as LongConsumer, DoubleFunction, IntPredicate the like, but the basic type Supplier exceptions.

If the return value is a primitive type represented by To as ToLongFunction And IntToLongFunction.

If the return value type is consistent with the parameter type, an operator is: UnaryOperator using a single parameter, two parameters BinaryOperator.

If the received two parameters and returns a Boolean value, is a predicate (Predicate).

If two different type of the received parameter, the name of a Bi.

The following examples are enumerated based on all the different variants of Function Lambda expression of

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);
    }
}

Method references

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()
 */

Based functional class, the method is applied to a reference

Create a simple function signature

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());
    }
}

More than 4.1 function interface parameters

package functional;

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

Verification testing methods and Lambda expressions references

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 lack basic types of functions

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 functions

Higher-order functions (Higher-order Function) is just a function of consumption or generation 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"));
    }
}

Consumption Function

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 Closure

6.1 as an internal type closure

Before using the example of anonymous inner class overrides

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 function composition

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 Currie and partial evaluation

Currying (Currying) from its name one of the inventors Haskell Curry

The function of more than one parameter, the parameter is converted to a series of single function.

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
 */

By adding to the level of a three-parameter function currying

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
 */

Basic processing and packing type, use the appropriate Interface 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 purely functional programming

To make sure everything is final, but all of your methods and functions without side effects. Because Java, in essence, is not immutable language, we are unable to troubleshooting by the compiler.

10 Summary

Guess you like

Origin www.cnblogs.com/erinchen/p/12310374.html