2015-06-09 26 views
8

Tôi đang xây dựng một đối tượng với một vòng lặp đơn giản:Builder pattern với Java 8 Suối

WebTarget target = getClient().target(u); 

for (Entry<String, String> queryParam : queryParams.entrySet()) { 
    target = target.queryParam(queryParam.getKey(), queryParam.getValue()); 
} 

Tôi muốn làm điều tương tự bằng cách sử dụng API Java8 Suối nhưng tôi không thể tìm ra cách để làm điều đó. Điều gì làm cho tôi đấu tranh là mục tiêu được gán lại mỗi lần, vì vậy một đơn giản .forEach() sẽ không hoạt động. Tôi đoán tôi cần sử dụng một .collect() hoặc reduce() vì tôi đang tìm kiếm một giá trị trả về duy nhất nhưng tôi bị mất vào lúc này!

Trả lời

6

Rất tiếc, không có phương thức foldLeft trong API luồng. Lý do cho điều này được giải thích bởi Stuart Marks trong this answer:

[...] Cuối cùng, Java không cung cấp foldLeftfoldRight hoạt động vì chúng ám chỉ một trật tự cụ thể của hoạt động mà vốn đã tuần tự. Điều này xung đột với nguyên tắc thiết kế đã nêu ở trên về việc cung cấp các API hỗ trợ hoạt động tuần tự và song song như nhau.

Cuối cùng, những gì bạn đang cố gắng làm ở đây là một số thủ tục/tuần tự vì vậy tôi không nghĩ API luồng phù hợp cho trường hợp sử dụng này. Tôi nghĩ rằng các vòng lặp cho mỗi bạn đã đăng cho mình là tốt như nó được.

Cập nhật:

Như @TagirValeev chỉ ra below bạn thể trên thực tế giải quyết nó với các API dòng (sử dụng forEachOrdered Mã của bạn sau đó sẽ giống như

WebTarget[] arr = { getClient().target(u) }; 
queryParams.entrySet() 
      .stream() 
      .forEachOrdered(e -> arr[0] = arr[0].queryParam(e.getKey(), 
                  e.getValue())); 
WebTarget target = arr[0]; 

tôi đứng. bởi câu trả lời ban đầu của tôi và tuyên bố rằng vòng lặp cũ tốt của bạn là cách tiếp cận tốt hơn trong trường hợp này.

+0

Tôi lo lắng về điều đó kết hợp cuối cùng, ngay cả khi bạn thêm 'tuần tự() '. –

+1

Tôi cũng thế. Tôi không chắc nó đúng. Không có bất kỳ tương đương với 'foldLeft', tôi nghi ngờ API luồng phù hợp trong tình huống này. – aioobe

+2

Tôi nghĩ rằng tôi thích một câu trả lời hoàn toàn tuyên bố rằng các luồng không thực sự hỗ trợ tốt điều này. –

8

Đó là n ot rất khó khăn để thực hiện một xác foldLeft cho Java 8 suối:

@SuppressWarnings("unchecked") 
public static <T, U> U foldLeft(Stream<T> stream, 
           U identity, BiFunction<U, ? super T, U> accumulator) { 
    Object[] result = new Object[] { identity }; 
    stream.forEachOrdered(t -> result[0] = accumulator.apply((U) result[0], t)); 
    return (U) result[0]; 
} 

Hoặc trong kiểu an cách:

public static <T, U> U foldLeft(Stream<T> stream, 
           U identity, BiFunction<U, ? super T, U> accumulator) { 
    class Box { 
     U value; 
     Box(U value) { this.value = value; } 
    } 
    Box result = new Box(identity); 
    stream.forEachOrdered(t -> result.value = accumulator.apply(result.value, t)); 
    return result.value; 
} 

này hoạt động một cách chính xác cho dòng tuần tự và song song. Bạn thậm chí có thể đạt được tốc độ sử dụng các luồng song song nếu luồng của bạn có một số hoạt động trung gian không sử dụng CPU như map: trong trường hợp này, phần tử tiếp theo có thể được xử lý bởi map song song với phần tử hiện tại được xử lý bởi foldLeft. Tôi không đồng ý rằng hoạt động như vậy không phù hợp với API luồng vì nó có thể được thể hiện chính xác qua số đã tồn tại forEachOrdered.

tôi có hoạt động này trong thư viện StreamEx tôi, vì vậy bạn có thể sử dụng nó như thế này:

WebTarget target = EntryStream.of(queryParams).foldLeft(getClient().target(u), 
     (t, entry) -> t.queryParam(entry.getKey(), entry.getValue())) 
+1

Tốt. Tuy nhiên, 3 dòng mã của bạn trông cực kỳ phức tạp với tôi, so với vòng lặp của OP. Đồ vật 'Object []' không thực sự trông thành ngữ lambda, có lẽ tôi sai. – aioobe

+3

Một AtomicReference có thể được sử dụng thay thế, nếu bạn muốn có loại an toàn, mặc dù tôi không chắc chắn nếu nó sẽ làm cho thành ngữ lambda kết quả hoặc là: AtomicReference result = new AtomicReference <> (identity); stream.forEachOrdered (t -> result.updateAndGet (u -> accumulator.apply (u, t)); return result.get(); – srborlongan

+1

@aioobe: triển khai 'foldLeft' là một phần của mã thư viện cấp thấp, Vì vậy, đối với tôi nó là ok nếu nó trông không đẹp, xem, ví dụ, 'Collectors' lớp: có rất nhiều công cụ tương tự ở đó.Đối với lớp an toàn bổ sung lớp có thể được tạo ra như' class Box {U value; Box (U v) {value = v;}} '. –

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