Java 8 สตรีมคล้ายกับ RxJava หรือไม่
การกำหนดสตรีม Java 8:
คลาสใน
java.util.stream
แพ็คเกจใหม่มี Stream API เพื่อรองรับการทำงานในรูปแบบการใช้งานในส่วนขององค์ประกอบ
Java 8 สตรีมคล้ายกับ RxJava หรือไม่
การกำหนดสตรีม Java 8:
คลาสใน
java.util.stream
แพ็คเกจใหม่มี Stream API เพื่อรองรับการทำงานในรูปแบบการใช้งานในส่วนขององค์ประกอบ
คำตอบ:
TL; DR : libs การประมวลผลตามลำดับ / สตรีมทั้งหมดจะเสนอ API ที่คล้ายกันมากสำหรับการสร้างไปป์ไลน์ ความแตกต่างอยู่ใน API สำหรับการจัดการหลายเธรดและองค์ประกอบของท่อ
RxJava ค่อนข้างแตกต่างจากสตรีม จากสิ่งต่างๆทั้งหมดของ JDK สิ่งที่ใกล้เคียงกับ rx.Observable มากที่สุดคือjava.util.stream.Collector Stream + CompletableFuture คอมโบ (ซึ่งมีค่าใช้จ่ายในการจัดการกับเลเยอร์ monad พิเศษนั่นคือต้องจัดการกับการแปลงระหว่างStream<CompletableFuture<T>>
และCompletableFuture<Stream<T>>
)
มีความแตกต่างที่สำคัญระหว่าง Observable และ Stream:
Stream#parallel()
แยกลำดับออกเป็นพาร์ติชันObservable#subscribeOn()
และObservable#observeOn()
อย่า; มันยากที่จะเลียนแบบStream#parallel()
พฤติกรรมด้วย Observable ซึ่งครั้งหนึ่งเคยมี.parallel()
วิธีการ แต่วิธีนี้ทำให้เกิดความสับสนมากจน.parallel()
การสนับสนุนถูกย้ายไปยังที่เก็บแยกต่างหากบน github, RxJavaParallel รายละเอียดเพิ่มเติมอยู่ในคำตอบอื่นStream#parallel()
ไม่อนุญาตให้ระบุเธรดพูลที่จะใช้ซึ่งแตกต่างจากวิธี RxJava ส่วนใหญ่ที่ยอมรับ Scheduler ที่เป็นตัวเลือก เนื่องจากสตรีมอินสแตนซ์ทั้งหมดใน JVM ใช้กลุ่ม fork-join เดียวกันการเพิ่ม.parallel()
อาจส่งผลต่อพฤติกรรมในโมดูลอื่นของโปรแกรมของคุณโดยไม่ได้ตั้งใจObservable#interval()
, Observable#window()
และอื่น ๆ อีกมากมาย; ส่วนใหญ่เป็นเพราะ Streams เป็นแบบ pull-based และ upstream ไม่มีการควบคุมเมื่อปล่อยอิลิเมนต์ถัดไป downstreamtakeWhile()
, takeUntil()
); วิธีแก้ปัญหาการใช้Stream#anyMatch()
มี จำกัด : เป็นการดำเนินการของเทอร์มินัลดังนั้นคุณไม่สามารถใช้งานได้มากกว่าหนึ่งครั้งต่อสตรีมObservable#using()
); คุณสามารถห่อ IO สตรีมหรือ mutex กับมันและให้แน่ใจว่าผู้ใช้จะไม่ลืมที่จะปลดปล่อยทรัพยากร - มันจะถูกกำจัดโดยอัตโนมัติเมื่อมีการบอกเลิกสมาชิก สตรีมมีonClose(Runnable)
เมธอด แต่คุณต้องโทรด้วยตนเองหรือผ่านการลองกับทรัพยากร เช่น. คุณต้องจำไว้ว่าไฟล์ # บรรทัด () จะต้องอยู่ใน block ลองกับทรัพยากรRound-up: RxJava แตกต่างจาก Streams อย่างมาก ตัวเลือก RxJava ที่แท้จริงคือการนำไปใช้งานอื่น ๆ ของReactiveStreamsเช่นส่วนที่เกี่ยวข้องของ Akka
ปรับปรุง มีเคล็ดลับในการใช้พูลการเข้าร่วมที่ไม่ใช่ค่าเริ่มต้นสำหรับStream#parallel
ดูเธรดพูลที่กำหนดเองใน Java 8 กระแสขนาน
ปรับปรุง จากข้อมูลทั้งหมดที่กล่าวมานี้อ้างอิงจากประสบการณ์ของ RxJava 1.x ตอนนี้RxJava 2.x อยู่ที่นี่คำตอบนี้อาจจะล้าสมัย
Stream.generate()
และผ่านSupplier<U>
การใช้งานของคุณเองได้เพียงวิธีการง่ายๆเพียงวิธีเดียวที่คุณให้รายการถัดไปในสตรีม มีวิธีอื่นมากมาย หากต้องการสร้างลำดับStream
ที่ขึ้นอยู่กับค่าก่อนหน้านี้อย่างง่ายดายคุณสามารถใช้interate()
วิธีCollection
ได้ทุกstream()
วิธีมีและStream.of()
สร้าง a Stream
จาก varargs หรืออาร์เรย์ ในที่สุดก็ StreamSupport
มีการสนับสนุนสำหรับการสร้างกระแสขั้นสูงมากขึ้นโดยใช้ตัวแยกหรือสำหรับชนิดดั้งเดิมของกระแส
takeWhile()
, takeUntil()
);" - JDK9 มีสิ่งเหล่านี้ผมเชื่อว่าในtakeWhile ()และdropWhile ()
Java 8 Stream และ RxJava ดูคล้ายกันมาก พวกเขามีตัวดำเนินการเหมือนกัน (ตัวกรองแผนที่ flatMap ... ) แต่ไม่ได้สร้างขึ้นสำหรับการใช้งานเดียวกัน
คุณสามารถทำงาน asynchonus โดยใช้ RxJava
ด้วยสตรีม Java 8 คุณจะสำรวจรายการในคอลเล็กชันของคุณ
คุณสามารถทำสิ่งเดียวกันได้ใน RxJava (รายการสำรวจของคอลเลกชัน) แต่เนื่องจาก RxJava เน้นงานที่เกิดขึ้นพร้อมกัน, ... , มันใช้การซิงก์, สลัก, ... ดังนั้นงานเดียวกันโดยใช้ RxJava อาจช้ากว่า ด้วย Java 8 สตรีม
RxJava สามารถนำมาเปรียบเทียบได้CompletableFuture
แต่นั่นสามารถคำนวณได้มากกว่าหนึ่งค่า
parallelStream
รองรับการซิงโครไนซ์ที่คล้ายกันของการสำรวจเส้นทาง / แผนที่ / การกรองอย่างง่าย ๆ
มีความแตกต่างทางด้านเทคนิคและแนวความคิดเล็กน้อยตัวอย่างเช่น Java 8 สตรีมเป็นแบบใช้ครั้งเดียวลำดับแบบซิงโครนัสของค่าในขณะที่ RxJava Observables สามารถสังเกตได้อีกครั้ง RxJava มีวัตถุประสงค์เพื่อ Java 6+ และทำงานบน Android เช่นกัน
Java 8 Streams นั้นใช้การดึง คุณทำซ้ำมากกว่าสตรีม Java 8 ที่บริโภคแต่ละรายการ และมันอาจเป็นกระแสที่ไม่รู้จบ
RXJava มาObservable
จากการพุชแบบเริ่มต้น คุณสมัครเป็นสมาชิก Observable และคุณจะได้รับการแจ้งเตือนเมื่อรายการถัดไปมาถึง ( onNext
) หรือเมื่อสตรีมเสร็จสมบูรณ์ ( onCompleted
) หรือเมื่อเกิดข้อผิดพลาด ( onError
) เพราะObservable
คุณได้รับonNext
, onCompleted
, onError
เหตุการณ์ที่คุณสามารถทำได้ทำงานที่มีประสิทธิภาพบางอย่างเช่นการรวมที่แตกต่างกันObservable
เพื่อหนึ่งใหม่ ( zip
, merge
, concat
) สิ่งอื่นที่คุณสามารถทำได้คือแคชการควบคุมปริมาณ ... และใช้ API เดียวกันมากขึ้นหรือน้อยลงในภาษาต่าง ๆ (RxJava, RX ใน C #, RxJS, ... )
โดยค่าเริ่มต้น RxJava เป็นเธรดเดียว นอกจากว่าคุณจะเริ่มใช้ Schedulers ทุกอย่างจะเกิดขึ้นในเธรดเดียวกัน
คำตอบที่มีอยู่นั้นครอบคลุมและถูกต้อง แต่ไม่มีตัวอย่างที่ชัดเจนสำหรับผู้เริ่มต้น อนุญาตให้ฉันวางรูปธรรมหลังคำเช่น "push / pull-based" และ "re-observable" หมายเหตุ : ฉันเกลียดคำนี้Observable
(เป็นสายน้ำเพื่อประโยชน์ของสวรรค์) ดังนั้นจะอ้างถึงกระแส J8 กับ RX
พิจารณารายการจำนวนเต็ม
digits = [1,2,3,4,5]
สตรีม J8 เป็นเครื่องมือในการปรับเปลี่ยนคอลเลกชัน ตัวอย่างเช่นตัวเลขที่สามารถแยกเป็น
evens = digits.stream().filter(x -> x%2).collect(Collectors.toList())
นี่คือแผนที่ของ Python , ตัวกรอง, การลด , การเพิ่มที่ดีมาก (และเกินกำหนดนาน) ไปยัง Java แต่จะเกิดอะไรขึ้นถ้าตัวเลขไม่ได้ถูกเก็บไว้ล่วงหน้า - จะเกิดอะไรขึ้นถ้าตัวเลขนั้นกำลังถูกสตรีมเข้ามาในขณะที่แอพกำลังทำงานอยู่ - เราจะกรองเลขคู่นั้นได้แบบเรียลไทม์ได้หรือไม่
ลองนึกภาพกระบวนการเธรดที่แยกต่างหากกำลังส่งออกจำนวนเต็มแบบสุ่มในขณะที่แอปกำลังทำงาน ( ---
หมายถึงเวลา)
digits = 12345---6------7--8--9-10--------11--12
ใน RX even
สามารถตอบสนองต่อแต่ละหลักใหม่และใช้ตัวกรองแบบเรียลไทม์
even = -2-4-----6---------8----10------------12
ไม่จำเป็นต้องเก็บรายการอินพุตและเอาต์พุต หากคุณต้องการรายการผลลัพธ์ก็ไม่มีปัญหาที่สามารถสตรีมได้เช่นกัน ในความเป็นจริงทุกอย่างเป็นกระแส
evens_stored = even.collect()
นี่คือเหตุผลที่คำเช่น "ไร้สัญชาติ" และ "หน้าที่" เกี่ยวข้องกับ RX มากกว่า
RxJava มีความสัมพันธ์อย่างใกล้ชิดกับความคิดริเริ่มของสตรีมปฏิกิริยาและพิจารณาว่าตนเองเป็นการนำไปใช้อย่างง่ายของ API ปฏิกิริยาสตรีม (เช่นเมื่อเทียบกับการดำเนินการสตรีม Akka ) ความแตกต่างที่สำคัญคือลำธารที่ตอบสนองได้รับการออกแบบมาให้สามารถรับมือกับแรงกดดันด้านหลังได้ แต่ถ้าคุณดูที่หน้าลำธารที่มีปฏิกิริยาคุณจะได้รับแนวคิด พวกเขาอธิบายเป้าหมายของพวกเขาสวยดีและลำธารยังมีความสัมพันธ์อย่างใกล้ชิดกับแถลงการณ์ปฏิกิริยา
ชวา 8 ลำธารจะสวยมากการดำเนินงานของคอลเลกชันมากมายที่สวยคล้ายกับScala สตรีมหรือหมายเลขขี้เกียจ Clojure
Java 8 Streams เปิดใช้งานการประมวลผลคอลเลกชันขนาดใหญ่อย่างมีประสิทธิภาพในขณะที่ใช้ประโยชน์จากสถาปัตยกรรมแบบมัลติคอร์ ในทางตรงกันข้าม RxJava ถูกเธรดเดี่ยวโดยค่าเริ่มต้น (ไม่มี Schedulers) ดังนั้น RxJava จะไม่ใช้ประโยชน์จากเครื่องมัลติคอร์เว้นแต่ว่าคุณใช้รหัสนั้นเอง