2014-05-01 31 views
43

Tôi đang cố gắng thay đổi một số vòng lặp cho từng lambda forEach() -methods để khám phá các khả năng của các biểu thức lambda. Các followong có vẻ là có thể:Trả lại từ lambda forEach() trong java

ArrayList<Player> playersOfTeam = new ArrayList<Player>();  
for (Player player : players) { 
    if (player.getTeam().equals(teamName)) { 
     playersOfTeam.add(player); 
    } 
} 

Với lambda forEach()

players.forEach(player->{if (player.getTeam().equals(teamName)) {playersOfTeam.add(player);}}); 

Nhưng một trong những công việc doesen't tiếp theo:

for (Player player : players) { 
    if (player.getName().contains(name)) { 
     return player; 
    } 
} 

với lambda

players.forEach(player->{if (player.getName().contains(name)) {return player;}}); 

Liệu có đôi khi hing sai trong cú pháp của dòng cuối cùng hoặc là nó không thể quay trở lại từ forEach() phương pháp?

+0

Tôi không quá quen thuộc với nội bộ của lambdas được nêu ra, nhưng khi tôi đặt câu hỏi cho bản thân mình: "Những gì bạn sẽ trở về từ?", Nghi ngờ ban đầu của tôi sẽ là nó không phải là phương pháp. – Gimby

+1

@Gimby Có, 'return' trong một tuyên bố lambda trả về từ lambda chính nó, không phải từ bất cứ điều gì được gọi là lambda. Việc chấm dứt một luồng sớm ("short-circuiting") sử dụng 'findFirst' như được hiển thị trong câu trả lời [Ian Roberts '] (http://stackoverflow.com/a/23407107/1441122). –

Trả lời

64

return có trở về từ biểu thức lambda thay vì từ phương thức chứa. Thay vì forEach bạn cần phải filter dòng:

players.stream().filter(player -> player.getName().contains(name)) 
     .findFirst().orElse(null); 

Đây filter hạn chế dòng cho những mục phù hợp với vị ngữ, và findFirst sau đó trả về một Optional với mục phù hợp đầu tiên. Điều này có vẻ kém hiệu quả hơn cách tiếp cận vòng lặp, nhưng trên thực tế, findFirst() có thể ngắn mạch - nó không tạo ra toàn bộ luồng được lọc và sau đó trích xuất một phần tử từ nó, thay vào đó nó chỉ lọc bao nhiêu phần tử cần phải tìm ra kết quả phù hợp đầu tiên. Bạn cũng có thể sử dụng findAny() thay vì findFirst() nếu bạn không nhất thiết phải quan tâm đến việc nhận được trình phát phù hợp đầu tiên từ luồng (đã đặt hàng) mà chỉ đơn giản là bất kỳ mục phù hợp nào. Điều này cho phép hiệu quả tốt hơn khi có sự liên quan song song.

+0

Cảm ơn, đó là những gì tôi đang tìm kiếm! Dường như có nhiều điểm mới trong Java8 để khám phá :) – samutamm

+5

Hợp lý, nhưng tôi khuyên bạn không nên sử dụng 'orElse (null)' trên một 'Tùy chọn'. Điểm chính của 'Optional' là cung cấp một cách để chỉ ra sự hiện diện hay vắng mặt của một giá trị thay vì quá tải null (dẫn đến NPE). Nếu bạn sử dụng 'optional.orElse (null)' nó mua lại tất cả các vấn đề với null. Tôi sẽ sử dụng nó chỉ khi bạn không thể sửa đổi người gọi và nó thực sự mong đợi một null. –

+0

@StuartMarks thực sự, sửa đổi kiểu trả về của phương thức thành 'Tùy chọn ' sẽ là một cách tự nhiên hơn để phù hợp với mô hình luồng. Tôi đã chỉ cố gắng để hiển thị như thế nào để nhân đôi hành vi hiện tại bằng cách sử dụng lambdas. –

7

Tôi đề nghị bạn trước tiên hãy cố gắng hiểu Java 8 trong toàn bộ hình ảnh, quan trọng nhất trong trường hợp của bạn, nó sẽ là các luồng, tham chiếu lambdas và phương thức.

Bạn nên không bao giờ chuyển đổi mã hiện tại sang mã Java 8 trên cơ sở từng dòng, bạn nên trích xuất các tính năng và chuyển đổi các tính năng đó.

Những gì tôi được xác định trong trường hợp đầu tiên của bạn là như sau:

  • Bạn muốn thêm các yếu tố của một cơ cấu đầu vào đến đầu ra một danh sách nếu họ phù hợp với một số vị.

Hãy xem cách chúng tôi làm điều đó, chúng ta có thể làm điều đó với những điều sau đây:

List<Player> playersOfTeam = players.stream() 
    .filter(player -> player.getTeam().equals(teamName)) 
    .collect(Collectors.toList()); 

Những gì bạn làm ở đây là:

  1. Rẽ cấu trúc đầu vào của bạn thành một dòng (Tôi giả sử ở đây là loại Collection<Player>, giờ bạn có một số Stream<Player>.
  2. Lọc tất cả các phần tử không mong muốn bằng một số Predicate<Player>, ánh xạ mọi người chơi đến e boolean đúng nếu nó muốn được giữ.
  3. Thu thập các phần tử kết quả trong danh sách, qua Collector, tại đây chúng tôi có thể sử dụng một trong các bộ sưu tập thư viện chuẩn, là Collectors.toList().

cũng này kết hợp hai điểm khác:

  1. Mã chống lại giao diện, do đó, mã chống lại List<E> qua ArrayList<E>.
  2. Sử dụng suy luận kim cương cho thông số loại trong new ArrayList<>(), bạn đang sử dụng Java 8 sau khi tất cả.

Bây giờ vào điểm thứ hai của bạn:

Bạn lại muốn chuyển đổi một cái gì đó của di sản Java để Java 8 mà không nhìn vào bức tranh lớn hơn. Phần này đã được trả lời bởi @IanRoberts, mặc dù tôi nghĩ rằng bạn cần phải làm players.stream().filter(...)... so với những gì ông đề xuất.

2

Nếu bạn muốn trả về một giá trị boolean, sau đó bạn có thể sử dụng một cái gì đó như thế này (nhanh hơn nhiều so với bộ lọc):

players.stream().anyMatch(player -> player.getName().contains(name)); 
Các vấn đề liên quan