如何以及为什么序列化Lambda
總覽
lambda序列化在許多用例中很有用,例如持久配置或作為遠程資源的訪客模式 。
遠程訪客
例如,因此我想訪問遠程Map上的資源,可以使用get / put,但是說我只想從Map的值中返回一個字段,我可以將lambda作為訪問者來傳遞以提取信息。我想要。
MapView userMap =Chassis.acquireMap("users", String.class, UserInfo.class); userMap.put("userid", new UserInfo("User's Name"));// print out changesuserInfo.registerSubscriber(System.out::println);// obtain just the fullName without downloading the whole object String name= userMap.applyToKey("userid", u -> u.fullName);// increment a counter atomically and trigger // an updated event printed with the subscriber. userMap.asyncUpdateKey("userid", ui -> {ui.usageCounter++;return ui; });// increment a counter and return the userid int count = userMap.syncUpdateKey("userid",ui -> { ui.usageCounter++; return ui;},ui -> ui.usageCounter);如您所見,添加各種簡單功能或調用方法來執行所需的操作很容易。 唯一的問題是默認情況下lambda無法序列化。
可序列化的Lambda
使lambda可序列化的一種簡單方法是將&的可轉換類型添加到引用lambda的實現的變量中。
Function<UserInfo, String> fullNameFunc = (Function<UserInfo,String> & Serializable) ui -> ui.fullName; String fullName = userInfo.applyToKey("userid", fullNameFunc);如您所見,這引入了很多樣板。 使用lambda的一個關鍵原因是避免樣板代碼,那么替代方法是什么?
使lambda可在您的API中序列化。
不幸的是,無法更改標準API或添加其子類,但是如果您擁有自己的API,則可以使用Serializable接口。
@FunctionalInterface public interface SerializableFunction<I, O> extends Function<I, O>, Serializable { }該接口可用作參數類型。
default <R> R applyToKey(K key, @NotNull SerializableFunction<E, R> function) {return function.apply(get(key)); }您的API用戶不必明確聲明lambda是可序列化的。
// obtain just the fullName without downloading the whole object String name= userMap.applyToKey("userid", u -> u.fullName);遠程實現對lambda進行序列化,然后在服務器上執行該lambda并返回結果。
類似地,存在將lambda應用于整個地圖的方法。
查詢和訂閱
為了支持查詢,如果要隱式添加Serializable,則不能使用內置的stream()API。 但是,您可以創建一個盡可能相似的文件。
Map> collect = userMap.entrySet().query().filter(e -> e.getKey().matches("u*d")).map(e -> e.getValue()).collect(Collectors.groupingBy(u -> u.usageCounter));或作為過濾的訂閱。
// print userid which have a usageCounter > 10 each time it is incremented. userMap.entrySet().query().filter(e -> e.getValue().usageCounter > 10).map(e -> e.getKey()).subscribe(System.out::println);這與常規流API的不同之處在于,數據可以分布在許多服務器上,并且當任何服務器上的數據發生更改時,您都會得到回調。 在服務器上應用過濾器和映射時,只有您感興趣的數據才通過網絡發送。
Java序列化
Java序列化是一個很好的通用化,向后兼容的序列化庫。 替代方案嘗試解決的兩個最常見問題是性能和跨平臺序列化。
在上面的示例中,fullNameFunc序列化到700多個字節,并且有非常有限的選項來優化它以減少消息的大小或產生的垃圾量。 相比之下,簡單的二進制YAML序列化使用348,并提供更多選項來優化序列化。
這就提出了如何使用替代,跨平臺或更快的序列化格式來序列化lambda的問題。
替代序列化
您可以加入當前的序列化機制。 不支持此功能,它可以隨時更改,但是沒有其他受支持的方式來執行此操作。
無論如何,您可以這樣做:
Method writeReplace = lambda.getClass().getDeclaredMethod("writeReplace"); writeReplace.setAccessible(true); SerializedLambda sl = (SerializedLambda) writeReplace.invoke(lambda);這為您提供了一個對象,您可以檢查該對象以提取lambda的內容。 要么查看它調用什么方法,要么對其進行序列化。 在反序列化方面,您可以重新創建該對象并可以在該對象上讀取Resolve。
標準API
當前,沒有用于內省lambda的標準API。 這樣做是有意進行的,以便將來可以更改實現,盡管沒有公共JEP可以這樣做。 但是,就像Unsafe是內部API一樣,我期待有一天可以使用標準API,而不必深入研究JVM的內部來實現解決方案。
結論
通過對API進行一些更改,您可以使序列化lambda對開發人員而言基本上是透明的。 這使實現簡單的分布式系統更易于使用,同時為您提供了優化方法。
翻譯自: https://www.javacodegeeks.com/2015/07/how-and-why-to-serialize-lambdas.html
總結
以上是生活随笔為你收集整理的如何以及为什么序列化Lambda的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 新农合住院8天没备案怎么办(新农合住院8
- 下一篇: 通用编程准则