2015-07-27 32 views
10

Trong Java8

Khi tôi viết mã như:Scala có các lệnh trung gian/thiết bị đầu cuối như Java8 không?

Stream<Integer> xs = Arrays.asList(1, 3, 5, 6, 7, 10).stream(); 
xs.map(x -> x * x).filter (x -> x > 15).forEach(System.out::println); 

suối Java8 được chia thành hai phần; các phép toán trung gian và đầu cuối, trong đó -AFAIK - hành động thực tế (các phép lặp theo dõi) được thực hiện trong các ops đầu cuối, trong khi mỗi op trung gian gắn thêm tên riêng của nó - Áp dụng các lớp bên trong.

Bằng cách này, sẽ chỉ có một lần lặp trong danh sách.

Mẫu mã từ JDK8:

@Override 
@SuppressWarnings("unchecked") 
public final <R> Stream<R> map(Function<? super P_OUT, ? extends R> mapper) { 
    Objects.requireNonNull(mapper); 
    return new StatelessOp<P_OUT, R>(this, StreamShape.REFERENCE, 
           StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) { 
     @Override 
     Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) { 
      return new Sink.ChainedReference<P_OUT, R>(sink) { 
       @Override 
       public void accept(P_OUT u) { 
        downstream.accept(mapper.apply(u)); 
       } 
      }; 
     } 
    }; 
} 

Trong Scala

Khi tôi viết mã như:

val xs = List(1, 3, 5, 6, 7, 10) 
xs map (x => x * x) filter (x => x > 15) foreach (println) 

Tôi đã được một thời gian đọc về nó, nhưng tôi không bao giờ nghe về đó các thuật ngữ rõ ràng hơn nữa, vòng lặp triển khai SDK (sử dụng vòng lặp đệ quy hoặc vòng lặp thông thường) trên mỗi thao tác:

final override def map[B, That](f: A => B)(implicit bf: CanBuildFrom[List[A], B, That]): That = { 
if (bf eq List.ReusableCBF) { 
    if (this eq Nil) Nil.asInstanceOf[That] else { 
    val h = new ::[B](f(head), Nil) 
    var t: ::[B] = h 
    var rest = tail 
    while (rest ne Nil) { 
     val nx = new ::(f(rest.head), Nil) 
     t.tl = nx 
     t = nx 
     rest = rest.tail 
    } 
    h.asInstanceOf[That] 
    } 
} 
else super.map(f) 
} 

Câu hỏi của tôi là:

Chúng ta có thể xem xét việc triển khai Java trên cùng một thứ sẽ nhanh hơn nhiều không. (O (n) trong Java vs O (bội số của n) trong Scala)

Trả lời

11

Java 8 suối là anh em họ ít tính năng hoàn chỉnh của Scala lặp tiết kiệm để có thể tính toán song song.

Nếu bạn không cần tính toán song song (và hầu hết thời gian trên không đáng giá - chỉ dành cho công việc đắt tiền lớn bạn muốn), thì bạn có thể nhận được cùng một loại xử lý với .iterator trong Scala (và sau đó to[Vector] hoặc bất kỳ điều gì bạn muốn ở cuối).

Java 8 luồng được chuyên biệt theo cách thủ công (Scala Iterator không), vì vậy có trường hợp sử dụng chúng nhanh hơn, nhưng không phải do yếu tố không đổi do tái tạo bộ sưu tập trên đường đi - ít nhất, không nếu bạn ném một số .iterator vào đó. (Nếu không có .iterator, bộ sưu tập Scala đánh giá háo hức theo mặc định, bộ sưu tập Java không có tùy chọn đó.)

Các Scala tương đương cho các mã Java 8 bạn đã viết như sau:

val xsi = Array(1, 3, 5, 6, 7, 10).iterator 
xsi.map(x => x*x).filter(_ > 15).foreach(println) 

Không có sự khác biệt trong số các bộ sưu tập được tạo ra ở đây với Scala vs Java.

Có lẽ sẽ là một ý tưởng hay khi áp dụng ngôn ngữ "hoạt động đầu cuối" rất rõ ràng cho tài liệu Iterator của Scala. Các tài liệu luồng Java 8 là tuyệt vời trong đó họ làm cho nó rõ ràng rõ ràng khi bạn đang xây dựng các mô tả của công việc và khi bạn cuối cùng đã làm nó.

Scala cũng cung cấp một lớp Stream rằng memoizes công việc cũ (do đó bạn không cần phải tính toán nó một lần thứ hai nếu bạn tái sử dụng nó), và khác nhau views do đó bạn không phải tạo lại quá trình xử lý chuỗi mỗi lần bạn muốn sử dụng nó. Ví dụ: với bình phương của bạn, bạn có thể

val xsv = Array(1, 3, 5, 6, 7, 10).view 
val xsq = xsv.map(x => x*x) 
xsq.filter(_ > 15).foreach(println) 
xsq.filter(_ < 5).foreach(println) 

trong khi với Java 8 suối xsq sẽ cạn kiệt sau khi hoạt động đầu cuối đầu tiên.

Vì vậy, Scala thực sự làm tất cả mọi thứ (lưu song song) mà Java 8 luồng làm, và khá nhiều hơn một chút bên cạnh, và có một thời gian dài.

Scala cũng có các bộ sưu tập song song, nhưng việc triển khai Java 8 là đủ cao về hiệu suất tại thời điểm này tôi khuyên bạn nên sử dụng chúng trước tiên. Và một lần nữa, nếu chuyên môn hóa thủ công là điều của bạn, Java 8 stream có nó cho Int, Double, và Long, và đó là một chiến thắng hiệu suất lớn. (Lưu ý: ví dụ của bạn, sử dụng asList, không phải là chuyên ngành theo cách thủ công.)

Nhưng nếu bạn chỉ muốn xếp hàng hoạt động và không có phí xây dựng bộ sưu tập trung gian, Scala sẽ thực hiện. Bạn chỉ cần hỏi.

9

Danh sách trong Scala là háo hức, điều đó có nghĩa rằng (như bạn nói) có nhiều lần lặp trên danh sách. Có (ít nhất) hai cách để giải quyết vấn đề này.

Sử dụng một cái nhìn:

xs.view.map(x => x * x).filter(x => x > 15).force 

Hoặc bằng cách chuyển đổi danh sách để một dòng (đó là lười biếng):

xs.toStream.map(x => x * x).filter(x => x > 15) 
+0

Bạn trả lời là đơn giản và tốt, tuy nhiên @Rex Kerr toàn diện hơn. Cảm ơn. –

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