2016-09-02 31 views
8

Tôi có một danh sách các số có số 0s bên trong. Vì 0 có nghĩa là số đo không hợp lệ trong trường hợp của tôi, tôi cần thay đổi thành phần có giá trị 0 với phần tử không phải 0 đầu tiên mà tôi có thể tìm thấy ở các vị trí trước đó.Luồng Java Sử dụng phần tử trước trong Foreach Lambda

Ví dụ danh sách

45 55 0 0 46 0 39 0 0 0 

phải trở thành

45 55 55 55 46 46 39 39 39 39 

Đây là thực hiện bằng cách sử dụng cổ điển for each

 int lastNonZeroVal = 0; 
     for (MntrRoastDVO vo : res) { 
      if (vo.getValColor() > 0) { 
       lastNonZeroVal = vo.getValColor(); 
      } else { 
       vo.setValColor(lastNonZeroVal); 
      } 
     } 

Có cách nào để thực hiện điều này với Streams Java và Hàm Lambda?

Vì tôi biết rằng tôi không được thay đổi nguồn của luồng trong lambda foreach, nên danh sách là danh sách đối tượng và tôi không thay đổi phần tử của danh sách nhưng tôi chỉ gán giá trị mới.

Đây là giải pháp đầu tiên của tôi

int lastNonZeroVal = 1; 
resutl.stream().forEach(vo -> { 
     if(vo.getValColor()>0){ 
      lastNonZeroVal=vo.getValColor(); 
     }else{ 
      vo.setValColor(lastNonZeroVal); 
     } 
}); 

Nhưng tôi cũng đọc here

Tốt nhất là nếu lambdas truyền cho dòng hoạt động hoàn toàn bên hiệu lực thi hành miễn phí. có nghĩa là, họ không biến đổi bất kỳ trạng thái heapbased nào hoặc thực hiện bất kỳ I/O nào trong quá trình thực hiện.

Đây là những gì tôi worryng

dữ liệu được phân chia, không có đảm bảo rằng khi một yếu tố nhất định là xử lý, tất cả các yếu tố trước yếu tố đó đã được xử lý.

Giải pháp này có thể tạo ra kết quả không hợp lệ, có thể khi số lượng thành phần trong danh sách cao? ? Sự kiện nếu tôi không sử dụng parallelStream()?

+0

có thể cho kết quả không chính xác nếu luồng chứa số âm .... trường hợp còn lại có vẻ tốt ... – Rishi

+4

Tại sao bạn muốn sử dụng cấu trúc không gian (luồng) cho hoạt động có trạng thái? – Spotted

+0

Tôi đoán đây chính xác là lỗi của tôi, luồng không phải là giải pháp phù hợp trong trường hợp này – Panciz

Trả lời

0

Bạn có thể sửa đổi trạng thái của các đối tượng bên trong luồng. Nhưng bạn không thể sửa đổi trạng thái nguồn dữ liệu.

Sự cố cũng giống như trong việc lặp lại cổ điển.

Sử dụng forEachOrdered() để thực hiện

một hành động cho mỗi yếu tố của dòng này, theo thứ tự cuộc gặp gỡ của con suối nếu dòng có một trật tự cuộc gặp gỡ định nghĩa

Nếu bạn gọi

result.stream.forEachOrdered(...) 

tất cả các yếu tố sẽ được xử lý tuần tự theo thứ tự.

Đối với các luồng tuần tự forEach dường như tôn trọng thứ tự.

+0

Tôi đã chỉ định rõ hơn những gì đang làm tôi lo lắng. – Panciz

+0

Ok điều này giải quyết được vấn đề của lệnh thi hành nhưng tôi nghĩ rằng tôi vẫn có thể gặp vấn đề với khả năng hiển thị của biến chia sẻ "Thực hiện hành động cho một phần tử xảy ra trước khi thực hiện hành động cho các phần tử tiếp theo, nhưng đối với bất kỳ phần tử nào, hành động có thể được thực hiện trong bất kỳ chủ đề nào mà thư viện chọn. " – Panciz

5

Tốt nhất là nếu lambdas được truyền đến các hoạt động truyền trực tiếp, hãy hoàn toàn phụ có hiệu lực miễn phí. có nghĩa là, họ không biến đổi bất kỳ trạng thái heapbased nào hoặc thực hiện bất kỳ I/O nào trong quá trình thực hiện.

Giải pháp của bạn không có tác dụng phụ , nó thay đổi danh sách nguồn của bạn thành danh sách tài nguyên. Để tránh điều đó, bạn cần toán tử bản đồ và chuyển luồng của bạn thành Bộ sưu tập. Vì bạn không thể truy cập vào phần tử trước, trạng thái phải được lưu trữ bên ngoài trong trường cuối cùng. Vì lý do ngắn gọn tôi đã sử dụng Integer thay vì đối tượng của bạn:

List<Integer> sourceList = Arrays.asList(45, 55, 0, 0, 46, 0, 39, 0, 0, 0); 

final Integer[] lastNonZero = new Integer[1]; // stream has no state, so we need a final field to store it 
List<Integer> resultList = sourceList.stream() 
      .peek(integer-> { 
       if (integer!= 0) { 
        lastNonZero[0] = item; 
       } 
      }) 
      .map(integer -> lastNonZero[0]) 
      .collect(Collectors.toList()); 

System.out.println(sourceList); // still the same 
System.out.println(resultList); // prints [45, 55, 55, 55, 46, 46, 39, 39, 39, 39] 

Sử dụng một dòng cho vấn đề của bạn không phải là giải pháp tốt nhất, trừ khi bạn cần một số hoạt động khác như bộ lọc, hoạt động bản đồ khác hoặc loại.

0

Trước hết, bạn không nên đột biến trạng thái trong một lambda. Điều đó nói rằng, bạn có thể sử dụng danh sách tùy chỉnh mở rộng ArrayList và ghi đè các phương thức iterator()spliterator().

Lưu ý rằng điều này đang sử dụng lớp họcPairmà tôi đã bỏ qua ở đây để ngắn gọn.

public class MemoList extends ArrayList<Pair<Integer,MntrRoastDVO>> { 
    private static final long serialVersionUID = -2816896625889263498L; 

    private final List<MntrRoastDVO> list; 

    private MemoList(List<MntrRoastDVO> list) { 
     this.list = list; 
    } 

    public static MemoList of(List<MntrRoastDVO> list) { 
     return new MemoList(Objects.requireNonNull(list)); 
    } 

    @Override 
    public Iterator<Pair<Integer,MntrRoastDVO>> iterator() { 
     Iterator<MntrRoastDVO> it = list.iterator(); 

     return new Iterator<Pair<Integer,MntrRoastDVO>>() { 
      private Integer previous = null; 

      @Override 
      public boolean hasNext() { 
       return it.hasNext(); 
      } 

      @Override 
      public Pair<Integer,MntrRoastDVO> next() { 
       MntrRoastDVO next = it.next(); 
       Pair<Integer,MntrRoastDVO> pair = new Pair<>(previous, next); 

       if (next.getValColor() > 0) { 
        previous = next.getValColor(); 
       } 

       return pair; 
      } 

     }; 
    } 

    @Override 
    public Spliterator<Pair<Integer,MntrRoastDVO>> spliterator() { 
     return Spliterators.spliterator(iterator(), list.size(), Spliterator.SIZED); 
    } 
} 

Sau đó tôi sẽ sử dụng nó như thế này.

public void doWork(List<MntrRoastDVO> res) 
{ 
    MemoList.of(res).stream().forEach(this::setData); 
} 

private void setData(Pair<Integer,MntrRoastDVO> pair) 
{ 
    MntrRoastDVO data = pair.two(); 

    if (data.getValColor() <= 0) 
    { 
     data.setValColor(pair.one()); 
    } 
} 

Lưu ý rằng điều này không được kiểm tra bằng luồng song song. Trong thực tế, tôi gần như chắc chắn nó sẽ không làm việc song song.

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