1. 程式人生 > >菜雞的Java筆記 第三十六 StudyLambda

菜雞的Java筆記 第三十六 StudyLambda

StudyLambda
    Lambda 指的是函數語言程式設計,現在最為流行的程式設計模式為面向物件,很多的開發者並不認可面向物件,所以很多的開發者寧願繼續使用 C 語言進行開發,也不願意使用java,c++
    但是隨著整個行業的技術發展,函式程式語言已經開始被很多的人所認可,於是java也是被迫環境因素追加了 Lambda
    如果要想去理解 Lambda 表示式設定的背景,就需要首先理解匿名內部類
    匿名內部類解決的問題:對於抽象類或介面的子類如果發現其只使用一次,那麼就沒有必要將其定義為一個類,這樣可以節約類的定義空間,但是匿名內部類太麻煩了
    
    範例:觀察匿名內部類

package cn.mysterious;
interface IMessage{
    public String getMsg();
    
}

public class Lang0 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        IMessage msg = new IMessage() {
            
            @Override
            public String getMsg() {
                
// TODO Auto-generated method stub return "ssssssssssssssss"; } }; System.out.println(msg.getMsg()); } }

           
            因為面向物件的最大特徵:結構要完整,這個時候如果使用 Lambda 表示式呢?
            

package cn.mysterious;
interface IMessage{
    public String getMsg();
    
}

public class Lang0 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        IMessage msg = () ->"?????????";
        System.out.println(msg.getMsg());
    }
}

           
            一個簡單的一行語句就代替了完整的結構,那麼自然會有許多的追捧者去使用它
            實際上 Lambda 表示式以上的做法只是其中的一種形式,它有三種語法:
                () ->{多行語句,return 語句};
                () ->單行語句;
                () ->返回結果;
                
            範例:多行語句定義

package cn.mysterious;
interface IMessage{
    public String getMsg();
    
}

public class Lang0 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        IMessage msg = () ->{
            String str = "???????";
            return str;
        };
        System.out.println(msg.getMsg());
    }

}                

               
                如果現在設計的接口裡面沒有返回值的存在,那麼方法體也可以使用一行語句,可以直接避免“{}”定義

package cn.mysterious;
interface IMessage{
    public void print();
    
}

public class Lang0 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        IMessage msg = () -> System.out.println("???????????");;
        msg.print();
    }

}

               
            如果要想使用 Lambda 表示式有一個重要的前提:一個介面之中只允許有一個抽象方法,如果你現在需要強制描述介面定義(某一個介面就是函數語言程式設計介面)則可以追加一個註解

package cn.mysterious;
@FunctionalInterface // 是函式式介面,只允許有一個抽象方法
interface IMessage{
    public void print();
    
}
public class Lang0 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        IMessage msg = () -> System.out.println("???????????");;
        msg.print();
    }

}

               
                Lambda 是基於函式式介面定義的,如果要想使用 Lambda  重要的前提:一個介面之中只允許有一個抽象方法
                
            如果有很多抽象方法呢?

package cn.mysterious;
@FunctionalInterface // 是函式式介面,只允許有一個抽象方法
interface IMessage{
    public void print();
    public default void fun(){}
    
}
public class Lang0 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        IMessage msg = () -> System.out.println("???????????");;
        msg.print();
        msg.fun();
    }

}


*/

/*    
    在之前所學習的都屬於物件的引用,物件引用的本質在於:同一塊堆記憶體空間,可以被不同的棧記憶體所指向
    那麼方法的引用指的是一個方法可以設定不同的別名,即:可以被不同的介面的物件所使用
    對於方法的引用在java裡面提供有四種處理形式:
        引用類中的靜態方法:類名稱 :: static 方法名稱
        引用某個物件的方法;例項化物件 :: 普通方法
        引用某個特定的方法:類名稱 :: 普通方法
        引用構造方法:類名稱 :: 普通方法
        
    範例:引用靜態方法
        String 類有一個 valueOf() 方法,該方法可以將接收到的基本資料型別變為字串
            方法定義: public static String valueOf(資料型別 變數);
            

package cn.mysterious;
/**
 * 進行以函式式介面定義
 * @author mldn
 * @param <P> 引用方法的引數型別
 * @param <R> 引用方法的返回值定義
 */
@FunctionalInterface // 是函式式介面,只允許有一個抽象方法
interface IUtile<P,R>{
    public R convert(P p); // 做新的方法
    
}
public class Lang0 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        IUtile<Integer,String> objA = String :: valueOf; // 方法引用
        System.out.println(objA.convert(100));
    }

}

           
        也可以使用 Integer,parseInt() 轉換
            

package cn.mysterious;
public class Lang0 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        IUtil<Integer,String> objA =  String :: valueOf; // 方法引用
        System.out.println(fun(objA,100).length());
    }
    public static <P,R> R fun(IUtil<P,R> temp,P p){
        return temp.convert(p);
    }

}
/**
 * 進行以函式式介面定義
 * @author mldn
 * @param <P> 引用方法的引數型別
 * @param <R> 引用方法的返回值定義
 */
@FunctionalInterface // 是函式式介面,只允許有一個抽象方法
interface IUtil<P,R>{
    public R convert(P p); // 做新的方法
    
}

           
        以上只是引用了一個簡單的 static 方法,也可以直接引用某一個類中的方法
        
        範例:引用 String 類中的字串轉大寫方法
            [“字串”.toUpperCase] public String toUpperCase();

package cn.mysterious;

@FunctionalInterface // 是函式式介面,只允許有一個抽象方法
interface IUtil<R>{
    public R upper(); // 做新的方法
    
}
public class Lang0 {

    public static void main(String[] args) {
        IUtil<String> obj = "hello" :: toUpperCase;
        System.out.println(obj.upper());
    }
}

           
        範例:引用類中的普通方法
            String 類有一個 compareTo() 方法,這個方法是一個普通方法,而且需要兩個引數比較
                方法: public int compareTo(String str);

package cn.mysterious;

@FunctionalInterface // 是函式式介面,只允許有一個抽象方法
interface IUtil<R,P>{
    public R compare(P p1,P p2); // 做新的方法
    
}
public class Lang0 {

    public static void main(String[] args) {
        IUtil<Integer,String> obj = String :: compareTo;
        System.out.println(obj.compare("A","a"));
    }
}

               
            以上使用的都是類的結構,而整個設計裡面最大的亮點在於構造方法也可以設定別名引用
            
        範例:引用構造方法

package cn.mysterious;
@FunctionalInterface // 是函式式介面,只允許有一個抽象方法
interface IUtil<R,FP,SP>{
    public R create(FP p1,SP p2); // 做新的方法

    
}
public class Lang0 {

    public static void main(String[] args) {
        IUtil<Member,String,Integer> obj = Member :: new; // 引用構造
        System.out.println(obj.create("????",20));
    }

}
class Member{
    private String name;
    private int age;
    public Member(String name,int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Member [name=" + name + ", age=" + age + "]";
    }
}

           
            Lambda 表示式的操作除了可以自定義方法體之外,使用者也可以去引用已經實現好的類中的方法
            
    
    內建函式式介面
        函式式介面是 Lambda 實現關鍵所在,但是很多時候如果要想進行一個專案設計的時候,肯定需要許多標準的函式式介面
        所以在java設計過程之中考慮到使用者使用標準型問題,所以也提供有四個內建的函式式介面
            功能性函式介面: public Interface Function<T,R>{R apply(T t)}
            消費型函式介面: public interface Consumer<T>{public void accept(T t)}
            供給性函式介面: public interface Supplier<T>{public T get()}
            斷言型函式介面: public interface Predicate<T>{public boolean test(T t)}
            
        範例:使用功能型介面

    package cn.mysterious;

    import java.util.function.Function;

    public class Lang0 {

        public static void main(String[] args) {
            Function<Integer,String> obj = String :: valueOf;
            System.out.println(obj.apply(100));
        }

    }

           
        實際上在 java.util.function 開發包裡面有許多擴充套件的函式式介面,可以幫助使用者簡化定義
        
        範例:使用 IntFunction

    package cn.mysterious;

    import java.util.function.IntFunction;
    public class Lang0 {

        public static void main(String[] args) {
            IntFunction<String> obj = String :: valueOf;
            System.out.println(obj.apply(100));
        }

    }

           
        範例:消費型介面,現在學習到的消費處理只有一個方法:列印輸出

    package cn.mysterious;

    import java.util.function.Consumer;
    import java.util.function.IntFunction;
    public class Lang0 {

        public static void main(String[] args) {
            Consumer<String> obj = System.out :: println;
            obj.accept("?????");
        }

    }

           
        範例:供給型,字串轉大寫或小寫(“Hello” .toLowerCase())

    package cn.mysterious;

    import java.util.function.Supplier;

    public class Lang0 {

        public static void main(String[] args) {
            Supplier<String> obj = "Hello" :: toLowerCase;
            System.out.println(obj.get());

        }

    }

           
        範例:斷言型介面( startsWith() 方法,返回boolean,接收一個字串)

    package cn.mysterious;

    import java.util.function.Predicate;

    public class Lang0 {

        public static void main(String[] args) {
            Predicate<String> obj = "##hello" :: startsWith;
            System.out.println(obj.test("##"));
        }

    }

           
            如果不去考慮標準,這些介面完全可以自己來實現,而這四個介面是 java 中進行 Lambda 程式設計時所採用的標準介面