最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java8如何使用Lambda表達式簡化代碼詳解

 更新時間:2020年11月13日 11:05:06   作者:超級小豆丁  
這篇文章主要給大家介紹了關于Java8如何使用Lambda表達式簡化的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

系統(tǒng)環(huán)境:

  • Java JDK 版本:1.8

參考地址:

一、Lambda 表達式簡介

1、什么是 Lambda 表達式

       Lambda 表達式是在 JDK 8 中引入的一個新特性,可用于取代大部分的匿名內部類。使用 Lambda 表達式可以完成用少量的代碼實現復雜的功能,極大的簡化代碼代碼量和代碼結構。同時,JDK 中也增加了大量的內置函數式接口供我們使用,使得在使用 Lambda 表達式時更加簡單、高效。

2、為什么需要 Lambda 表達式

       談起為什么需要 Lambda 表達式,那得從函數式編程開始說起。函數式編程可以簡單說是一種編程規(guī)范,也就是如何編寫程序的方法論。它屬于結構化編程的一種,主要思想是把運算過程盡量寫成一系列嵌套的函數調用。函數式編程有很多優(yōu)點,其中包括:

  • 易于并發(fā)編程;
  • 代碼的熱升級;
  • 更方便的代碼管理;
  • 代碼簡潔,開發(fā)快速;
  • 接近自然語言,易于理解;

函數式編程在 C#、Python、JavaScript中都得到充分體現,在 Java 8 版本中也得到了支持。最明顯的就是對 Lambda 表達式的支持。很多種跡象表明未來編程語言將是逐漸融合各自的特性,而不是單純的聲明式語言函數編程語言。將來聲明式編程語言借鑒函數編程思想,函數編程語言融合聲明式編程特性,這幾乎是一種必然趨勢。

       在 Java 中主要引入 Lambda 表達式的作用是對現有編碼語義的優(yōu)化,減少語法冗余。輕量級的將代碼封裝為數據,使代碼簡潔,易于理解。

二、函數式接口和定義

1、什么是函數式接口

       函數式接口(Functional Interface)是一個有且僅有一個抽象方法,但是可以有多個非抽象方法的接口。Java 中函數式接口被隱式轉換為 Lambda 表達式,只有保證接口類中有且只有一個抽象方法,Java 中的 Lambda 表達式才能對該方法進行推導。

2、函數式接口格式

在 Java 函數式接口類中,需要滿足接口類中只能有一個抽象方法??偨Y如下:

  • 接口有且僅有一個抽象方法;
  • 允許定義靜態(tài)方法;
  • 允許定義默認方法;
  • 允許 java.lang.Object 中的 public 方法;

在創(chuàng)建函數式接口時,可以在接口類上面加上@FunctionalInterface注解,這時編譯器就可以對接口結構進行強制檢查是否符合函數式接口規(guī)則,如果不符合規(guī)則就顯示錯誤。當然,這個注解只是用于檢查,即使不加上該注解,只要符合函數式接口規(guī)則一樣也是函數式接口。

下面創(chuàng)建個演示的函數式接口,如下:

// @FunctionalInterface 注解說明: 
// 使用該注解來定義接口,編譯器會強制檢查接口是否符合函數式接口規(guī)則(有且僅有一個抽象方法),如果不符合則會報錯。
@FunctionalInterface
public interface MyInterface{
 /**
 * 抽象方法(Jdk 8 以后接口類中方法可以省去 public abstract)
 */
 public abstract [返回值類型] [方法名稱](參數列表);
 
 /**
 * 其它方法(Jdk 8 以后允許接口類中添加"默認方法"與"靜態(tài)方法" )
 */
 ...(略)
}

按照上面函數式接口,定義一個示例的函數式接口類,代碼如下:

@FunctionalInterface
public interface MyCollection {
 
 void push(List list);
 
}

3、函數式接口和 Lambda 表達式的關系

函數式接口和 Lambda 表達式的關系可以總結為:

  • 函數式接口只包含一個操作方法;
  • Lambda 表達式只能操作一個方法;
  • Java 中的 Lambda 表達式核心就是一個函數式編程接口的實現。

4、當前 JDK 8 中存在的函數式接口類

在 JDK 1.8 之前,已經存在部分函數式接口,如下:

  • java.lang.Runnable
  • java.util.concurrent.Callable
  • java.security.PrivilegedAction
  • java.util.Comparator
  • java.io.FileFilter
  • java.nio.file.PathMatcher
  • java.lang.reflect.InvocationHandler
  • java.beans.PropertyChangeListener
  • java.awt.event.ActionListener
  • javax.swing.event.ChangeListener

在 JDK 8 中新增了函數接口 java.util.function 包,里面包含了很多用來支持 Java 的函數式編程的接口類,如下:

類名稱 描述信息
BiConsumer<T,U> 代表了一個接受兩個輸入參數的操作,并且不返回任何結果。
BiFunction<T,U,R> 代表了一個接受兩個輸入參數的方法,并且返回一個結果。
BinaryOperator<T> 代表了一個作用于于兩個同類型操作符的操作,并且返回了操作符同類型的結果。
BiPredicate<T,U> 代表了一個兩個參數的 boolean 值方法。
BooleanSupplier 代表了 boolean 值結果的提供方。
Consumer<T> 代表了接受一個輸入參數并且無返回的操作。
DoubleBinaryOperator 代表了作用于兩個 double 值操作符的操作,并且返回了一個 double 值的結果。
DoubleConsumer 代表一個接受 double 值參數的操作,并且不返回結果。
DoubleFunction<R> 代表接受一個 double 值參數的方法,并且返回結果。
DoublePredicate 代表一個擁有 double 值參數的 boolean 值方法。
DoubleSupplier 代表一個 double 值結構的提供方。
DoubleToIntFunction 接受一個 double 類型輸入,返回一個 int 類型結果。
DoubleToLongFunction 接受一個 double 類型輸入,返回一個 long 類型結果。
DoubleUnaryOperator 接受一個參數同為類型 double,返回值類型也為 double。
Function<T,R> 接受一個輸入參數,返回一個結果。
IntBinaryOperator 接受兩個參數同為類型 int,返回值類型也為 int。
IntConsumer 接受一個 int 類型的輸入參數,無返回值。
IntFunction<R> 接受一個 int 類型輸入參數,返回一個結果。
IntPredicate 接受一個 int 輸入參數,返回一個布爾值的結果。
IntSupplier 無參數,返回一個 int 類型結果。
IntToDoubleFunction 接受一個 int 類型輸入,返回一個double類型結果。
IntToLongFunction 接受一個 int 類型輸入,返回一個 long 類型結果。
IntUnaryOperator 接受一個參數同為類型 int,返回值類型也為 int。
LongBinaryOperator 接受兩個參數同為類型 long,返回值類型也為 long。
LongConsumer 接受一個 long 類型的輸入參數,無返回值。
LongFunction<R> 接受一個 long 類型輸入參數,返回一個結果。
LongPredicate R接受一個 long 輸入參數,返回一個布爾值類型結果。
LongSupplier 無參數,返回一個結果 long 類型的值。
LongToDoubleFunction 接受一個 long 類型輸入,返回一個 double 類型結果。
LongToIntFunction 接受一個 long 類型輸入,返回一個 int 類型結果。
LongUnaryOperator 接受一個參數同為類型 long,返回值類型也為 long。
ObjDoubleConsumer<T> 接受一個 object 類型和一個 double 類型的輸入參數,無返回值。
ObjIntConsumer<T> 接受一個 object 類型和一個 int 類型的輸入參數,無返回值。
ObjLongConsumer<T> 接受一個 object 類型和一個 long 類型的輸入參數,無返回值。
Predicate<T> 接受一個輸入參數,返回一個布爾值結果。
Supplier<T> 無參數,返回一個結果。
ToDoubleBiFunction<T,U> 接受兩個輸入參數,返回一個 double 類型結果
ToDoubleFunction<T> 接受一個輸入參數,返回一個 double 類型結果。
ToIntBiFunction<T,U> 接受兩個輸入參數,返回一個 int 類型結果。
ToIntFunction<T> 接受一個輸入參數,返回一個 int 類型結果。
ToLongBiFunction<T,U> 接受兩個輸入參數,返回一個 long 類型結果。
ToLongFunction<T> 接受一個輸入參數,返回一個 long 類型結果。
UnaryOperator<T> 接受一個參數為類型 T,返回值類型也為 T。

5、JDK 中常見的函數式接口類

上面 java.util.function 包提供了眾多的函數式接口,其中常用的有:

  • java.util.function.Predicate<T>:接收參數對象 T,返回一個 boolean 類型結果。
  • java.util.function.Comsumer<T>:接收參數對象 T,不返回結果。
  • java.util.function.Function<T,R>:接收參數對象 T,返回結果對象 R。
  • java.util.function.Supplier<T>:不接收參數,提供 T 對象的創(chuàng)建工廠。
  • java.util.function.UnaryOperator<T>:接收參數對象 T,返回結果對象 T。
  • java.util.function.BinaryOperator<T>:接收兩個 T 對象,返回一個 T 對象結果。

注:為了使易懂,下面示例中 Lambda 表達式沒有使用的最簡易寫法,而是使用比較繁瑣的寫法。

(1)、java.util.function.Predicate<T>

接口類作用: 接收參數對象T,返回一個 boolean 類型結果。

接口類源碼:

@FunctionalInterface
public interface Predicate<T> {
 /** abstract 方法,接收一個參數, 判斷這個參數是否匹配某種規(guī)則, 然后返回布爾值結果 */
 boolean test(T t);
 
 /** default 方法,接收另外一個 Predicate<T> 類型參數進行"邏輯與"操作,返回一個新的 Predicate */
 default Predicate<T> and(Predicate<? super T> other) {
 Objects.requireNonNull(other);
 return (t) -> test(t) && other.test(t);
 }
 
 /** default 方法,接收另外一個 Predicate<T> 類型參數進行"邏輯或"操作,返回一個新的 Predicate */
 default Predicate<T> negate() {
 return (t) -> !test(t);
 }
 
 /** default 方法,返回當前 Predicate 取反操作之后的 Predicate */
 default Predicate<T> or(Predicate<? super T> other) {
 Objects.requireNonNull(other);
 return (t) -> test(t) || other.test(t);
 }

 static <T> Predicate<T> isEqual(Object targetRef) {
 return (null == targetRef)
 ? Objects::isNull
 : object -> targetRef.equals(object);
 }
}

使用示例:

public class PredicateExample {

 /** 這里創(chuàng)建一個 Prodicate,設置驗證秘鑰的一個邏輯,然后返回并輸出驗證結果 */
 public static void main(String[] args) {
 // 創(chuàng)建 Predicate 及 Lambda 表達式與待實現的邏輯
 Predicate<String> validation = (String secret) -> {
 return "123456".equals(secret);
 };
 // 調用 Predicate 提供的 test 方法并輸出結果
 System.out.println(validation.test("123"));
 System.out.println(validation.test("123456"));
 } 
 
}

日常開發(fā)中,需要對某個值進行判斷操作,并且返回判斷結果,這時可以考慮使用 Predicate 接口,以及它的 Lambda 表達式的實現,能方便的實現我們業(yè)務上的一些功能。

(2)、java.util.function.Comsumer<T>

接口類作用: 接收參數對象 T,不返回結果。

接口類源碼:

@FunctionalInterface
public interface Consumer<T> {

 /** abstract 方法,接收一個參數,執(zhí)行消費邏輯 */
 void accept(T t);
 
 /** default 方法,將兩個 Consumer 連接到一起,再進行消費 */
 default Consumer<T> andThen(Consumer<? super T> after) {
 Objects.requireNonNull(after);
 return (T t) -> { accept(t); after.accept(t); };
 }
 
}

使用示例:

/** 這里創(chuàng)建一個 Consumer,模擬發(fā)送消息并打印內容 */
public class ConsumerExample {

 public static void main(String[] args) {
 // 創(chuàng)建 Consumer 及 Lambda 表達式與待實現的邏輯
 Consumer<String> consumer = (String message) -> {
 System.out.println("發(fā)送消息內容:" + message);
 };
 // 調用 Consumer 提供的 accept 方法
 consumer.accept("測試消息");
 } 
 
}

日常開發(fā)中,需要對某個類型進行公共處理,并且不需要任何返回值,這時可以考慮使用 Consumer 接口及它的 Lambda 表達式的實現,能方便的實現我們業(yè)務上的一些功能。

(3)、java.util.function.Function<T,R>

接口類作用: 接收參數對象 T,返回結果對象 R。

接口類源碼:

@FunctionalInterface
public interface Function<T, R> {
 /**abstract 方法,接收一個參數進行處理,然后返回處理結果 R */
 R apply(T t);

 /** default 方法,先執(zhí)行參數(Function)的,再執(zhí)行調用者(Function) */
 default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
 Objects.requireNonNull(before);
 return (V v) -> apply(before.apply(v));
 }
 
 /** default 方法,先執(zhí)行調用者,再執(zhí)行參數,和compose相反 */
 default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
 Objects.requireNonNull(after);
 return (T t) -> after.apply(apply(t));
 }
 
 /** 返回當前正在執(zhí)行的方法 */
 static <T> Function<T, T> identity() {
 return t -> t;
 }
}

使用示例:

/** 這里創(chuàng)建一個 Function,對傳入的參數進行驗證,如果包含 a 字符就返回1,否則返回0 */
public class FunctionExample {

 public static void main(String[] args) {
 // 創(chuàng)建 Function 及 Lambda 表達式與待實現的邏輯
 Function<String, Integer> function = (String str) -> {
 return str.contains("a") ? 1 : 0;
 };
 // 調用 Function 提供的 apply 方法
 System.out.println(function.apply("abcd"));
 System.out.println(function.apply("efgh"));
 }
 
}

日常開發(fā)中,需要對某個類型數據進行操作,經過一系列邏輯后轉換為一個新的類型進行返回,這時可以考慮使用 Function 接口及它的 Lambda 表達式的實現,能方便的實現我們業(yè)務上的一些功能。

(4)、java.util.function.Supplier<T>

接口類作用: 不接收參數,提供 T 對象的創(chuàng)建工廠。

接口類源碼:

@FunctionalInterface
public interface Supplier<T> {
 /** abstract 方法,設置業(yè)務邏輯,獲取邏輯中創(chuàng)建的對象 */
 T get();
}

使用示例:

/** 這里創(chuàng)建一個 Supplier,用于生成隨機ID,通過 get 方法獲取生成的隨機ID值 */
public class SupplierExample {

 public static void main(String[] args) {
 // 創(chuàng)建 Supplier 及 Lambda 表達式與待實現的邏輯
 Supplier<String> supplier = () -> {
 return UUID.randomUUID().toString();
 };
 // 調用 Supplier 提供的 get 方法
 System.out.println(supplier.get());
 }

}

日常開發(fā)中,需要創(chuàng)建一個統(tǒng)一的工廠用于生成特定的產物完成特定的目標,這時就可以考慮使用 Supplier 接口及它的 Lambda 表達式的實現,能方便的實現我們業(yè)務上的一些功能。

(5)、java.util.function.UnaryOperator<T>

接口類作用: 接收參數對象 T,返回結果對象 T。

接口類源碼:

// 可以看到 UnaryOperator 繼承了 Function 接口
@FunctionalInterface
public interface UnaryOperator<T> extends Function<T, T> {
 /** static 方法,接收一個參數,然后對其處理后再返回 */
 static <T> UnaryOperator<T> identity() {
 return t -> t;
 }
}

使用示例:

/** 這里創(chuàng)建一個 UnaryOperator,接收一個字符串進行加工處理后返回新字符串 */
public class UnaryOperatorExample {
 
 public static void main(String[] args) {
 // 創(chuàng)建 UnaryOperator 及 Lambda 表達式與待實現的邏輯
 UnaryOperator<String> unaryOperator = (String str) -> {
 return "[" + str + "]";
 };
 // 調用 UnaryOperator 繼承的 Function 提供的 apply 方法
 System.out.println(unaryOperator.apply("hello"));
 }

}

日常開發(fā)中,我們經常要對一個已有的對象進行操作修改,然后返回修改后的對象,這時就可以考慮使用 UnaryOperator 接口及它的 Lambda 表達式的實現,能方便的實現我們業(yè)務上的一些功能。

(6)、java.util.function.BinaryOperator<T>

接口類作用: 接收兩個 T 對象,返回一個 T 對象結果。

接口類源碼:

@FunctionalInterface
public interface BinaryOperator<T> extends BiFunction<T,T,T> {
 /** abstract 方法,通過比較器Comparator來比較兩個元素中較小的一個作為返回值返回 */
 public static <T> BinaryOperator<T> minBy(Comparator<? super T> comparator) {
 Objects.requireNonNull(comparator);
 return (a, b) -> comparator.compare(a, b) <= 0 ? a : b;
 }
 
 /** 通過比較器Comparator來比較兩個元素中較大的一個作為返回值返回 */
 public static <T> BinaryOperator<T> maxBy(Comparator<? super T> comparator) {
 Objects.requireNonNull(comparator);
 return (a, b) -> comparator.compare(a, b) >= 0 ? a : b;
 }
}

使用示例:

/** 這里創(chuàng)建一個 BinaryOperator,比較傳入的兩個參數哪個值最大,返回最大值 */
public class BinaryOperatorExample {

 public static void main(String[] args) {
 // 創(chuàng)建 BinaryOperator 及 Lambda 表達式與待實現的邏輯
 BinaryOperator<Integer> binaryOperator = (Integer t1, Integer t2) -> {
 return t1 > t2 ? t1 : t2;
 };
 // 調用 BinaryOperator 繼承的 BiFunction 提供的 apply 方法
 System.out.println(binaryOperator.apply(1, 2));
 }

}

在使用這幾種基本函數接口時傳入參數 T 不能是基本類型,如 BinaryOperator 中 T 不能設置為 int,只能使用 Integer 包裝類,這也限制了 Lambda 表達式中設置參數時候,使用包裝類替換基本類型。

日常開發(fā)中,我們有時候會對兩個對象進行操作,執(zhí)行一些操作邏輯后返回結果,這時就可以考慮使用 BinaryOperator 接口及它的 Lambda 表達式的實現,能方便的實現我們業(yè)務上的一些功能。

三、Lambda 表達式基本語法

1、Lambda 表達式的組成

Lambda 表達式的組成可以拆分為:

  • 聲明: 與 Lambda 表達式綁定的接口類型。
  • 參數: 參數包含在一對 () 中,和綁定的接口中的抽象方法中的參數個數及順序一致。
  • 操作符: ->
  • 執(zhí)行代碼塊: 執(zhí)行代碼塊包含在一對 {} 中,出現在操作符的右側。           

[接口聲明] = (參數) -> {執(zhí)行代碼塊}

2、Lambda 表達式的格式

Lambda 表達式可以分為下面幾種格式:

  • 無參數,無返回值;
  • 有一個參數,無返回值;
  • 左側只有一個參數,小括號可以省略不寫;
  • 有兩個以上參數,有返回值,并且Lambda 體中有多條語句;
  • 若右側Lambda體中,只有一條語句,return 和大括號都可以省略不寫;
  • Lambda 表達式的參數列表的數據類型可以省略不寫,jvm編譯器會進行上下文推斷出,數據類型“類型推斷”;

(1)、無參數,無返回值

() -> System.out.println("測試");

(2)、有一個參數,無返回值

(x) -> System.out.println(x);

(3)、左側只有一個參數,小括號可以省略不寫

x -> System.out.println(x);

(4)、有兩個以上參數,有返回值,并且Lambda 體中有多條語句

Comparator<Integer> comparator = (x, y) -> {
 System.out.println("測試");
 return Integer.compare(x,y);
};

(5)、若右側Lambda體中,只有一條語句,return 和大括號都可以省略不寫

Comparator<Integer> Comparator = (x, y) -> Integer.compare(x, y);

(6)、Lambda 表達式的參數列表的數據類型可以省略不寫,JVM 在運行時,會自動根據綁定的抽象方法中的參數,進行數據類型推導

(Integer x, Integer y) -> Integer.compare();

四、Lambda 表達式中變量作用域

Java 中的變量捕獲與變量隱藏:

  • 變量捕獲: 局部類和匿名內部類可以訪問被 final 修飾的封閉塊內的局部變量。
  • 變量隱藏: 在一個類中,子類中的成員變量如果和父類中的成員變量同名,那么即使他們類型不一樣,只要名字一樣,父類中的成員變量都會被隱藏。

在局部類和匿名內部類都存在 變量捕獲 與 變量隱藏,而在 Lambda 表達式中則只支持 變量捕獲。

下面是對這作用域得演示示例:

(1)、匿名內部類:

public class VariableExample {
 /** 成員變量 */
 String str1 = "成員變量";

 public void innerClass() {
 // 方法內部變量
 String str2 = "方法內部變量";
 // 使用匿名內部類創(chuàng)建線程
 new Thread(new Runnable() {
  // 匿名內部類內部變量
  String str3 = "匿名內部類內部變量";
  @Override
  public void run() {
  /* 訪問變量 */
  System.out.println("匿名內部類輸出:" + str1);
  System.out.println("匿名內部類輸出:" + str2);
  System.out.println("匿名內部類輸出:" + str3);
  /* 修改變量 */
  str1 = "修改訪問成員變量";
  // str2 = "修改訪問方法內部變量"; // 不能進行修改,默認推導變量的修飾符 final
  str3 = "修改訪問匿名內部類內部變量";
  /* 在匿名內部類中定義和類外部變量一樣名稱的變量 */
  String str1 = "重新命名成員變量";
  String str2 = "重新命名方法內部變量";
  }
 }).start();
 }
 
 /** Main 方法 */
 public static void main(String[] args) {
 VariableExample variableExample = new VariableExample();
 // 匿名內部類
 variableExample.innerClass();
 }

}

(2)、Lambda 表達式:

public class VariableExample {
 /** 成員變量 */
 String str1 = "成員變量";
 
 public void lambdaExpression() {
 // 方法內部變量
 String str2 = "方法內部變量";
 new Thread(()->{
  // Lambda 內部變量
  String str3 = "Lambda 內部變量";
  /* 訪問變量 */
  // 訪問成員變量
  System.out.println("Lambda 表達式輸出:" + str1);
  // 訪問方法內部變量
  System.out.println("Lambda 表達式輸出:" + str2);
  // 訪問匿名內部類內部變量
  System.out.println("Lambda 表達式輸出:" + str3);
  /* 修改變量 */
  str1 = "修改訪問成員變量";
  // str2 = "修改訪問方法內部變量"; // 不能進行修改,默認推導變量的修飾符 final
  str3 = "修改訪問匿名內部類內部變量";
  /* 在 Lambda 中定義和類外部變量一樣名稱的變量 */
  String str1 = "重新命名成員變量";
  // String str2 = "重新命名方法內部變量"; // 不能命名,lambda 不支持變量隱藏
 }).start();
 }

 /** Main 方法 */
 public static void main(String[] args) {
 VariableExample variableExample = new VariableExample();
 // 匿名內部類
 variableExample.innerClass();
 // Lambda 表達式
 variableExample.lambdaExpression();
 }

}

五、Lambda 表達式方法重載問題

       當使用 Lambda 表達式,調用一個類中的重載方法,且方法中的參數為都為函數接口,函數接口中定義的方法接收的參數類型相同,這時候 Lambda 是無法推斷出要調用哪個方法。

函數接口A:

@FunctionalInterface
interface MyInterfaceA {
 void push(String param);
}

函數接口B:

@FunctionalInterface
interface MyInterfaceB {
 void pull(String param);
}

示例,實現方法重載與測試的 Main 方法:

public class LambdaOverloadExample {
 
 // 重載方法A
 public static void method(MyInterfaceA myInterfaceA) {
 myInterfaceA.push("hello 1");
 }
 // 重載方法B
 public static void method(MyInterfaceB myInterfaceB) {
 myInterfaceB.pull("Hello 2");
 }

 /** Main 方法*/
 public static void main(String[] args) {
 // 使用匿名內部類
 method(new MyInterfaceA() {
  @Override
  public void push(String param) {
  System.out.println(param);
  }
 });
 method(new MyInterfaceB() {
  @Override
  public void pull(String param) {
  System.out.println(param);
  }
 });
 // 使用 Lambda 表達式
 //method(param -> System.out.println(param)); // 編譯器提示錯誤,表示無法推斷使用哪個參數
 }

}

上面注掉的那部分代碼,在編輯器中直接提示錯誤,很顯然 Lambda 表達式無法直接推斷出使用哪個類中的重載方法。其實,只要明確告訴 Lambda 表達式使用哪個參數,就可以很簡單的解決問題,比如以上面的例子,在 Lambda 表達式使用 method 方法時,將參數類型轉換為對應的要使用的類型就可以解決這個問題,代碼如下:

// 轉換參數為 MyInterfaceA
method((MyInterfaceA)param -> System.out.println(param));
// 轉換參數為 MyInterfaceB
method((MyInterfaceB)param -> System.out.println(param));

按上面進行修改后就可以正常使用 Lambda 表達式了,如果不習慣也可以使用匿名內部類進行方法調用,內名內部類是沒有相關問題的。

六、Lambda 表達式方法引用

       方法引用本質上就是對方法調用的簡化,方法引用和函數式接口綁定,在使用過程中會創(chuàng)建函數式接口的實例,是結合 Lambda 表達式的一種特性。在應用過程中,方法引用常分為:

  • 靜態(tài)方法引用
  • 實例方法引用
  • 構造方法引用
  • 特定類型的任意對象實例方法引用

注意:在使用 Lmabda 方法引用時雖然能夠簡化代碼,但是在實際開發(fā)中不可因需要簡化代碼而過度使用方法引用,因為他會在很大程度上降低代碼可讀性。

1、創(chuàng)建示例的實體類

為了下面示例方便,我們首先創(chuàng)建一個 Person 實體類,如下:

public class Person {
 /** 姓名 */
 private String name;
 /** 歲數 */
 private int age;

 public Person() {
 }
 public Person(String name, int age) {
 this.name = name;
 this.age = age;
 }

 public String getName() {
 return name;
 }
 public void setName(String name) {
 this.name = name;
 }
 public int getAge() {
 return age;
 }
 public void setAge(int age) {
 this.age = age;
 }
 
 @Override
 public String toString() {
 return "Person{name=" + name + ",age=" + age + "}";
 }
}

2、靜態(tài)方法引用示例

靜態(tài)方法的引用的使用: 靜態(tài)方法所在類.方法名稱() –> 靜態(tài)方法所在類 :: 方法名稱

創(chuàng)建一個使用靜態(tài)方法引用的示例類:

public class StaticMethodExample {

 /** 測試的靜態(tài)方法 */
 public static int compareAge(Person p1, Person p2) {
 return p1.getAge() - p2.getAge();
 }

 public static void main(String[] args) {
 // 創(chuàng)建 Person 集合
 List<Person> personList = new ArrayList<>();
 personList.add(new Person("Wangqin",26));
 personList.add(new Person("Liming",22));
 personList.add(new Person("Alisi",18));
 personList.add(new Person("Jerry",31));
 
 // 按歲數進行排序,使用靜態(tài)方法引用
 personList.sort(StaticMethodExample::compareAge);
 }

}

3、實例方法引用示例

實例方法的引用的使用:創(chuàng)建類型對應一個對象 –> 對應應用 :: 實例方法名稱

創(chuàng)建一個封裝實例方法的類:

public class PersonUtil{
 /** 測試的實例方法 */
 public int compareAge(Person p1, Person p2) {
 return p1.getAge() - p2.getAge();
 }
}

創(chuàng)建一個使用實例方法引用的示例類:

public class InstanceMethodExample {

 public static void main(String[] args) {
 // 創(chuàng)建 Person 集合
 List<Person> personList = new ArrayList<>();
 personList.add(new Person("Wangqin",26));
 personList.add(new Person("Liming",22));
 personList.add(new Person("Alisi",18));
 personList.add(new Person("Jerry",31));
 
 // 按歲數進行排序,
 PersonUtil personUtil = new PersonUtil();
 // 引用實例方法
 personList.sort(personUtil::compareAge);
 }

}

4、構造方法引用示例

構造方法的引用的使用:綁定函數式接口

創(chuàng)建一個函數式接口,且設置接收參數和 Person 的構造方法相同,返回 Person 對象的方法定義:

@FunctionalInterface
public interface PersonConstructor{
 Person initInstance(String name, int age);
}

創(chuàng)建一個使用構造方法引用的示例類

public class LambdaConstructorMethodExample {

 public static void main(String[] args) {
 // 創(chuàng)建 Person 集合
 List<Person> personList = new ArrayList<>();
 personList.add(new Person("Wangqin", 26));
 personList.add(new Person("Liming", 22));
 personList.add(new Person("Alisi", 18));
 personList.add(new Person("Jerry", 31));

 // 構造方法引用
 PersonConstructor personConstructor = Person::new;
 Person person = personConstructor.initInstance("linda", 18);
 System.out.println(person);
 }
 
}

5、特定類型的任意對象實例方法引用示例

特定類型的任意對象實例方法引用示例:特定類型 :: 特定類型的方法

以下是對特定類型的任意對象的實例方法的引用的示例:

public class LambdaExample {

 public static void main(String[] args) {
 // 創(chuàng)建字符串集合
 List<String> strList = new ArrayList<>();
 strList.add("Jerry");
 strList.add("Mini");
 strList.add("Kary");
 strList.add("walls");
 
 // 使用集合的sort方法,按照String的compareToIgnoreCase進行排序(比較字符串hash值)
 strList.sort(String::compareToIgnoreCase);
 System.out.println(strList);
 }

}

這里根據定義的集合 strList 去推導目標類型參數值,如果不符合后面?zhèn)魅氲姆椒ㄒ盟鶎念愋?,將報錯。該方法參考等效 Lambda 表達式 String::compareToIgnoreCase 的參數列表 (String a, String b),其中 a 和 b 是用于更好地描述這個例子中的任意名稱。方法引用將調用該方法 a.compareToIgnoreCase(b)。

到此這篇關于Java8如何使用Lambda表達式簡化代碼的文章就介紹到這了,更多相關Java8用Lambda表達式簡化代碼內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • springboot使用IDEA遠程Debug

    springboot使用IDEA遠程Debug

    項目上線之后,如果日志打印的很模糊或者業(yè)務邏輯比較復雜,有時候無法定位具體的錯誤原因,因此可以通過IDEA遠程代理進行Debug,本文就來介紹一下如何使用
    2021-06-06
  • Java中異常處理之try和catch代碼塊的使用

    Java中異常處理之try和catch代碼塊的使用

    這篇文章主要介紹了Java中異常處理之try和catch代碼塊的使用,是Java入門學習中的基礎知識,需要的朋友可以參考下
    2015-09-09
  • Maven 多profile及指定編譯問題的解決

    Maven 多profile及指定編譯問題的解決

    這篇文章主要介紹了Maven 多profile及指定編譯問題的解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Java中websocket消息推送的實現代碼

    Java中websocket消息推送的實現代碼

    這篇文章主要介紹了Java中websocket消息推送的實現代碼,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2017-02-02
  • Java快速實現圖書管理基本功能

    Java快速實現圖書管理基本功能

    隨著網絡技術的高速發(fā)展,計算機應用的普及,利用計算機對圖書館的日常工作進行管理勢在必行,本篇文章涵蓋一個圖書管理系統(tǒng)的基本功能實現代碼,大家可以查缺補漏,提升水平
    2022-05-05
  • 通過HashMap原理詳解entrySet中的疑問

    通過HashMap原理詳解entrySet中的疑問

    這篇文章主要為大家介紹了通過HashMap原理詳解entrySet中的疑問,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-11-11
  • Docker使用Dockerfile自定義鏡像方式

    Docker使用Dockerfile自定義鏡像方式

    這篇文章主要介紹了Docker使用Dockerfile自定義鏡像方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • SpringCloud開啟session共享并存儲到Redis的實現

    SpringCloud開啟session共享并存儲到Redis的實現

    這篇文章主要介紹了SpringCloud開啟session共享并存儲到Redis的實現方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • Java正則表達式驗證固定電話號碼符合性

    Java正則表達式驗證固定電話號碼符合性

    這篇文章主要介紹了Java正則表達式驗證固定電話號碼符合性的實例代碼,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2018-09-09
  • Java實現數獨小游戲

    Java實現數獨小游戲

    這篇文章主要為大家詳細介紹了Java實現數獨小游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-05-05

最新評論

通道| 舒城县| 运城市| 泰宁县| 沈阳市| 深圳市| 象州县| 九江县| 叙永县| 舞钢市| 浙江省| 北京市| 永顺县| 天水市| 扶风县| 石景山区| 六安市| 黑龙江省| 隆子县| 宁波市| 莲花县| 利辛县| 北碚区| 昌邑市| 临高县| 八宿县| 石渠县| 大姚县| 浪卡子县| 海原县| 乌兰浩特市| 罗田县| 永川市| 城固县| 平舆县| 方山县| 肇庆市| 荔浦县| 乌恰县| 平江县| 工布江达县|