Tolong, pertimbangkan kode ini:

System.out.println("#1");
Stream.of(0, 1, 2, 3)
        .peek(e -> System.out.println(e))
        .sorted()
        .findFirst();

System.out.println("\n#2");
IntStream.range(0, 4)
        .peek(e -> System.out.println(e))
        .sorted()
        .findFirst();

Outputnya akan menjadi:

#1
0
1
2
3

#2
0

Adakah yang bisa menjelaskan, mengapa output dari dua aliran berbeda?

52
Pavel_K 24 Mei 2021, 12:22

2 jawaban

Jawaban Terbaik

Nah, IntStream.range() mengembalikan a sequential ordered IntStream from startInclusive(inclusive) to endExclusive (exclusive) by an incremental step of 1, yang berarti sudah diurutkan. Karena sudah diurutkan, masuk akal jika operasi perantara .sorted() berikut tidak melakukan apa-apa. Akibatnya, peek() dieksekusi hanya pada elemen pertama (karena operasi terminal hanya membutuhkan elemen pertama).

Di sisi lain, elemen yang diteruskan ke Stream.of() belum tentu diurutkan (dan metode of() tidak memeriksa apakah mereka diurutkan). Oleh karena itu, .sorted() harus melintasi semua elemen untuk menghasilkan aliran yang diurutkan, yang memungkinkan operasi terminal findFirst() untuk mengembalikan elemen pertama dari aliran yang diurutkan. Akibatnya, peek dieksekusi pada semua elemen, meskipun operasi terminal hanya membutuhkan elemen pertama.

45
Eran 25 Mei 2021, 07:08

IntStream.range sudah diurutkan:

// reports true
System.out.println(
       IntStream.range(0, 4)
                .spliterator()
                .hasCharacteristics(Spliterator.SORTED)
);

Jadi ketika metode sorted() di Stream dipukul, secara internal, metode tersebut akan menjadi NO-OP.

Jika tidak, seperti yang sudah Anda lihat dalam contoh pertama Anda, semua elemen harus diurutkan, hanya dengan demikian findFirst dapat mengetahui siapa yang "benar-benar yang pertama".

Perhatikan bahwa pengoptimalan ini hanya berfungsi untuk aliran yang diurutkan secara alami. Sebagai contoh:

// prints too much you say?
Stream.of(new User(30), new User(25), new User(34))
            .peek(x -> System.out.println("1 : before I call first sorted"))
            .sorted(Comparator.comparing(User::age))
            .peek(x -> System.out.println("2 : before I call second sorted"))
            .sorted(Comparator.comparing(User::age))
            .findFirst();

Di mana (untuk singkatnya):

record User(int age) { }
30
Naman 25 Mei 2021, 17:34