จำกัด กระแสโดยเพรดิเคต


187

มีการดำเนินการสตรีม Java 8 ที่ จำกัด (อาจไม่มีที่สิ้นสุด) Streamจนกว่าองค์ประกอบแรกจะไม่ตรงกับภาคแสดงหรือไม่?

ใน Java 9 เราสามารถใช้takeWhileตามตัวอย่างด้านล่างเพื่อพิมพ์ตัวเลขทั้งหมดที่น้อยกว่า 10

IntStream
    .iterate(1, n -> n + 1)
    .takeWhile(n -> n < 10)
    .forEach(System.out::println);

เนื่องจากไม่มีการดำเนินการดังกล่าวใน Java 8 วิธีที่ดีที่สุดในการนำไปใช้ในทางทั่วไปคืออะไร?


1
ข้อมูลที่มีประโยชน์อาจเป็นไปได้ที่: stackoverflow.com/q/19803058/248082
nobeh

ที่เกี่ยวข้อง: เทียบเท่ากับ Scala dropWhile
Charlie

ฉันสงสัยว่าสถาปนิกสามารถผ่าน "สิ่งที่เราสามารถใช้เพื่อ" โดยไม่ต้องทำงานใน usecase นี้ ในฐานะของ Java 8 Streams มีประโยชน์สำหรับโครงสร้างข้อมูลจริงเท่านั้น: - /
Thorbjørn Ravn Andersen


ด้วย Java 9 มันจะง่ายกว่าในการเขียนIntStream.iterate(1, n->n<10, n->n+1).forEach(System.out::print);
Marc Dzaebel

คำตอบ:


81

การดำเนินการดังกล่าวควรจะเป็นไปได้ด้วย Java 8 Streamแต่ไม่สามารถทำได้อย่างมีประสิทธิภาพ - ตัวอย่างเช่นคุณไม่สามารถทำการขนานการดำเนินการดังกล่าวได้เนื่องจากคุณต้องดูองค์ประกอบตามลำดับ

API ที่ไม่ได้ให้เป็นวิธีที่ง่ายที่จะทำ แต่สิ่งที่อาจจะเป็นวิธีที่ง่ายที่สุดคือการใช้Stream.iterator()ห่อIteratorจะมี "ใช้เวลาขณะที่" การดำเนินงานและจากนั้นกลับไปแล้วSpliterator Streamหรือ - อาจ - ปิดส่วนท้ายSpliteratorแม้ว่าจะไม่สามารถแยกได้อีกต่อไปในการนำไปใช้นี้

นี่คือการดำเนินการทดสอบของtakeWhileบนSpliterator:

static <T> Spliterator<T> takeWhile(
    Spliterator<T> splitr, Predicate<? super T> predicate) {
  return new Spliterators.AbstractSpliterator<T>(splitr.estimateSize(), 0) {
    boolean stillGoing = true;
    @Override public boolean tryAdvance(Consumer<? super T> consumer) {
      if (stillGoing) {
        boolean hadNext = splitr.tryAdvance(elem -> {
          if (predicate.test(elem)) {
            consumer.accept(elem);
          } else {
            stillGoing = false;
          }
        });
        return hadNext && stillGoing;
      }
      return false;
    }
  };
}

static <T> Stream<T> takeWhile(Stream<T> stream, Predicate<? super T> predicate) {
   return StreamSupport.stream(takeWhile(stream.spliterator(), predicate), false);
}

8
ในทางทฤษฎีการทำคู่ขนานขณะที่สถานะไร้สัญชาตินั้นง่าย ประเมินสภาพในแบทช์แบบขนาน (สมมติว่าเพรดิเคตไม่ได้โยนหรือมีผลข้างเคียงหากดำเนินการเพิ่มอีกสองสามครั้ง) ปัญหาเกิดขึ้นในบริบทของการย่อยสลายแบบเรียกซ้ำ (fork / join framework) ที่ Streams ใช้ จริงๆแล้วมันเป็นสตรีมที่ไม่มีประสิทธิภาพอย่างน่ากลัว
Aleksandr Dubinsky

91
สตรีมจะดีขึ้นมากหากพวกเขาไม่ได้หมกมุ่นอยู่กับความเท่าเทียมแบบอัตโนมัติ จำเป็นต้องใช้ความเท่าเทียมกันในสถานที่เพียงไม่กี่แห่งที่สามารถใช้ Streams นอกจากนี้หาก Oracle ใส่ใจในเรื่องประสิทธิภาพเป็นอย่างมากพวกเขาอาจทำให้ JVM JIT มีความเป็นอัตโนมัติและได้รับประสิทธิภาพที่ยอดเยี่ยมยิ่งขึ้นโดยไม่ต้องรบกวนนักพัฒนา ทีนี้มันคือการขนานแบบอัตโนมัติที่ถูกต้อง
Aleksandr Dubinsky

คุณควรอัปเดตคำตอบนี้ทันทีที่มีการเปิดตัว Java 9
Radiodef

4
ไม่ @Radiodef คำถามถามเฉพาะสำหรับโซลูชัน Java 8
Renato Back

145

การดำเนินงานtakeWhileและdropWhileได้รับการเพิ่มใน JDK 9 โค้ดตัวอย่างของคุณ

IntStream
    .iterate(1, n -> n + 1)
    .takeWhile(n -> n < 10)
    .forEach(System.out::println);

จะทำงานตรงตามที่คุณคาดหวังไว้เมื่อรวบรวมและทำงานภายใต้ JDK 9

JDK 9 เปิดตัวแล้ว สามารถดาวน์โหลดได้ที่นี่: http://jdk.java.net/9/


3
ลิงก์โดยตรงไปยังเอกสารตัวอย่างสำหรับ JDK9 สตรีมด้วยtakeWhile/ dropWhile: download.java.net/jdk9/docs/api/java/util/stream/Stream.html
Miles

1
มีเหตุผลใดที่พวกเขาถูกเรียกtakeWhileและdropWhileมากกว่าlimitWhileและskipWhileเพื่อความสอดคล้องกับ API ที่มีอยู่หรือไม่
Lukas Eder

10
@ LukasEder takeWhileและdropWhileค่อนข้างแพร่หลายเกิดขึ้นใน Scala, Python, Groovy, Ruby, Haskell และ Clojure ความไม่สมดุลกับskipและlimitเป็นโชคร้าย บางทีskipและlimitควรได้รับการเรียกdropและสิ่งtakeเหล่านี้ไม่ใช่สิ่งที่เข้าใจง่ายเว้นแต่คุณจะคุ้นเคยกับแฮสเค็ลล์อยู่แล้ว
Stuart Marks

3
@ StuartMarks: ฉันเข้าใจdropXXXและtakeXXXเป็นคำศัพท์ที่นิยมมากขึ้น แต่ฉันสามารถอยู่กับ SQL-esque limitXXXและskipXXXส่วนตัวได้มากกว่า ฉันพบความไม่สมดุลใหม่นี้ทำให้สับสนมากกว่าทางเลือกของคำศัพท์ ... :) (btw: Scala ยังมีdrop(int)และtake(int))
Lukas Eder

1
ใช่ให้ฉันเพิ่งอัพเกรดเป็น Jdk 9 ในการผลิต devs จำนวนมากยังคงอยู่ใน Jdk8 คุณลักษณะดังกล่าวควรรวมอยู่ใน Streams ตั้งแต่เริ่มต้น
wilmol

50

allMatch()เป็นฟังก์ชั่นลัดวงจรดังนั้นคุณสามารถใช้เพื่อหยุดการประมวลผล ข้อเสียเปรียบหลักคือคุณต้องทำการทดสอบสองครั้ง: หนึ่งครั้งเพื่อดูว่าคุณควรดำเนินการหรือไม่และอีกครั้งเพื่อดูว่าจะทำต่อไปหรือไม่

IntStream
    .iterate(1, n -> n + 1)
    .peek(n->{if (n<10) System.out.println(n);})
    .allMatch(n->n < 10);

5
นี้ดูเหมือน unintuitive กับผมในตอนแรก (ชื่อวิธีการ) แต่เอกสารยืนยันว่าStream.allMatch()เป็นดำเนินการลัดวงจรสั้น IntStream.iterate()ดังนั้นนี้จะเสร็จสมบูรณ์แม้ในกระแสไม่มีที่สิ้นสุดเช่น แน่นอนว่าเมื่อมองย้อนกลับไปนี่เป็นการปรับปรุงที่เหมาะสม
Bailey Parker

3
นี้เป็นที่เรียบร้อย peekแต่ผมไม่คิดว่ามันจะสื่อสารได้เป็นอย่างดีว่าเป็นความตั้งใจที่ร่างกายของ หากฉันพบมันในเดือนหน้าฉันจะใช้เวลาสักครู่เพื่อสงสัยว่าทำไมโปรแกรมเมอร์ก่อนที่ฉันจะตรวจสอบว่าถ้าallMatchไม่สนใจคำตอบ
Joshua Goldberg

10
ข้อเสียของโซลูชันนี้คือส่งคืนบูลีนดังนั้นคุณจึงไม่สามารถรวบรวมผลลัพธ์ของสตรีมได้ตามปกติ
neXus

35

ในฐานะที่เป็นติดตามเพื่อตอบ @StuartMarks ห้องสมุดStreamExของฉันมีการtakeWhileดำเนินการที่เข้ากันได้กับการใช้งาน JDK-9 ปัจจุบัน เมื่อทำงานภายใต้ JDK-9 มันจะมอบให้กับการใช้งาน JDK ( MethodHandle.invokeExactซึ่งเร็วมาก ๆ ) เมื่อทำงานภายใต้ JDK-8 การใช้งาน "โพลีฟิล" จะถูกนำมาใช้ ดังนั้นการใช้ห้องสมุดของฉันปัญหาสามารถแก้ไขได้ดังนี้:

IntStreamEx.iterate(1, n -> n + 1)
           .takeWhile(n -> n < 10)
           .forEach(System.out::println);

ทำไมคุณไม่นำไปใช้กับคลาส StreamEx
Someguy

@Someguy ฉันใช้มัน
Tagir Valeev

14

takeWhileเป็นหนึ่งในฟังก์ชั่นที่มีให้โดยห้องสมุด protonpack

Stream<Integer> infiniteInts = Stream.iterate(0, i -> i + 1);
Stream<Integer> finiteInts = StreamUtils.takeWhile(infiniteInts, i -> i < 10);

assertThat(finiteInts.collect(Collectors.toList()),
           hasSize(10));

11

อัปเดต: Java 9 Streamมาพร้อมกับวิธีการtakeWhile

ไม่ต้องการแฮ็กหรือการแก้ปัญหาอื่น ๆ แค่ใช้มัน!


ฉันแน่ใจว่าสิ่งนี้สามารถปรับปรุงได้อย่างมากเมื่อ: (ใครบางคนสามารถทำให้มันปลอดภัยเธรด)

Stream<Integer> stream = Stream.iterate(0, n -> n + 1);

TakeWhile.stream(stream, n -> n < 10000)
         .forEach(n -> System.out.print((n == 0 ? "" + n : "," + n)));

แฮ็คอย่างแน่นอน ... ไม่สง่างาม - แต่ใช้งานได้ ~: D

class TakeWhile<T> implements Iterator<T> {

    private final Iterator<T> iterator;
    private final Predicate<T> predicate;
    private volatile T next;
    private volatile boolean keepGoing = true;

    public TakeWhile(Stream<T> s, Predicate<T> p) {
        this.iterator = s.iterator();
        this.predicate = p;
    }

    @Override
    public boolean hasNext() {
        if (!keepGoing) {
            return false;
        }
        if (next != null) {
            return true;
        }
        if (iterator.hasNext()) {
            next = iterator.next();
            keepGoing = predicate.test(next);
            if (!keepGoing) {
                next = null;
            }
        }
        return next != null;
    }

    @Override
    public T next() {
        if (next == null) {
            if (!hasNext()) {
                throw new NoSuchElementException("Sorry. Nothing for you.");
            }
        }
        T temp = next;
        next = null;
        return temp;
    }

    public static <T> Stream<T> stream(Stream<T> s, Predicate<T> p) {
        TakeWhile tw = new TakeWhile(s, p);
        Spliterator split = Spliterators.spliterator(tw, Integer.MAX_VALUE, Spliterator.ORDERED);
        return StreamSupport.stream(split, false);
    }

}

8

คุณสามารถใช้ java8 + rxjava

import java.util.stream.IntStream;
import rx.Observable;


// Example 1)
IntStream intStream  = IntStream.iterate(1, n -> n + 1);
Observable.from(() -> intStream.iterator())
    .takeWhile(n ->
          {
                System.out.println(n);
                return n < 10;
          }
    ).subscribe() ;


// Example 2
IntStream intStream  = IntStream.iterate(1, n -> n + 1);
Observable.from(() -> intStream.iterator())
    .takeWhile(n -> n < 10)
    .forEach( n -> System.out.println(n));

6

จริงๆแล้วมี 2 วิธีใน Java 8 โดยไม่ต้องมีไลบรารีเพิ่มเติมหรือใช้ Java 9

หากคุณต้องการพิมพ์ตัวเลขตั้งแต่ 2 ถึง 20 บนคอนโซลคุณสามารถทำได้:

IntStream.iterate(2, (i) -> i + 2).peek(System.out::println).allMatch(i -> i < 20);

หรือ

IntStream.iterate(2, (i) -> i + 2).peek(System.out::println).anyMatch(i -> i >= 20);

เอาต์พุตอยู่ในทั้งสองกรณี:

2
4
6
8
10
12
14
16
18
20

ยังไม่มีใครพูดถึงแมทช์เลย นี่คือเหตุผลสำหรับการโพสต์นี้


5

นี่คือซอร์สที่คัดลอกมาจาก JDK 9 java.util.stream.Stream.takeWhile (Predicate) ข้อแตกต่างเล็กน้อยในการทำงานกับ JDK 8

static <T> Stream<T> takeWhile(Stream<T> stream, Predicate<? super T> p) {
    class Taking extends Spliterators.AbstractSpliterator<T> implements Consumer<T> {
        private static final int CANCEL_CHECK_COUNT = 63;
        private final Spliterator<T> s;
        private int count;
        private T t;
        private final AtomicBoolean cancel = new AtomicBoolean();
        private boolean takeOrDrop = true;

        Taking(Spliterator<T> s) {
            super(s.estimateSize(), s.characteristics() & ~(Spliterator.SIZED | Spliterator.SUBSIZED));
            this.s = s;
        }

        @Override
        public boolean tryAdvance(Consumer<? super T> action) {
            boolean test = true;
            if (takeOrDrop &&               // If can take
                    (count != 0 || !cancel.get()) && // and if not cancelled
                    s.tryAdvance(this) &&   // and if advanced one element
                    (test = p.test(t))) {   // and test on element passes
                action.accept(t);           // then accept element
                return true;
            } else {
                // Taking is finished
                takeOrDrop = false;
                // Cancel all further traversal and splitting operations
                // only if test of element failed (short-circuited)
                if (!test)
                    cancel.set(true);
                return false;
            }
        }

        @Override
        public Comparator<? super T> getComparator() {
            return s.getComparator();
        }

        @Override
        public void accept(T t) {
            count = (count + 1) & CANCEL_CHECK_COUNT;
            this.t = t;
        }

        @Override
        public Spliterator<T> trySplit() {
            return null;
        }
    }
    return StreamSupport.stream(new Taking(stream.spliterator()), stream.isParallel()).onClose(stream::close);
}

4

นี่คือรุ่นที่ทำกับ ints - ตามที่ถามในคำถาม

การใช้งาน:

StreamUtil.takeWhile(IntStream.iterate(1, n -> n + 1), n -> n < 10);

นี่คือรหัสสำหรับ StreamUtil:

import java.util.PrimitiveIterator;
import java.util.Spliterators;
import java.util.function.IntConsumer;
import java.util.function.IntPredicate;
import java.util.stream.IntStream;
import java.util.stream.StreamSupport;

public class StreamUtil
{
    public static IntStream takeWhile(IntStream stream, IntPredicate predicate)
    {
        return StreamSupport.intStream(new PredicateIntSpliterator(stream, predicate), false);
    }

    private static class PredicateIntSpliterator extends Spliterators.AbstractIntSpliterator
    {
        private final PrimitiveIterator.OfInt iterator;
        private final IntPredicate predicate;

        public PredicateIntSpliterator(IntStream stream, IntPredicate predicate)
        {
            super(Long.MAX_VALUE, IMMUTABLE);
            this.iterator = stream.iterator();
            this.predicate = predicate;
        }

        @Override
        public boolean tryAdvance(IntConsumer action)
        {
            if (iterator.hasNext()) {
                int value = iterator.nextInt();
                if (predicate.test(value)) {
                    action.accept(value);
                    return true;
                }
            }

            return false;
        }
    }
}

2

ไปรับห้องสมุดAbacusUtil มันมี API ที่แน่นอนที่คุณต้องการและอื่น ๆ :

IntStream.iterate(1, n -> n + 1).takeWhile(n -> n < 10).forEach(System.out::println);

ประกาศ: ฉันเป็นผู้พัฒนา AbacusUtil


0

คุณไม่สามารถยกเลิกการสตรีมได้ยกเว้นการทำงานของเทอร์มินัลการลัดวงจรซึ่งจะทำให้ค่าสตรีมบางส่วนไม่ได้ประมวลผลโดยไม่คำนึงถึงค่าของสตรีม แต่ถ้าคุณต้องการหลีกเลี่ยงการดำเนินการกับกระแสคุณสามารถเพิ่มการแปลงและตัวกรองในกระแส:

import java.util.Objects;

class ThingProcessor
{
    static Thing returnNullOnCondition(Thing thing)
    {    return( (*** is condition met ***)? null : thing);    }

    void processThings(Collection<Thing> thingsCollection)
    {
        thingsCollection.stream()
        *** regular stream processing ***
        .map(ThingProcessor::returnNullOnCondition)
        .filter(Objects::nonNull)
        *** continue stream processing ***
    }
} // class ThingProcessor

ที่เปลี่ยนกระแสของสิ่งที่เป็นโมฆะเมื่อสิ่งที่ตรงตามเงื่อนไขบางอย่างจากนั้นกรองออกเป็นโมฆะ หากคุณเต็มใจที่จะดื่มด่ำกับผลข้างเคียงคุณสามารถตั้งค่าเงื่อนไขให้เป็นจริงได้เมื่อพบเจอสิ่งใดสิ่งหนึ่งดังนั้นสิ่งที่ตามมาทั้งหมดจะถูกกรองออกโดยไม่คำนึงถึงคุณค่าของมัน แต่แม้ว่าจะไม่ใช่คุณสามารถบันทึกการประมวลผล (ถ้าไม่ใช่ทั้งหมด) จำนวนมากโดยการกรองค่าออกจากสตรีมที่คุณไม่ต้องการประมวลผล


มันเป็นข้ออ้างที่ว่าผู้ทดสอบที่ไม่เปิดเผยชื่อบางคนประเมินคำตอบของฉันโดยไม่บอกว่าทำไม ดังนั้นฉันและผู้อ่านคนอื่น ๆ ก็ไม่ทราบว่าคำตอบของฉันคืออะไร ในกรณีที่ไม่มีเหตุผลของพวกเขาฉันจะถือว่าการวิจารณ์ของพวกเขาไม่ถูกต้องและคำตอบของฉันที่โพสต์นั้นถูกต้อง
Matthew

คุณตอบไม่ได้แก้ปัญหา OPs ซึ่งกำลังจัดการกับกระแสที่ไม่มีที่สิ้นสุด นอกจากนี้ยังดูเหมือนว่าจะซับซ้อนโดยไม่จำเป็นเนื่องจากคุณสามารถเขียนเงื่อนไขในตัวกรอง () เรียกตัวเองโดยไม่จำเป็นต้องใช้แผนที่ () คำถามมีรหัสตัวอย่างอยู่แล้วลองใช้คำตอบกับรหัสนั้นแล้วคุณจะเห็นว่าโปรแกรมจะวนซ้ำตลอดไป
SenoCtar

0

แม้ว่าฉันจะมีความต้องการที่คล้ายกัน - เรียกใช้บริการเว็บถ้ามันล้มเหลวลองอีกครั้ง 3 ครั้ง หากล้มเหลวแม้จะผ่านการทดลองมากมายเหล่านี้ส่งการแจ้งเตือนทางอีเมล หลังจาก googling มากanyMatch()มาเป็นผู้ช่วยเหลือ รหัสตัวอย่างของฉันเป็นดังนี้ ในตัวอย่างต่อไปถ้าwebServiceCallanyMatch()วิธีการส่งกลับจริงในการย้ำแรกของตัวเองกระแสไม่ได้ย้ำต่อไปในฐานะที่เราได้เรียกว่า ฉันเชื่อว่านี่คือสิ่งที่คุณกำลังมองหา

import java.util.stream.IntStream;

import io.netty.util.internal.ThreadLocalRandom;

class TrialStreamMatch {

public static void main(String[] args) {        
    if(!IntStream.range(1,3).anyMatch(integ -> webServiceCall(integ))){
         //Code for sending email notifications
    }
}

public static boolean webServiceCall(int i){
    //For time being, I have written a code for generating boolean randomly
    //This whole piece needs to be replaced by actual web-service client code
    boolean bool = ThreadLocalRandom.current().nextBoolean();
    System.out.println("Iteration index :: "+i+" bool :: "+bool);

    //Return success status -- true or false
    return bool;
}

0

หากคุณทราบจำนวนการทำซ้ำที่แน่นอนที่จะดำเนินการคุณสามารถทำได้

IntStream
          .iterate(1, n -> n + 1)
          .limit(10)
          .forEach(System.out::println);

1
แม้ว่าสิ่งนี้อาจตอบคำถามผู้แต่ง แต่ก็ไม่มีคำอธิบายและลิงก์ไปยังเอกสารประกอบ ตัวอย่างโค้ดดิบนั้นไม่ค่อยมีประโยชน์หากไม่มีวลีอยู่รอบ ๆ คุณอาจพบว่าวิธีเขียนคำตอบที่ดีมีประโยชน์มาก โปรดแก้ไขคำตอบของคุณ
สวัสดี

0
    IntStream.iterate(1, n -> n + 1)
    .peek(System.out::println) //it will be executed 9 times
    .filter(n->n>=9)
    .findAny();

แทนที่จะเป็นจุดสูงสุดคุณสามารถใช้ mapToObj เพื่อส่งคืนวัตถุหรือข้อความสุดท้าย

    IntStream.iterate(1, n -> n + 1)
    .mapToObj(n->{   //it will be executed 9 times
            if(n<9)
                return "";
            return "Loop repeats " + n + " times";});
    .filter(message->!message.isEmpty())
    .findAny()
    .ifPresent(System.out::println);

-2

หากคุณมีปัญหาแตกต่างกันอาจจำเป็นต้องใช้วิธีแก้ปัญหาที่แตกต่างกัน แต่สำหรับปัญหาปัจจุบันของคุณฉันจะไปกับ:

IntStream
    .iterate(1, n -> n + 1)
    .limit(10)
    .forEach(System.out::println);

-2

อาจจะเป็นหัวข้อเล็กน้อย แต่นี่คือสิ่งที่เรามีให้List<T>มากกว่าStream<T>มากกว่า

ก่อนอื่นคุณต้องมีtakeวิธีการใช้ วิธีนี้ใช้nองค์ประกอบแรก:

static <T> List<T> take(List<T> l, int n) {
    if (n <= 0) {
        return newArrayList();
    } else {
        int takeTo = Math.min(Math.max(n, 0), l.size());
        return l.subList(0, takeTo);
    }
}

มันใช้งานได้เหมือน scala.List.take

    assertEquals(newArrayList(1, 2, 3), take(newArrayList(1, 2, 3, 4, 5), 3));
    assertEquals(newArrayList(1, 2, 3), take(newArrayList(1, 2, 3), 5));

    assertEquals(newArrayList(), take(newArrayList(1, 2, 3), -1));
    assertEquals(newArrayList(), take(newArrayList(1, 2, 3), 0));

ตอนนี้มันจะค่อนข้างง่ายในการเขียนtakeWhileวิธีการตามtake

static <T> List<T> takeWhile(List<T> l, Predicate<T> p) {
    return l.stream().
            filter(p.negate()).findFirst(). // find first element when p is false
            map(l::indexOf).        // find the index of that element
            map(i -> take(l, i)).   // take up to the index
            orElse(l);  // return full list if p is true for all elements
}

มันทำงานได้เช่นนี้:

    assertEquals(newArrayList(1, 2, 3), takeWhile(newArrayList(1, 2, 3, 4, 3, 2, 1), i -> i < 4));

การใช้งานนี้ซ้ำรายการบางส่วนสองสามครั้ง แต่จะไม่เพิ่มO(n^2)การดำเนินการเพิ่ม หวังว่าจะเป็นที่ยอมรับ


-3

ฉันมีอีกวิธีแก้ปัญหาอย่างรวดเร็วโดยการนำสิ่งนี้ไปใช้ (ซึ่งเป็นสิ่งที่ไม่สะอาดในความเป็นจริง แต่คุณได้ความคิด):

public static void main(String[] args) {
    System.out.println(StreamUtil.iterate(1, o -> o + 1).terminateOn(15)
            .map(o -> o.toString()).collect(Collectors.joining(", ")));
}

static interface TerminatedStream<T> {
    Stream<T> terminateOn(T e);
}

static class StreamUtil {
    static <T> TerminatedStream<T> iterate(T seed, UnaryOperator<T> op) {
        return new TerminatedStream<T>() {
            public Stream<T> terminateOn(T e) {
                Builder<T> builder = Stream.<T> builder().add(seed);
                T current = seed;
                while (!current.equals(e)) {
                    current = op.apply(current);
                    builder.add(current);
                }
                return builder.build();
            }
        };
    }
}

2
คุณกำลังประเมินกระแสทั้งหมดล่วงหน้า! และถ้าcurrentไม่เคย.equals(e)คุณจะได้รับการวนซ้ำไม่รู้จบ .limit(1)ทั้งสองแม้ว่าคุณต่อมาใช้เช่น มันแย่กว่า'มลทิน'มาก
charlie

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.