菜雞的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 程式設計時所採用的標準介面