Константин
ระดับ

สตรีม API

เผยแพร่ในกลุ่ม
สตรีม API - 1

สตรีม API คืออะไร

Stream API เป็นวิธีใหม่ในการทำงานกับโครงสร้างข้อมูลในรูปแบบการทำงาน Stream API (คำอธิบายวิธีที่โปรแกรมคอมพิวเตอร์ตัวหนึ่งสามารถสื่อสารกับโปรแกรมอื่น) ถือเป็นกระแสข้อมูลหลัก คำว่า "thread" นั้นค่อนข้างคลุมเครือในการเขียนโปรแกรมโดยทั่วไปและโดยเฉพาะใน Java
สตรีม API - 1
ด้วยการถือกำเนิดของ Java 8 ทำให้ Stream API ช่วยให้โปรแกรมเมอร์สามารถเขียนสิ่งที่ก่อนหน้านี้ใช้โค้ดหลายบรรทัดได้สั้นมากขึ้น กล่าวคือ เพื่อทำให้การทำงานกับชุดข้อมูลง่ายขึ้น โดยเฉพาะเพื่อลดความซับซ้อนในการกรอง การเรียงลำดับ และการดำเนินการจัดการข้อมูลอื่นๆ หากคุณไม่มีการดำเนินการระหว่างกลาง คุณสามารถและควรทำโดยไม่มีสตรีมบ่อยครั้ง ไม่เช่นนั้นโค้ดจะซับซ้อนกว่าไม่มีสตรีม
สตรีม API - 2
ฉันควรเริ่มจากตรงไหนดี? จากการสร้าง Stream instance ซึ่งขึ้นอยู่กับการรวบรวม อาร์เรย์ หรือวิธีการที่เราต้องการ และตำแหน่งที่จะดึงข้อมูลตามลำดับ:
List<String> list = new ArrayList<String>();
       list.add("One");
       list.add("Two");
       list.add("Three");
       list.add("Four");
       list.add("Five");
       list.add("Six");
       list.add("Seven");
       list.add("Eight");
       list.add("Nine");
       list.add("Ten");
       Stream stream = list.stream();
ตามที่กล่าวไว้ข้างต้น Stream API ช่วยให้คุณสามารถลดจำนวนบรรทัดของโค้ดได้ ตัวอย่างที่มีกระแส:
IntStream.of(50, 60, 70, 80, 90, 100, 110, 120).filter(x -> x < 90).map(x -> x + 10)
.limit(3).forEach(System.out::print);
ตัวอย่างที่ไม่มีเธรด:
int[] arr = {50, 60, 70, 80, 90, 100, 110, 120
	int count = 0;
	for (int x : arr) {
	    if (x >= 90) continue;
	    x += 10;
	    count++;
	    if (count > 3) break;
	    System.out.print(x);
	}
วิธีที่เป็นไปได้ในการสร้างสตรีม:
สตรีม API - 3
  • สตรีมว่างเปล่า:Stream.empty()
  • สตรีมจากรายการ:list.stream()
  • สตรีมจากแผนที่:map.entrySet().stream()
  • สตรีมจากอาเรย์:Arrays.stream(array)
  • สตรีมจากองค์ประกอบที่ระบุ:Stream.of("1", "2", "3")
ต่อไปก็มีสิ่งที่เรียกว่า Operators (โดยพื้นฐานแล้วเป็นวิธีการของคลาส Stream) Operators สามารถแบ่งออกเป็น 2 กลุ่ม:
  • ระดับกลาง (เรียกอีกอย่างว่า "ขี้เกียจ") - ประมวลผลองค์ประกอบที่เข้ามาและส่งคืนสตรีม อาจมีตัวดำเนินการระดับกลางจำนวนมากในห่วงโซ่การประมวลผลองค์ประกอบ
  • เทอร์มินัล (“เทอร์มินัล” หรือที่เรียกว่า “กระตือรือร้น”) - ประมวลผลองค์ประกอบและยุติสตรีม ดังนั้นจึงมีผู้ดำเนินการเทอร์มินัลได้เพียงคนเดียวในห่วงโซ่
ตัวอย่าง:
1.List<String> list = new ArrayList<String>();
2.list.add("One");11.list.add("Ten");
12.Stream stream = list.stream();
13.stream.filter(x-> x.toString().length() == 3).forEach(System.out::println);
เกิดอะไรขึ้นที่นี่:
  • 1 - สร้างรายการlist;
  • 2-11 - กรอกข้อมูลการทดสอบ
  • 12 - สร้างวัตถุStream;
  • 13 - วิธีการfilter(ตัวกรอง) - ตัวดำเนินการระดับกลางxเท่ากับองค์ประกอบหนึ่งของคอลเลกชันสำหรับการแจงนับ (เช่นเดียวกับfor each) และหลังจาก -> เราระบุว่าคอลเลกชันของเราถูกกรองอย่างไร และเนื่องจากนี่คือตัวดำเนินการระดับกลาง คอลเลกชันที่กรองจึงไปเพิ่มเติมที่วิธีการ ซึ่งforEachในทางกลับกันคือเทอร์มินัล (สุดท้าย) อะนาล็อกของการแจงนับfor each(นิพจน์System.out::printlnย่อมาจาก: x-> System.out.println(x))ซึ่งจะผ่านองค์ประกอบทั้งหมดของคอลเลกชันที่ส่งผ่านไปและแสดง)
สตรีม API - 5
ประเด็นสำคัญ:
  • การประมวลผลจะไม่เริ่มจนกว่าจะมีการเรียกตัวดำเนินการเทอร์มินัล list.stream().filter(s -> s > 5)(จะไม่รับองค์ประกอบเดียวจากรายการ)
  • อินสแตนซ์ของสตรีมไม่สามารถใช้งานได้มากกว่าหนึ่งครั้ง =( ;
  • สตรีม API - 6

    ดังนั้นทุกครั้งที่มีรายการใหม่:

    list.stream().filter(x-> x.toString().length() == 3).forEach(System.out::println);
    list.stream().forEach(x -> System.out.println(x));
  • สามารถมีตัวดำเนินการระดับกลางได้หลายตัวที่ถูกเรียกในสตรีมเดียว ในขณะที่มีตัวดำเนินการเทอร์มินัลเพียงตัวเดียว:

    stream.filter(x-> x.toString().length() == 3).map(x -> x + " - the length of the letters is three").forEach(x -> System.out.println(x));
ต่อไป มาดูตัวดำเนินการระดับกลางบางตัว:
สตรีม API - 7
  • filter(Predicate predicate)กรองสตรีมโดยส่งเฉพาะองค์ประกอบที่ผ่านเงื่อนไข (เพรดิเคตเป็นอินเทอร์เฟซการทำงานในตัวที่เพิ่มให้กับแพ็คเกจใน Java SE 8 java.util.functionตรวจสอบค่าสำหรับ " true " และ " false ");
  • map(Function mapper)ทำให้สามารถสร้างฟังก์ชันที่เราจะเปลี่ยนแต่ละองค์ประกอบและข้ามไปเพิ่มเติมได้ (อินเทอร์เฟซการทำงานFunction<T,R>แสดงถึงฟังก์ชันการเปลี่ยนจากวัตถุประเภท T ไปเป็นวัตถุประเภท R)
  • flatMap(Function<T, Stream<R>> mapper)- เช่นเดียวกับในกรณีของmapพวกมันจะถูกใช้เพื่อแปลงเป็นสตรีมดั้งเดิม
ตัวอย่างเช่น เมื่อทำงานกับอาร์เรย์ของสตรีม (อาร์เรย์ รายการ และอื่นๆ) ระบบจะแปลงสตรีมเหล่านั้นให้เป็นสตรีมเดียว (อาร์เรย์ รายการ และอื่นๆ [stream1,stream2,stream3,stream4] => stream:
String[] array = {"Java", "Ruuuuussshhh"};
Stream<String> streamOfArray = Arrays.stream(array);
streamOfArray.map(s->s.split("")) //Convert the word to an array of letters
        .flatMap(Arrays::stream).distinct() //aligns each generated thread into a single thread
        .collect(Collectors.toList()).forEach(System.out::println);
ในขณะที่mapแปลงเป็นรายการเธรด ( <Stream>เธรดที่แม่นยำยิ่งขึ้น) [stream1,stream2,stream3,stream4] =>Stream.of(stream1,stream2,stream3,stream4):
String[] array = {"Java", "Ruuuuussshhh"};
Stream<String> streamOfArray = Arrays.stream(array);
streamOfArray.map(s->s.split("")) //Convert the word to an array of letters
        .map(Arrays::stream).distinct() //Make the array into a separate thread
        .collect(Collectors.toList()).forEach(System.out::println);
ข้อแตกต่างอีกประการหนึ่งเมื่อเปรียบเทียบกับmapคุณสามารถแปลงองค์ประกอบหนึ่งให้เป็นศูนย์ หรือหนึ่งรายการหรือหลายรายการก็ได้ ในการแปลงองค์ประกอบหนึ่งให้เป็นองค์ประกอบศูนย์ คุณต้องส่งกลับnullหรือสตรีมว่างเปล่า หากต้องการแปลงเป็นองค์ประกอบเดียว คุณจะต้องส่งคืนสตรีมจากองค์ประกอบหนึ่ง เช่นStream.of(x)ผ่าน หากต้องการส่งคืนองค์ประกอบหลายรายการ คุณสามารถสร้างสตรีมด้วยองค์ประกอบเหล่านี้ด้วยวิธีใดก็ได้ วิธี flatMap เดียวกัน แต่สำหรับ Double, Integer และ Long:
  • flatMapToDouble (ตัวทำแผนที่ฟังก์ชัน)
  • flatMapToInt (ตัวทำแผนที่ฟังก์ชัน)
  • flatMapToLong (ตัวทำแผนที่ฟังก์ชัน)
และอีกตัวอย่างสำหรับการเปรียบเทียบ flatMap:
Stream.of(2, 3, 0, 1, 3)
        .flatMapToInt(x -> IntStream.range(0, x))
        .forEach(System.out::print);// 010120012
  • IntStream.range(0,x) – ส่งออกองค์ประกอบตั้งแต่ 0 (รวม) ถึง x (ไม่รวม) ไปยังสตรีม

    แผนที่:

    Stream.of(2, 3, 0, 1, 3)
            .map(x -> IntStream.range(0, x))
            .forEach(System.out::print);//list of streams (streams);
  • ขีดจำกัด(long maxSize) – จำกัดสตรีมด้วยจำนวนองค์ประกอบ:

    stream.limit(5).forEach(x -> System.out.println(x));
  • ข้าม(ยาว n) – ข้ามองค์ประกอบ n:

    stream.skip(3).forEach(x -> System.out.println(x));
  • เรียงลำดับ()

  • sorted(ตัวเปรียบเทียบ) – เรียงลำดับสตรีม (เรียงลำดับเหมือน TreeMap):

    stream.sorted().forEach(x -> System.out.println(x));
  • แตกต่าง() - ตรวจสอบสตรีมเพื่อดูเอกลักษณ์ขององค์ประกอบ (ลบการซ้ำซ้อนขององค์ประกอบ)

  • dropWhile(เพรดิเคตเพรดิเคต) - ข้ามองค์ประกอบที่ตรงตามเงื่อนไข (ปรากฏใน java 9, อินเทอร์เฟซการทำงานของเพรดิเคต<T> จะตรวจสอบว่าตรงตามเงื่อนไขที่กำหนดหรือไม่ หากเป็นไปตามนั้น จริง จะถูกส่งกลับ นิพจน์แลมบ์ดารับอ็อบเจ็กต์ของ พิมพ์ T เป็นพารามิเตอร์:

    Predicate<Integer> isPositive = x -> x > 0;
           System.out.println(isPositive.test(3)); // true
           System.out.println(isPositive.test(-9)); // false
ผู้ประกอบการเทอร์มินัล:
สตรีม API - 8
  • forEach(Consumer action) – คล้ายคลึงกับ for Each (Consumer<T> ดำเนินการบางอย่างกับอ็อบเจ็กต์ประเภท T โดยไม่ส่งคืนสิ่งใด)

  • count() – ส่งกลับจำนวนองค์ประกอบสตรีม:

    System.out.println(stream.count());

  • collect(Collector collector) – วิธีการรวบรวมองค์ประกอบทั้งหมดลงในรายการ ชุดหรือคอลเลกชันอื่น ๆ จัดกลุ่มองค์ประกอบตามเกณฑ์บางอย่าง รวมทุกอย่างไว้ในสตริง ฯลฯ:

    List<String> list = Stream.of(One,Two,Three).collect(Collectors.toList());
  • collect(Supplier supplier, BiConsumer accumulator, BiConsumer combiner)— เช่นเดียวกับ มีcollect(collector)เพียงพารามิเตอร์เท่านั้นที่ถูกแจกแจงเพื่อความสะดวก ( supplierจัดหาวัตถุใหม่ (คอนเทนเนอร์) เช่นnew ArrayList()เพิ่มaccumulatorองค์ประกอบลงในคอนเทนเนอร์combinerรวมส่วนของสตรีมเข้าด้วยกัน)

  • ลด(Tเอกลักษณ์, ตัวสะสม BinaryOperator) - แปลงองค์ประกอบทั้งหมดของสตรีมให้เป็นวัตถุเดียว (คำนวณผลรวมขององค์ประกอบทั้งหมดหรือค้นหาองค์ประกอบขั้นต่ำ) ก่อนอื่นให้นำวัตถุidentityและองค์ประกอบแรกของสตรีมไปใช้ฟังก์ชันaccumulatorและidentityกลายเป็น ผลลัพธ์ของมัน จากนั้นทุกอย่างจะดำเนินต่อไปสำหรับองค์ประกอบที่เหลือ

    int sum = Stream.of(1, 2, 3, 4, 5).reduce(10, (acc, x) -> acc + x);// = 25
  • reduce(BinaryOperator accumulator)— วิธีการเดียวกับข้างต้น แต่ไม่มีวิธีเริ่มต้นidentityมันเป็นองค์ประกอบแรกของสตรีม

    Optional min(Comparator comparator)
    ตัวเลือกสูงสุด (ตัวเปรียบเทียบ) จะค้นหาองค์ประกอบขั้นต่ำ/สูงสุดตามตัวเปรียบเทียบที่ส่งผ่าน

  • findFirst()– ดึงองค์ประกอบแรกของสตรีมออกมา:

    Stream.of(1, 2, 3, 4, 9).findFirst();
  • allMatch(Predicate predicate)— คืนค่าเป็นจริงหากองค์ประกอบทั้งหมดของสตรีมตรงตามเงื่อนไข หากพบองค์ประกอบใดๆ ซึ่งผลลัพธ์ของการเรียกใช้ฟังก์ชันเพรดิเคตเป็นfalseตัวดำเนินการจะหยุดการสแกนองค์ประกอบและส่งคืนค่าfalse :

    Stream.of(1, 2, 3, 4, 9).allMatch(x -> x <= 7);//false
  • anyMatch(Predicate predicate)— จะคืนค่าเป็นจริงหากองค์ประกอบสตรีมอย่างน้อยหนึ่งองค์ประกอบตรงตามเงื่อนไขpredicate:

    Stream.of(1, 2, 3, 4, 9).anyMatch(x -> x >= 7);//true
  • noneMatch(Predicate predicate)— จะคืนค่าเป็นจริงถ้าผ่านองค์ประกอบทั้งหมดของสตรีมแล้ว ไม่มีองค์ประกอบใดที่ตรงตามเงื่อนไขpredicate:

    Stream.of(1, 2, 3, 4, 9).noneMatch(x -> x >= 7);//false
และในที่สุดฉันก็อยากจะดูวิธีการบางอย่างCollectors:
  • toList()— รวบรวมองค์ประกอบเป็นList:

    List<Integer> list = Stream.of(99, 2, 3).collect(Collectors.toList());
  • toSet()— รวบรวมองค์ประกอบเป็นชุด:

    Set<Integer> set = Stream.of(99, 2, 3).collect(Collectors.toSet());
  • counting()— นับจำนวนองค์ประกอบ:

    Long count = Stream.of("1", "2", "3", "4").collect(Collectors.counting());
  • joining()

  • joining(CharSequence delimiter)

  • joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix)— รวบรวมองค์ประกอบเป็นบรรทัดเดียว นอกจากนี้ คุณยังสามารถระบุตัวคั่น รวมถึงคำนำหน้าและส่วนต่อท้ายสำหรับลำดับทั้งหมดได้:

    String a = Stream.of("s", "u" ,"p", "e", "r").collect(Collectors.joining());
           System.out.println(a); // super
    
           String b = Stream.of("s", "u", "p", "e", "r").collect(Collectors.joining("-"));
           System.out.println(b); // s-u-p-e-r
    
           String c = Stream.of("s", "u", "p", "e", "r").collect(Collectors.joining(" -> ", "[ ", " ]"));
           System.out.println(c);  // [ s -> u -> p -> e -> r ]
  • summingInt(ToIntFunction mapper)

  • summingLong(ToLongFunction mapper)

  • summingDouble(ToDoubleFunction mapper)- ตัวสะสมที่แปลงวัตถุเป็น int/long/double และคำนวณผลรวม

ลิงค์ที่เป็นประโยชน์: PS. อย่าอายที่จะกดไลค์เรานะ ^ : ^
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION