溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

java8之lambda表達(dá)式用法總結(jié)

發(fā)布時(shí)間:2020-08-25 20:05:42 來(lái)源:腳本之家 閱讀:132 作者:漫夭 欄目:編程語(yǔ)言

java8之lambda表達(dá)式

目的:行為參數(shù)化

Lambda表達(dá)式是簡(jiǎn)潔地表示可傳遞的匿名函數(shù)的一種方式:它沒(méi)有名稱,但它有參數(shù)列表、函數(shù)主體、返回類型,可能還有一個(gè)可以拋出的異常列表。

Lambda的基本語(yǔ)法是(parameters) -> expression 或 (parameters) -> { statements; }。其中, (parameters) -> expression 的表達(dá)式中隱含了return,如 () -> 42; (parameters) -> { statements; } 的花括號(hào)內(nèi)是語(yǔ)句。

舉例:

() -> 42  //參數(shù)為空,返回一個(gè)int
(List<String> list) -> list.isEmpty() //參數(shù)為list,返回一個(gè)boolean
(int x, int y) -> x*y //參數(shù)為兩個(gè)int,返回一個(gè)int
(String s) -> System.out.println(s); //參數(shù)為一個(gè)String,不返回結(jié)果
(String s) -> {System.out.println(s);} //參數(shù)為一個(gè)String,打印字符串

哪些地方使用哪些lambda

函數(shù)式接口是只定義一個(gè)抽象方法的接口,即使擁有多個(gè)默認(rèn)方法。FunctionalInterface 標(biāo)注一個(gè)函數(shù)式接口,會(huì)加入編譯檢查。函數(shù)式接口中默認(rèn)方法的目的是:改變已發(fā)布的接口而不破壞已有的實(shí)現(xiàn)。

在接受函數(shù)式接口為參數(shù)的地方,都可以使用lambda表達(dá)式。

例子:

public void execute(Runnable r){
  r.run(); 
}
execute(() -> {}); //使用lambda,Runnable是參數(shù)為空,沒(méi)有返回值的函數(shù)式接口,即() -> void 
//fetch返回一個(gè)函數(shù)式接口,() -> String
public Callable<String> fetch() { 
  return () -> "Tricky example ;-)";
}

為什么只有在函數(shù)式接口的地方使用呢?lambda表達(dá)式?jīng)]有函數(shù)名,只有參數(shù)列表,函數(shù)主體和返回值,如果接口有多個(gè)方法,就不能直接匹配到正確的方法上了,所以,只有一個(gè)抽象方法的函數(shù)式接口可以滿足。

Predicate

java.util.function.Predicate<T>是一個(gè)含有多個(gè)默認(rèn)方法的函數(shù)式接口,抽象方法為:(T t) -> bool??聪麓a,你就懂了~

FunctionalInterface
public interface Predicate<T> {
  //接口方法,入?yún)榉盒蚑,返回bool。即:(T t) -> bool
  boolean test(T t);
  //默認(rèn)方法,and操作
  default Predicate<T> and(Predicate<? super T> other) {
    Objects.requireNonNull(other);
    return (t) -> test(t) && other.test(t);
  }
  //默認(rèn)方法,取反操作
  default Predicate<T> negate() {
    return (t) -> !test(t);
  }
  //默認(rèn)方法,or 操作
  default Predicate<T> or(Predicate<? super T> other) {
    Objects.requireNonNull(other);
    return (t) -> test(t) || other.test(t);
  }
  //默認(rèn)方法,判斷是否相等
  static <T> Predicate<T> isEqual(Object targetRef) {
    return (null == targetRef)
        ? Objects::isNull
        : object -> targetRef.equals(object);
  }

使用

Predicate<String> nonEmptyStringPredicate = (String s) -> !s.isEmpty();

Consumer

java.util.function.Consumer<T> 是一個(gè)只含有一個(gè)默認(rèn)方法的函數(shù)式接口,抽象方法為:(T t) ->void。看下代碼,你就懂了~

@FunctionalInterface
public interface Consumer<T> {
  //接口方法,入?yún)榉盒蚑,返回void。即:(T t) -> void
  void accept(T t);
  //默認(rèn)方法,可以執(zhí)行級(jí)聯(lián)操作
  default Consumer<T> andThen(Consumer<? super T> after) {
    Objects.requireNonNull(after);
    return (T t) -> { accept(t); after.accept(t); };
  }

Function

java.util.function.Function<T, R>是一個(gè)含有多個(gè)默認(rèn)方法的函數(shù)式接口,抽象方法為:(T t) ->R??聪麓a,你就懂了~

@FunctionalInterface
public interface Function<T, R> {
  //接口方法,入?yún)榉盒蚑,返回泛型R。即:(T t) -> R
  R apply(T t);
  //默認(rèn)方法,實(shí)現(xiàn)級(jí)聯(lián)操作。before方法輸入V,輸出T,本function輸入T,輸出R。
  default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
    Objects.requireNonNull(before);
    return (V v) -> apply(before.apply(v));
  }
  //默認(rèn)方法,級(jí)聯(lián)操作
  default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
    Objects.requireNonNull(after);
    return (T t) -> after.apply(apply(t));
  }
  //默認(rèn)方法,輸入啥,輸出啥
  static <T> Function<T, T> identity() {
    return t -> t;
  }

特定方法避免裝箱操作

在處理數(shù)據(jù)時(shí),使用特定方法,可以避免裝箱操作,如:IntPredicate、LongConsumer、DoubleFunction等。具體見(jiàn)API庫(kù)。

總結(jié)

函數(shù)描述符 函數(shù)式接口
(T) ->bool java.util.function.Predicate<T>
(T) -> void java.util.function.Consumer<T>
(T) -> R java.util.function.Function<T, R>
(T,U) -> R java.util.function.BiFunction<T, U, R>
() -> T java.util.function.Supplier<T>

只要函數(shù)描述符兼容,函數(shù)式接口就可以復(fù)用。

特殊的void兼容規(guī)則:

// Predicate返回了一個(gè)boolean 
Predicate<String> p = s -> list.add(s); 
// Consumer返回了一個(gè)void 
Consumer<String> b = s -> list.add(s);

方法引用

方法引用是調(diào)用單一方法的Lambda的快捷寫法,格式ClassName::methodName。看下栗子你就懂了~

一般方法引用

(Apple a) -> a.getWeight() 等價(jià)于Apple::getWeight 
() -> Thread.currentThread().dumpStack() 等價(jià)于 Thread.currentThread()::dumpStack
(str, i) -> str.substring(i) 等價(jià)于 String::substring
(String s) -> System.out.println(s) 等價(jià)于 System.out::println
(list, element) -> list.contains(element) 等價(jià)于 List::contains

主要有三類:

  1. 指向靜態(tài)方法的方法引用,如:Integer::parseInt
  2. 指向任意類型實(shí)例方法的方法引用,如:String::length
  3. 指向現(xiàn)有對(duì)象的實(shí)例方法的方法引用,如:User::getUserId

構(gòu)造函數(shù)引用

無(wú)參構(gòu)造函數(shù)

無(wú)參構(gòu)造函數(shù)的函數(shù)描述符:() -> T,由上面的總結(jié)知,可以使用Supplier接口,如下:

Supplier<User> c1 = User::new; // c1 = () -> new User();
User user = c1.get();

有一個(gè)參數(shù)的構(gòu)造函數(shù)

有一個(gè)參數(shù)的構(gòu)造函數(shù)的函數(shù)描述符是(T) -> R,可以使用Function接口,如下:

Function<Long, User> c2 = User::new;

User user = c2.apply(110L);

有三個(gè)參數(shù)的構(gòu)造函數(shù)

有三個(gè)參數(shù)的構(gòu)造函數(shù)的函數(shù)描述符是(T,U,V) -> R,沒(méi)有現(xiàn)成的接口,需要自定義,如下:

@Data
@AllArgsConstructor
public class User {
  private String name;
  private Long userId;
  private Integer age;
}
@FunctionalInterface
public interface TriFunction<T,U,V,R> {
  R create(T t, U u, V v);
}
public static void main(String[] args) {
  TriFunction<String, Long, Integer, User> triFunction = User::new;
  User user = triFunction.create("tina", 12L, 13);
}

使用注意事項(xiàng)

Lambda表達(dá)式可以引用靜態(tài)變量、成員變量和最終的(final) 或事實(shí)上最終的局部變量。

更多關(guān)于java8中l(wèi)ambda表達(dá)式相關(guān)方法請(qǐng)查看下面的相關(guān)鏈接

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI