亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Java > 正文

深入理解Java中的Lambda表達式

2019-11-26 15:05:57
字體:
來源:轉載
供稿:網友

 Java 8 開始出現,帶來一個全新特性:使用 Lambda 表達式 (JSR-335) 進行函數式編程。今天我們要討論的是 Lambda 的其中一部分:虛擬擴展方法,也叫做公共辯護(defender)方法。該特性可以讓你在接口定義中提供方法的默認實現。例如你可以為已有的接口(如 List 和 Map)聲明一個方法定義,這樣其他開發者就無需重新實現這些方法,有點像抽象類,但實際卻是接口。當然,Java 8 理論上還是兼容已有的庫。

虛擬擴展方法為 Java 帶來了多重繼承的特性,盡管該團隊聲稱與多重繼承不同,虛擬擴展方法被限制用于行為繼承。或許通過這個特性你可以看到了多重繼承的影子。但你還是可以模擬實例狀態的繼承。我將在接下來的文章詳細描述 Java 8 中通過 mixin 混入實現狀態的繼承。

什么是混入 mixin?

混入是一種組合的抽象類,主要用于多繼承上下文中為一個類添加多個服務,多重繼承將多個 mixin 組合成你的類。例如,如果你有一個類表示“馬”,你可以實例化這個類來創建一個“馬”的實例,然后通過繼承像“車庫”和“花園”來擴展它,使用 Scala 的寫法就是:
 
val myHouse = new House with Garage with Garden

從 mixin 繼承并不是一個特定的規范,這只是用來將各種功能添加到已有類的方法。在 OOP 中,有了 mixin,你就有通過它來提升類的可讀性。

例如在 Python 的  socketserver 模塊中就有使用 mixin 的方法,在這里,mixin 幫助 4 個基于不同 Socket 的 服務,包括支持多進程的 UDP 和 TCP 服務以及支持多線程的 UDP 和 TCP 服務。
 

class ForkingUDPServer(ForkingMixIn, UDPServer): passclass ForkingTCPServer(ForkingMixIn, TCPServer): pass class ThreadingUDPServer(ThreadingMixIn, UDPServer): passclass ThreadingTCPServer(ThreadingMixIn, TCPServer): pass

什么是虛擬擴展方法?


Java 8 將引入虛擬擴展方法的概念,也叫 public defender method. 讓我們姑且把這個概念簡化為 VEM。

VEM 旨在為 Java 接口提供默認的方法定義,你可以用它在已有的接口中添加新的方法定義,例如 Java 里的集合 API。這樣類似 Hibernate 這樣的第三方庫無需重復實現這些集合 API 的所有方法,因為已經提供了一些默認方法。

下面是如何在接口中定義方法的示例:
 

public interface Collection<T> extends Iterable<T> {   <R> Collection<R> filter(Predicate<T> p)    default { return Collections.<T>filter(this, p); } }

Java 8 對混入的模擬

現在我們來通過 VEM 實現一個混入效果,不過事先警告的是:請不要在工作中使用!

下面的實現不是線程安全的,而且還可能存在內存泄露問題,這取決于你在類中定義的 hashCode 和 equals 方法,這也是另外一個缺點,我將在后面討論這個問題。

首先我們定義一個接口(模擬狀態Bean)并提供方法的默認定義:
 

public interface SwitchableMixin {  boolean isActivated() default { return Switchables.isActivated(this); }  void setActivated(boolean activated) default { Switchables.setActivated(this, activated); }}

然后我們定義一個工具類,包含一個 Map 實例來保存實例和狀態的關聯,狀態通過工具類中的私有的嵌套類代表:
 

public final class Switchables {   private static final Map<SwitchableMixin, SwitchableDeviceState> SWITCH_STATES = new HashMap<>();   public static boolean isActivated(SwitchableMixin device) {    SwitchableDeviceState state = SWITCH_STATES.get(device);    return state != null && state.activated;  }   public static void setActivated(SwitchableMixin device, boolean activated) {    SwitchableDeviceState state = SWITCH_STATES.get(device);    if (state == null) {      state = new SwitchableDeviceState();      SWITCH_STATES.put(device, state);    }    state.activated = activated;  }   private static class SwitchableDeviceState {    private boolean activated;  } }

這里是一個使用用例,突出了狀態的繼承:
 

private static class Device {} private static class DeviceA extends Device implements SwitchableMixin {} private static class DeviceB extends Device implements SwitchableMixin {}

“完全不同的東西”

上面的實現跑起來似乎挺正常的,但 Oracle 的 Java 語言架構師 Brian Goetz 向我提出一個疑問說當前實現是無法工作的(假設線程安全和內存泄露問題已解決)
 

interface FakeBrokenMixin {  static Map<FakeBrokenMixin, String> backingMap    = Collections.synchronizedMap(new WeakHashMap<FakeBrokenMixin, String>());   String getName() default { return backingMap.get(this); }  void setName(String name) default { backingMap.put(this, name); }} interface X extends Runnable, FakeBrokenMixin {} X makeX() { return () -> { System.out.println("X"); }; }   X x1 = makeX();  X x2 = makeX();  x1.setName("x1");  x2.setName("x2");   System.out.println(x1.getName());  System.out.println(x2.getName());


你猜這段代碼執行后會顯示什么結果呢?
疑問的解決

第一眼看去,這個實現的代碼沒有問題。X 是一個只包含一個方法的接口,因為 getName 和 setName 已經有了默認的定義,但 Runable 接口的 run 方法沒有定義,因此我們可通過 lambda 表達式來生成 X 的實例,然后提供 run 方法的實現,就像 makeX 那樣。因此,你希望這個程序執行后顯示的結果是:
 

x1x2

如果你刪掉 getName 方法的調用,那么執行結果變成:
 

MyTest$1@30ae8764MyTest$1@123acf34

這兩行顯示出 makeX 方法的執行來自兩個不同的實例,而這時當前 OpenJDK 8 生成的(這里我使用的是 OpenJDK 8 24.0-b07).

不管怎樣,當前的 OpenJDK 8 并不能反映最終的 Java 8 的行為,為了解決這個問題,你需要使用特殊參數 -XDlambdaToMethod 來運行 javac 命令,在使用了這個參數后,運行結果變成:

 

x2x2

如果不調用 getName 方法,則顯示:
 

MyTest$$Lambda$1@5506d4eaMyTest$$Lambda$1@5506d4ea

每個調用 makeX 方法似乎都是來自相同匿名內部類的一個單例實例,如果觀察包含編譯后的 java class 文件的目錄,會發現并沒有一個名為 MyTestClass$$Lambda$1.class 的文件。

因為在編譯時,lambda 表達式并沒有經過完整的翻譯,事實上這個翻譯過程是在編譯和運行時完成的,javac 編譯器將 lambda 表達式變成 JVM 新增的指令 invokedynamic (JSR292)。這個指令包含所有必須的關于在運行時執行 lambda 表達式的元信息。包括要調用的方法名、輸入輸出類型以及一個名為 bootstrap 的方法。bootstrap 方法用于定義接收此方法調用的實例,一旦 JVM 執行了 invokedynamic 指令,JVM 就會在特定的 bootstrap 上調用 lambda 元工廠方法 (lambda metafactory method)。

再回到剛才那個疑問中,lambda 表達式轉成了一個私有的靜態方法,() -> { System.out.println("X"); } 被轉到了 MyTest:
 

private static void lambda$0() {  System.out.println("X");}

如果你用 javap 反編譯器并使用 -private 參數就可以看到這個方法,你也可以使用 -c 參數來查看更加完整的轉換。

當你運行程序時,JVM 會調用 lambda metafactory method 來嘗試闡釋 invokedynamic 指令。在我們的例子中,首次調用 makeX 時,lambda metafactory method 生成一個 X 的實例并動態鏈接 run 方法到 lambda$0 方法. X 的實例接下來被存儲在內存中,當第二次調用 makeX 時就直接從內存中讀取這個實例,因此你第二次調用的實例跟第一次是一樣的。
修復了嗎?有解決辦法嗎?

目前尚無這個問題直接的修復或者是解決辦法。盡管 Oracle 的 Java 8 計劃默認激活-XDlambdaToMethod 參數,因為這個參數并不是 JVM 規范的一部分,因此不同供應商和 JVM 的實現是不同的。對一個 lambda 表達式而言,你唯一能期望的就是在類中實現你的接口方法。


其他的方法

到此為止,盡管我們對 mixin 的模仿并不能兼容 Java 8,但還是可能通過多繼承和委派為已有的類添加多個服務。這個方法就是 virtual field pattern (虛擬字段模式).

所以來看看我們的 Switchable.
 

interface Switchable {  boolean isActive();  void setActive(boolean active);}

我們需要一個基于 Switchable 的接口,并提供一個附加的抽象方法返回 Switchable 的實現。集成的方法包含默認的定義,它們使用 getter 來轉換到 Switchable 實現的調用:

 

public interface SwitchableView extends Switchable {  Switchable getSwitchable();    boolean isActive() default { return getSwitchable().isActive(); }  void setActive(boolean active) default { getSwitchable().setActive(active); }}

接下來,我們創建一個完整的 Switchable 實現:
 

public class SwitchableImpl implements Switchable {    private boolean active;    @Override  public boolean isActive() {    return active;  }    @Override  public void setActive(boolean active) {    this.active = active;  }}

這里是我們使用虛擬字段模式的例子:
 

public class Device {}  public class DeviceA extends Device implements SwitchableView {  private Switchable switchable = new SwitchableImpl();    @Override  public Switchable getSwitchable() {    return switchable;  }}  public class DeviceB extends Device implements SwitchableView {  private Switchable switchable = new SwitchableImpl();    @Override  public Switchable getSwitchable() {    return switchable;  }}

結論

在這篇文章中,我們使用了兩種方法通過 Java 8 的虛擬擴展方法為類增加多個服務。第一個方法使用一個 Map 來存儲實例狀態,這個方法很危險,因為不是線程安全而且存在內存泄露問題,這完全依賴于不同的 JVM 對 Java 語言的實現。另外一個方法是使用虛擬字段模式,通過一個抽象的 getter 來返回最終的實現實例。第二種方法更加獨立而且更加安全。

虛擬擴展方法是 Java 的新特性,本文主要介紹的是多重繼承的實現,詳細你會有更深入的研究以及應用于其他方面,別忘了跟大家分享。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
精品国产91久久久久久| 在线性视频日韩欧美| 97婷婷涩涩精品一区| 欧美大全免费观看电视剧大泉洋| 萌白酱国产一区二区| 色综合影院在线| 懂色av中文一区二区三区天美| 久久在线免费视频| 国产视频精品在线| 国产欧美一区二区三区久久| 91sao在线观看国产| 亚洲精品乱码久久久久久按摩观| 成人激情视频在线播放| 色777狠狠综合秋免鲁丝| 色先锋资源久久综合5566| 成人午夜在线视频一区| 26uuu另类亚洲欧美日本一| 91精品国产综合久久男男| 亚洲www在线观看| 欧美视频专区一二在线观看| 国产精品一区二区性色av| 亚洲成人黄色在线| xvideos成人免费中文版| 国产视频亚洲精品| 国产国语videosex另类| 国产精品视频成人| 欧美在线视频免费播放| 亚洲一区亚洲二区| 日韩电影在线观看中文字幕| 成人激情视频网| 国产欧美欧洲在线观看| 国产成人精品av| 91av在线网站| 国产精自产拍久久久久久| 日韩精品欧美激情| 一本色道久久综合狠狠躁篇的优点| 亚洲电影第1页| 午夜免费在线观看精品视频| 精品丝袜一区二区三区| 亚洲国产精品人人爽夜夜爽| 国产精品欧美激情| 欧美黑人xxxx| 91av在线免费观看视频| 26uuu日韩精品一区二区| 国产精品www| 中文字幕日韩欧美在线视频| 精品国产精品三级精品av网址| 国产精品18久久久久久麻辣| 亚洲色图美腿丝袜| 91精品中国老女人| 亚洲r级在线观看| 国产美女精品视频免费观看| 久久精品一本久久99精品| 久久99久久99精品免观看粉嫩| 夜夜嗨av色综合久久久综合网| 国产欧美精品在线播放| 午夜精品久久久久久久久久久久久| 97视频在线观看亚洲| 亚洲精品视频中文字幕| 午夜美女久久久久爽久久| 国产精品久久久久秋霞鲁丝| 色爱av美腿丝袜综合粉嫩av| 亚洲视频在线免费观看| 久久久久久一区二区三区| 免费97视频在线精品国自产拍| 搡老女人一区二区三区视频tv| 51精品国产黑色丝袜高跟鞋| 国产精品视频白浆免费视频| 97香蕉超级碰碰久久免费的优势| 国产精品一区二区三区免费视频| 亚洲性猛交xxxxwww| 日韩精品欧美激情| www.欧美免费| 亚洲一二三在线| 啪一啪鲁一鲁2019在线视频| 北条麻妃一区二区在线观看| 日韩av大片在线| 国产精品免费一区豆花| 欧美中文字幕在线| 国产亚洲欧美一区| 中文字幕日韩av电影| 97视频在线免费观看| 欧美日韩电影在线观看| 久久黄色av网站| 亚洲午夜激情免费视频| 国产精品1区2区在线观看| 日韩小视频在线| 精品国产拍在线观看| 91日本视频在线| 国产精品手机播放| 国产精品久久在线观看| 久久精品视频一| 在线精品91av| 91天堂在线视频| 91精品国产电影| 亚洲第一精品福利| 98视频在线噜噜噜国产| 亚洲天堂网在线观看| 欧美成在线视频| 成人av.网址在线网站| 国产成人97精品免费看片| 亚洲精品白浆高清久久久久久| 91国产一区在线| 美女啪啪无遮挡免费久久网站| 少妇高潮 亚洲精品| 日韩国产精品亚洲а∨天堂免| 国内外成人免费激情在线视频网站| 亚洲人高潮女人毛茸茸| 欧美午夜丰满在线18影院| 久久最新资源网| 久久久欧美一区二区| 成人深夜直播免费观看| 97色在线播放视频| 成人免费视频在线观看超级碰| 精品福利樱桃av导航| 国内精品久久久久影院 日本资源| 最近2019中文字幕大全第二页| 亚洲人成电影在线观看天堂色| 欧美华人在线视频| 欧美视频第一页| 欧美日韩高清区| 国产精品视频中文字幕91| 尤物99国产成人精品视频| 91欧美精品成人综合在线观看| 黄色一区二区在线观看| 久久五月情影视| 亚洲理论片在线观看| 国产日韩一区在线| 亚洲国产精品国自产拍av秋霞| 91国产视频在线播放| 在线视频免费一区二区| 91香蕉亚洲精品| 日韩电影中文 亚洲精品乱码| 国产精品欧美日韩| 日韩av一区在线| 国产精品久久久久久久久久小说| 国产亚洲精品久久久优势| 日本成熟性欧美| 国产成人精品在线观看| 精品视频中文字幕| 欧美精品在线免费播放| 欧美在线视频观看| 久久久久久久久久久网站| 精品福利在线观看| 国产精品美女网站| 中文字幕亚洲欧美在线| 亚州精品天堂中文字幕| 欧美老妇交乱视频| 色青青草原桃花久久综合| 亚洲丝袜一区在线| 国模极品一区二区三区| 日韩欧美在线视频日韩欧美在线视频| 91九色国产在线| 国产主播欧美精品| 欧美精品激情在线观看| 亚洲精品一区二区三区婷婷月| 国产精品久久久久一区二区| 欧美日本啪啪无遮挡网站| 青青草精品毛片| 欧美激情xxxxx| 国产免费观看久久黄| 久久精品国产亚洲一区二区| 亚洲a一级视频| 性色av一区二区三区免费|