ฉันจะสร้างสตรีมจากอาร์เรย์ได้อย่างไร


134

เมื่อใดก็ตามที่ฉันต้องการสร้างสตรีมจากอาร์เรย์ฉันจะทำ

String[] array = {"x1", "x2"};
Arrays.asList(array).stream();

มีวิธีโดยตรงในการสร้างสตรีมจากอาร์เรย์หรือไม่?

คำตอบ:


202

คุณสามารถใช้ Arrays.stream เช่น

Arrays.stream(array);

คุณยังสามารถใช้Stream.ofตามที่ @fge กล่าวไว้ได้ซึ่งมีลักษณะดังนี้

public static<T> Stream<T> of(T... values) {
    return Arrays.stream(values);
}

แต่ทราบStream.of(intArray)จะกลับมาStream<int[]>ในขณะที่Arrays.stream(intArr)จะกลับมาให้คุณผ่านอาร์เรย์ของพิมพ์IntStream int[]ดังนั้นโดยสรุปสำหรับประเภทดั้งเดิมคุณสามารถสังเกตความแตกต่างระหว่าง 2 วิธีเช่น

int[] arr = {1, 2};
Stream<int[]> arr1 = Stream.of(arr);

IntStream stream2 = Arrays.stream(arr); 

เมื่อคุณส่งอาร์เรย์ดั้งเดิมไปยังArrays.streamโค้ดต่อไปนี้จะถูกเรียกใช้

public static IntStream stream(int[] array) {
    return stream(array, 0, array.length);
}

และเมื่อคุณส่งอาร์เรย์ดั้งเดิมไปStream.ofยังรหัสต่อไปนี้จะถูกเรียกใช้

 public static<T> Stream<T> of(T t) {
     return StreamSupport.stream(new Streams.StreamBuilderImpl<>(t), false);
 }

ดังนั้นคุณจะได้รับผลลัพธ์ที่แตกต่างกัน

อัปเดต : ตามที่กล่าวไว้โดยความคิดเห็นของStuart Marksการโอเวอร์โหลดของช่วงย่อยArrays.streamเป็นที่นิยมในการใช้Stream.of(array).skip(n).limit(m)เนื่องจากผลลัพธ์ก่อนหน้านี้ในสตรีม SIZED ในขณะที่หลังไม่ได้ เหตุผลก็คือlimit(m)ไม่ทราบว่าขนาดคือ m หรือน้อยกว่า m ในขณะที่Arrays.streamตรวจสอบช่วงและทราบขนาดที่แน่นอนของสตรีมคุณสามารถอ่านซอร์สโค้ดสำหรับการใช้งานสตรีมที่ส่งคืนได้Arrays.stream(array,start,end) ที่นี่ในขณะที่การใช้งานสตรีมกลับมาStream.of(array).skip().limit()คือ ภายในวิธีนี้


9
คำตอบนี้ดีกว่าเนื่องจากArrays.streamมีกรณีที่โอเวอร์โหลดทั้งหมดสำหรับอาร์เรย์ดั้งเดิม IE Stream.of(new int[]{1,2,3})จะให้คุณStream<int[]>ในขณะที่Arrays.streamจะให้คุณกลับIntStreamซึ่งอาจเป็นสิ่งที่คุณต้องการ ดังนั้น +1
user2336315

3
@ ดิมาเดาว่าเป็นเรื่องของรสนิยม ฉันหมายความว่าดีกว่าในแง่หนึ่งStream.ofอาจทำให้คุณประหลาดใจ (เช่นเมื่อคุณโทรArrays.asListด้วยอาร์เรย์ดั้งเดิมและผู้คนคาดหวังว่าจะได้รับการตอบList<Integer>กลับ) :-)
user2336315

3
Arrays.streamรองรับการสตรีมช่วงของอาร์เรย์ซึ่งIntStream.ofไม่ได้ ในทางตรงกันข้ามStream.ofเป็นทางเลือกที่ดีกว่าถ้าคุณต้องการStream<int[]>ขนาด1...
โฮล

4
@Dima การโอเวอร์โหลดของช่วงย่อยArrays.streamนั้นดีกว่าที่จะใช้Stream.of(array).skip(n).limit(m)เนื่องจากผลลัพธ์เดิมในสตรีม SIZED ในขณะที่หลังไม่ได้ เหตุผลก็คือlimit(m)ไม่ทราบว่ามีขนาดmหรือน้อยกว่าmในขณะที่Arrays.streamตรวจสอบช่วงและทราบขนาดที่แน่นอนของสตรีม
Stuart Marks

6
สำหรับผู้อ่านที่สนใจดูละครเรื่องนี้สรุปให้Arrays.stream(array,start,end)ส่งคืนการStreamดำเนินการที่มีอยู่ที่นี่ในขณะที่Stream.of(array).skip().limit()ส่งกลับการStreamดำเนินการที่อยู่ในวิธีนี้
Stuart Marks

43

ทางเลือกในการแก้ปัญหาของ @ sol4me:

Stream.of(theArray)

จากความแตกต่างระหว่างสิ่งนี้และArrays.stream(): จะสร้างความแตกต่างหากอาร์เรย์ของคุณเป็นประเภทดั้งเดิม ตัวอย่างเช่นหากคุณทำ:

Arrays.stream(someArray)

ที่someArrayเป็นก็จะกลับมาเป็นlong[] ในทางกลับกันจะส่งคืน a ด้วยองค์ประกอบเดียวLongStreamStream.of()Stream<long[]>


1
@Dima แน่นอน แต่ก็Arrays.stream()ใช้ได้เช่นกัน
fge

2
เป็นสตรีมสะดวก! ไม่จำเป็นต้องโทรหา*Stream.of()เมื่อคุณArrays.stream()จัดการกับอาร์เรย์ดั้งเดิม และสำหรับอาร์เรย์ที่ไม่ใช่วัตถุจริงนี่คือ Java ซึ่งเป็นเช่นนี้มาตั้งแต่ 1.0 ดังนั้นจัดการกับมัน การครุ่นคิดเรื่องนี้ไม่ช่วยอะไรเลย
fge

2
@Dima และเป็นของคุณ คุณถือว่าArrays.stream()ไม่สะดวกผมถือว่าสะดวก พูดพอแล้ว.
fge

2
@ ดิมาใช่ฉันพบว่าข้อโต้แย้งของคุณ*Stream.of()สะดวกกว่าที่จะเข้าใจผิด เพราะมันเป็นเรื่องของการตั้งค่า ฉันชอบArrays.stream()สำหรับกรณีเช่นนี้ซึ่งทำให้ผิดเป็นกฎทั่วไปที่Stream.of()สะดวกกว่า (พีชคณิต Peano)
fge

3
@ ดิมา: มันเป็นเรื่องของความชอบ ความแตกต่างนั้นเล็กมากอย่างไม่น่าเชื่อซึ่งมันไม่สำคัญเลย โดยเฉพาะอย่างยิ่ง: ความแตกต่างของตัวละครไม่กี่คืออะไร นำเข้าเพิ่มเติมให้กับแพคเกจภายในห้องสมุดมาตรฐานคืออะไร และจริงๆแล้วการสร้างอาร์เรย์ด้วยตนเองแทนที่จะเป็น varargs overload นั้นไม่มีอะไรเลย
Jeroen Vannevel

15
Stream.of("foo", "bar", "baz")

หรือถ้าคุณมีอาร์เรย์อยู่แล้วคุณสามารถทำได้เช่นกัน

Stream.of(array) 

สำหรับประเภทดั้งเดิมใช้IntStream.ofหรือLongStream.ofอื่น ๆ


สิ่งที่ฉันไม่เข้าใจคือเมื่อint[]สามารถส่งผ่านไปยังวิธีการยอมรับ varargs ทำไมไม่Stream.of(intArray)สร้าง a Stream<Integer>แทนStream<int[]>? นอกจากนี้ยังมีเหตุผลทางเทคนิคใด ๆ ว่าทำไมจึงมีคลาส Stream พิเศษสำหรับดั้งเดิม?
asgs

1
สัตว์ดึกดำบรรพ์ของ Java เป็นสัตว์ประหลาด int[]ไม่เหมือนกับอาร์เรย์อื่น ๆ ไม่ใช่คลาสย่อยของObject[]แต่เป็นคลาสย่อยของObject. ดังนั้นเมื่อคุณผ่านไปStream.ofก็นำมาเป็นพารามิเตอร์และคุณได้รับกระแสของObject int[]นั่นเป็นหนึ่งในเหตุผลที่ต้องมีคลาสพิเศษสำหรับดั้งเดิม - หากคุณไม่ได้สร้างสตรีมจากอาร์เรย์ดั้งเดิมจะค่อนข้างเจ็บปวด อีกเหตุผลหนึ่งคือการเรียนเฉพาะทางมีประสิทธิภาพมากกว่าเนื่องจากไม่จำเป็นต้องเสียObjectค่าใช้จ่ายจากการชกมวย (แปลงintเป็นIntegerเพื่อให้ดูเหมือนวัตถุทั่วไป)
Dima

อาเนื่องจากint[]เป็นObjectก็จะตรงกับวิธีการมากเกินไปและด้วยเหตุนี้มันกลับof(T t) Stream<int[]>ดังนั้นในทางทฤษฎีถ้าไม่มีวิธีนี้เราจะได้รับStream<Integer>ผลตอบแทน? หรืออาจทำให้เกิดข้อผิดพลาดในการคอมไพล์เนื่องจากไม่พบวิธีการจับคู่? เช่นint[]ไม่สามารถถือว่าเป็นT...
asgs

1
ไม่เรายังไม่เข้าใจStream<Integer>เพราะStream.of(t ... T) ยังคงจับคู่แบบเดิม
Dima

0

คุณสามารถทำได้ด้วยวิธีระดับต่ำซึ่งมีตัวเลือกคู่ขนาน:

อัปเดต: ใช้อาร์เรย์เต็มความยาว (ไม่ใช่ความยาว - 1)

/** 
 * Creates a new sequential or parallel {@code Stream} from a
 * {@code Spliterator}.
 *
 * <p>The spliterator is only traversed, split, or queried for estimated
 * size after the terminal operation of the stream pipeline commences.
 *
 * @param <T> the type of stream elements
 * @param spliterator a {@code Spliterator} describing the stream elements
 * @param parallel if {@code true} then the returned stream is a parallel
 *        stream; if {@code false} the returned stream is a sequential
 *        stream.
 * @return a new sequential or parallel {@code Stream}
 *
 * <T> Stream<T> stream(Spliterator<T> spliterator, boolean parallel)
 */

StreamSupport.stream(Arrays.spliterator(array, 0, array.length), true)

0

คุณสามารถใช้ Arrays.stream:

Arrays.stream (อาร์เรย์); 

เพื่อให้แน่ใจว่านี้เป็นชนิดที่การกลับมาของไอน้ำขึ้นอยู่กับประเภทการป้อนข้อมูลอาร์เรย์ของคุณหากString []แล้วกลับStream<String>ถ้าint []ผลตอบแทนแล้วIntStream

เมื่อคุณรู้จักอาร์เรย์ประเภทอินพุตแล้วคุณควรใช้อาร์เรย์เฉพาะเช่นสำหรับประเภทอินพุต int[]

 IntStream.of (อาร์เรย์); 

ส่งคืน Intstream

ในตัวอย่างแรก Java ใช้วิธีoverloadingการค้นหาวิธีการเฉพาะตามประเภทอินพุตในขณะที่ในวินาทีที่คุณรู้จักประเภทอินพุตและเรียกวิธีการเฉพาะแล้ว


0

ไม่ค่อยเห็น แต่นี่เป็นวิธีที่ตรงที่สุด

Stream.Builder<String> builder = Stream.builder();
for( int i = 0; i < array.length; i++ )
  builder.add( array[i] );
Stream<String> stream = builder.build();
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.