2014-04-02 16 views
116

Làm thế nào tôi có thể sắp xếp một cách thanh lịch một lambda?Làm thế nào để tuần tự hóa một lambda?

Ví dụ: mã bên dưới ném một số NotSerializableException. Làm cách nào để khắc phục sự cố mà không cần tạo giao diện "giả" SerializableRunnable?

public static void main(String[] args) throws Exception { 
    File file = Files.createTempFile("lambda", "ser").toFile(); 
    try (ObjectOutput oo = new ObjectOutputStream(new FileOutputStream(file))) { 
     Runnable r =() -> System.out.println("Can I be serialized?"); 
     oo.writeObject(r); 
    } 

    try (ObjectInput oi = new ObjectInputStream(new FileInputStream(file))) { 
     Runnable r = (Runnable) oi.readObject(); 
     r.run(); 
    } 
} 
+8

Mặc dù điều này có thể (xem phần chọn lọc d trả lời), tất cả mọi người có lẽ nên suy nghĩ hai lần về thực sự làm điều này. Nó chính thức ["không khuyến khích"] (https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html#serialization) và có thể có [nghiêm trọng] (http://stackoverflow.com/questions/25443655/khả năng-để-xoá-serial-hỗ trợ-cho-một-lambda) [bảo mật] (https://www.contrastsecurity.com/security-influencers/serialization-must-die-act-1-kryo) [ngụ ý] (https://www.contrastsecurity.com/security-influencers/serialization-must-die-act-2-xstream). – David

Trả lời

191

Java 8 giới thiệu khả năng cast an object to an intersection of types by adding multiple bounds. Trong trường hợp serialization, do đó có thể viết:

Runnable r = (Runnable & Serializable)() -> System.out.println("Serializable!"); 

Và lambda automagically trở thành serializable.

+2

Rất thú vị - tính năng này có vẻ khá mạnh mẽ. Có sử dụng một biểu hiện như vậy bên ngoài đúc lambdas? Ví dụ. là bây giờ cũng có thể làm một cái gì đó tương tự với một lớp vô danh bình thường? – Balder

+0

Điều tôi muốn nói là: có cách nào để khởi tạo một lớp ẩn danh thực hiện hai giao diện tương tự như biểu thức lambda đã được khởi tạo trong ví dụ của bạn hay không. Nhưng tôi chỉ nhìn vào nó và có vẻ như không có cú pháp mới để làm một cái gì đó như thế. – Balder

+4

@Balder Các cơ sở để đúc một loại giao lộ đã được thêm vào để cung cấp một loại mục tiêu cho suy luận kiểu lambdas. Vì AIC có loại tệp kê khai (tức là, loại của nó không được suy ra) việc đúc AIC đến loại giao lộ không hữu ích. (Có thể, chỉ là không hữu ích.) Để có một AIC thực hiện nhiều giao diện, bạn phải tạo một giao diện con mới mở rộng tất cả chúng, và sau đó khởi tạo nó. –

17

Có thể sử dụng cùng một cấu trúc cho tham chiếu phương pháp. Ví dụ: mã này:

import java.io.Serializable; 

public class Test { 
    static Object bar(String s) { 
     return "make serializable"; 
    } 

    void m() { 
     SAM s1 = (SAM & Serializable) Test::bar; 
     SAM s2 = (SAM & Serializable) t -> "make serializable"; 
    } 

    interface SAM { 
     Object action(String s); 
    } 
} 

xác định biểu thức lambda và tham chiếu phương pháp với loại mục tiêu có thể tuần tự.

2

Nếu bạn sẵn sàng chuyển sang một khung công tác tuần tự hóa khác như Kryo, bạn có thể loại bỏ nhiều giới hạn hoặc yêu cầu giao diện được triển khai phải thực hiện Serializable. Cách tiếp cận này để

  1. Sửa đổi InnerClassLambdaMetafactory để luôn tạo mã cần thiết cho serialization
  2. Gọi trực tiếp đến các LambdaMetaFactory trong deserialization

Để biết chi tiết và mã thấy blog post

3

cast Rất xấu xí này . Tôi thích để xác định một phần mở rộng Serializable đến giao diện chức năng Tôi đang sử dụng

Ví dụ:

interface SerializableFunction<T,R> extends Function<T,R>, Serializable {} 
interface SerializableConsumer<T> extends Consumer<T>, Serializable {} 

sau đó phương pháp chấp nhận lambda có thể được định nghĩa như vậy:

private void someFunction(SerializableFunction<String, Object> function) { 
    ... 
} 

và gọi chức năng bạn có thể vượt qua lambda của bạn mà không có bất kỳ diễn viên xấu xí:

someFunction(arg -> doXYZ(arg)); 
+1

Tôi thích câu trả lời này bởi vì sau đó bất kỳ người gọi bên ngoài bạn không viết sẽ tự động cũng được serializable. Nếu bạn muốn các đối tượng được gửi để có thể tuần tự hóa, giao diện của bạn nên được tuần tự hóa, đó là loại điểm của giao diện. Tuy nhiên, câu hỏi đã nói "không tạo giao diện" có thể thay thế được "SerializableRunnable' – sjlevin

Các vấn đề liên quan