【前言】 java8新特性html
java8中一個很是重要的特性就是lambda表達式,咱們能夠把它當作是一種閉包,它容許把函數當作參數來使用,是面向函數式編程的思想,必定程度上可使代碼看起來更加簡潔。例如之前咱們使用匿名內部類來實現代碼:java
//匿名內部類寫法 new Thread(new Runnable() { @Override public void run() { System.out.println("內部類寫法"); } }).start();
使用lambda則更加簡潔:git
//lambda 寫法 new Thread(() -> System.out.println("lambda寫法")).start();
(paramters) -> expression;
或者github
(paramters) -> {statements;} 展開如: (Type1 param1, Type2 param2, Type2 param2, ...) -> { statement1; statement2; statement3; ... return statementX; }
示例:express
//入參爲空 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.1 對象::實例方法,將lambda的參數當作方法的參數使用閉包
objectName::instanceMethod
示例:app
Consumer<String> sc = System.out::println; //等效 Consumer<String> sc2 = (x) -> System.out.println(x); sc.accept("618, 狂歡happy");
3.2 類::靜態方法,將lambda的參數當作方法的參數使用編程語言
ClassName::staticMethod
示例:ide
//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");
無參的構造方法就是類::實例方法模型,如:
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");
接口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方法。
java8引入lambda表達式是接收了函數式編程語言的思想,例如scala之類的,它將函數視爲一等公民,可使用高階函數等。
和指令式編程相比,函數式編程強調函數的計算比指令的執行重要。