【前言】 java8新特性
java8 函數接口
java8 Optional使用總結
Java 8 時間日期使用
java8中一個非常重要的特性就是lambda表達式,我們可以把它看成是一種閉包,它允許把函數當做參數來使用,是面向函數式編程的思想,一定程度上可以使代碼看起來更加簡潔。例如以前我們使用匿名內部類來實現代碼:
//匿名內部類寫法 new Thread(new Runnable() { @Override public void run() { System.out.println("內部類寫法"); } }).start();
使用lambda則更加簡潔:
//lambda 寫法 new Thread(() -> System.out.println("lambda寫法")).start();
1、lambda表達式語法
(paramters) -> expression;
或者
(paramters) -> {statements;} 展開如: (Type1 param1, Type2 param2, Type2 param2, ...) -> { statement1; statement2; statement3; ... return statementX; }
2、lambda表達式特征
- 可選類型聲明:不需要聲明參數類型,編譯器可以統一識別參數值。
- 可選的參數圓括號:一個參數無需定義圓括號,但多個參數需要定義圓括號。
- 可選的大括號:如果主體包含了一個語句,就不需要使用大括號。
- 可選的返回關鍵字:如果主體只有一個表達式返回值則編譯器會自動返回值,大括號需要指定明表達式返回了一個數值。
示例:
//入參為空 TestDemo no_param = () -> "hi, no param"; TestDemo no_param2 = () -> { return "hi, no param"; }; System.out.println(no_param.hi()); //單個參數 TestDemo2 param = name -> name; TestDemo2 param2 = name -> { return name;}; System.out.println(param.hei("hei, grils")); //多個參數 TestDemo3 multiple = (String hello, String name) -> hello + " " + name; //一條返回語句,可以省略大括號和return TestDemo3 multiple2 = (hello, name) -> hello + name; //多條處理語句,需要大括號和return TestDemo3 multiple3 = (hello, name) -> { System.out.println("進入內部"); return hello + name; }; System.out.println(multiple.greet("hello", "lambda"));
3、方法引用
有以下幾種類型
3.1 對象::實例方法,將lambda的參數當做方法的參數使用
objectName::instanceMethod
示例:
Consumer<String> sc = System.out::println; //等效 Consumer<String> sc2 = (x) -> System.out.println(x); sc.accept("618, 狂歡happy");
3.2 類::靜態方法,將lambda的參數當做方法的參數使用
ClassName::staticMethod
示例:
//ClassName::staticMethod 類的靜態方法:把表達式的參數值作為staticMethod方法的參數 Function<Integer, String> sf = String::valueOf; //等效 Function<Integer, String> sf2 = (x) -> String.valueOf(x); String apply1 = sf.apply(61888);
3.3 類::實例方法,將lambda的第一個參數當做方法的調用者,其他的參數作為方法的參數。開發中盡量少些此類寫法,減少后續維護成本。
ClassName::instanceMethod
示例:
//ClassName::instanceMethod 類的實例方法:把表達式的第一個參數當成instanceMethod的調用者,其他參數作為該方法的參數 BiPredicate<String, String> sbp = String::equals; //等效 BiPredicate<String, String> sbp2 = (x, y) -> x.equals(y); boolean test = sbp.test("a", "A");
4、構造函數
無參的構造方法就是類::實例方法模型,如:
Supplier<User> us = User::new; //等效 Supplier<User> us2 = () -> new User(); //獲取對象 User user = us.get();
當有參數時:
//一個參數,參數類型不同則會編譯出錯 Function<Integer, User> uf = id -> new User(id); //或加括號 Function<Integer, User> uf2 = (id) -> new User(id); //等效 Function<Integer, User> uf3 = (Integer id) -> new User(id); User apply = uf.apply(61888); //兩個參數 BiFunction<Integer, String, User> ubf = (id, name) -> new User(id, name); User 狂歡happy = ubf.apply(618, "狂歡happy");
5、繼承及實現具有相同默認方法的父類或接口問題
接口A:
public interface A { String hi(); String greet(); default void hello() { System.out.println("A.hello"); } }
接口B:
public interface B { String hi(); String hh(); default void hello() { System.out.println("B.hello"); } }
類C實現A,B:
public class C implements A, B{ @Override public String hi() { return "C.hi"; } @Override public String greet() { return "C.greet"; } @Override public String hh() { return "C.hh"; } /** * 子類優先繼承父類的方法, 如果父類沒有相同簽名的方法,才繼承接口的默認方法。 * 編譯報錯解決1:覆蓋法 */ @Override public void hello() { System.out.println("C.hello"); } /** * 編譯報錯解決2:指定實現的父接口 */ // @Override // public void hello() { // A.super.hello(); //// B.super.hello(); // } }
此時若不處理hello方法時,類C將編譯出錯,解決方式要么覆蓋,要么指定實現父接口的該方法。
進一步測試繼承具有相同方法的父類:
類D:
public class D { public void hello() { System.out.println("D.hello"); } }
類C繼承類D:
public class C extends D implements A, B{ @Override public String hi() { return "C.hi"; } @Override public String greet() { return "C.greet"; } @Override public String hh() { return "C.hh"; } /** * 子類優先繼承父類的方法, 如果父類沒有相同簽名的方法,才繼承接口的默認方法。 * 編譯報錯解決1:覆蓋法 */ // @Override // public void hello() { // System.out.println("C.hello"); // } /** * 編譯報錯解決2:指定實現的父接口 */ // @Override // public void hello() { // A.super.hello(); //// B.super.hello(); // } }
此時若不覆蓋或指定父接口的方法時,類C將繼承類D的hello方法。
6、總結
java8引入lambda表達式是接收了函數式編程語言的思想,例如scala之類的,它將函數視為一等公民,可以使用高階函數等。
和指令式編程相比,函數式編程強調函數的計算比指令的執行重要。
和過程化編程相比,函數式編程里函數的計算可隨時調用。
寫在最后,lambda表達式可以使代碼看起來簡潔,但一定程度上增加了代碼的可讀性以及調試的復雜性,所以在使用時應盡量是團隊都熟悉使用,要么干脆就別用,不然維護起來是件較痛苦的事。
源碼參照Github