2014-05-03 31 views
5

Giả sử tôi có một số List<String>List<Transfomer>. Tôi muốn áp dụng từng biến áp cho mỗi chuỗi trong danh sách.Java 8 lambda trong một lambda không thể sửa đổi biến từ bên ngoài lambda

Sử dụng Java 8 lambdas, tôi có thể làm điều này:

strings.stream().map(s -> { 
    for(Transformer t : transformers) { 
     s = t.apply(s); 
    } 
    return s; 
}).forEach(System.out::println); 

Nhưng tôi muốn làm một cái gì đó nhiều như thế này, tuy nhiên nó kết quả trong một lỗi thời gian biên dịch:

strings.stream().map(s -> transformers.stream().forEach(t -> s = t.apply(s))).forEach(System.out::println); 

tôi chỉ mới bắt đầu chơi với lambdas, vì vậy có lẽ tôi chỉ không có cú pháp chính xác.

+1

Nó có thể giúp đưa văn bản của lỗi trình biên dịch vào. – MatrixFrog

+1

Lỗi: (49, 60) java: biến cục bộ được tham chiếu từ biểu thức lambda phải là kết quả cuối cùng hoặc hiệu quả –

+0

Câu hỏi này rất hay; Tuy nhiên, tôi sẽ đề nghị rằng nó nên được chuyển đến Stack Overflow. –

Trả lời

13

Cách tốt nhất để làm điều này với con suối là sử dụng reduce:

// make a transformer that combines all of them as one 
Transformer combinedTransformer = 

    // the stream of transformers 
    transformers.stream() 

    // combine all the transformers into one 
    .reduce(

     // apply each of the transformers in turn 
     (t1, t2) -> x -> t2.apply(t1.apply(x))) 

    ); 



// the stream of strings 
strings.stream() 

// transform each string with the combined transformer 
.map(combinedTranformer::apply); 

Tất nhiên, điều này giả định rằng transformers không bị để trống; nếu có một khả năng rằng nó là trống rỗng, hơn nó là đủ đơn giản để sử dụng quá tải hai đối số của reduce thay vào đó, như vậy (điều này giả định Tranformer là một giao diện chức năng):

// make a transformer that combines all of them as one 
Transformer combinedTransformer = 

    // the stream of transformers 
    transformers.stream() 

    // combine all the transformers into one 
    .reduce(

     // the no-op transformer 
     x -> x, 

     // apply each of the transformers in turn 
     (t1, t2) -> x -> t2.apply(t1.apply(x))) 

    ); 



// the stream of strings 
strings.stream() 

// transform each string with the combined transformer 
.map(combinedTranformer::apply); 

Lý do bạn có một lỗi biên dịch là, như lỗi nói, các biến bên ngoài được sử dụng trong một biểu thức lambda phải là hiệu quả cuối cùng; có nghĩa là, tuyên bố chúng final (nếu chúng chưa có) không được thay đổi ý nghĩa của chương trình, hoặc thay đổi hay không biên dịch. Do đó, việc sử dụng một phép gán mutable trong lambda thường bị cấm, và với lý do chính đáng: các vít đột biến lên song song, và một trong những lý do chính lambdas được đưa vào Java 8 là cho phép lập trình song song dễ dàng hơn.

Nói chung, bất cứ khi nào bạn muốn "tổng hợp" kết quả theo một cách nào đó, reduce (trong bất kỳ ba quá tải nào của nó) là phương pháp truy cập của bạn. Tìm hiểu cách sử dụng map, filter, reduceflatMap hiệu quả là rất quan trọng khi làm việc với Stream s.

+1

Cảm ơn, đó là khá một chút để đi với kinh nghiệm hạn chế của tôi bằng cách sử dụng lambdas. Cú pháp hơi rắc rối một chút, nhưng tôi sẽ xem xét nó cho đến khi tôi hiểu nó :) –

+1

+1, nhưng tôi thấy dễ đọc hơn nếu các chú thích ngắn hơn hoặc trên các dòng riêng biệt để không có cuộn ngang. –

+0

@DavidConrad Cái nhìn đó như thế nào? –

1

Lambdas (giống như các lớp địa phương) không bao giờ có thể gán cho các biến cục bộ đã chụp, cho dù từ một lambda bên ngoài, hoặc từ một phương thức kèm theo. Các biến cục bộ được chụp phải có hiệu quả cuối cùng.

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