16-bo‘lim
Stream API
Oqim yaratish, filter va map, saralash, collect va Collectors, guruhlash, reduce hamda oqimlarning kechiktirilgan tabiati.
Ushbu bo‘lim mundarijasi
Stream API - to'plamlar ustida so'rov yozish vositasi. Java 8 da qo'shilgan va tilning eng ko'p ishlatiladigan qismlaridan biri.
Oqim bilan "nima kerakligini" yozasiz, "qanday qilishni" emas.
Sikl va oqim #
Talabalar ichidan 80 dan yuqori ball olganlarni topib, ism bo'yicha saralash kerak:
record Talaba(String ism, int ball, String guruh) {
}
Shu turdan foydalanamiz.
import java.util.*;
public class Sikl {
public static void main(String[] args) {
List<Talaba> sinf = List.of(
new Talaba("Husanboy", 92, "A"),
new Talaba("Malika", 78, "B"),
new Talaba("Nodira", 85, "A"),
new Talaba("Aziza", 95, "B"),
new Talaba("Kamola", 64, "A"));
List<String> natija = new ArrayList<>();
for (Talaba t : sinf) {
if (t.ball() > 80) {
natija.add(t.ism());
}
}
Collections.sort(natija);
System.out.println(String.join(", ", natija));
}
}
Aziza, Husanboy, Nodira
Endi xuddi shuni oqim bilan:
import java.util.*;
import java.util.stream.*;
public class Oqim {
public static void main(String[] args) {
List<Talaba> sinf = List.of(
new Talaba("Husanboy", 92, "A"),
new Talaba("Malika", 78, "B"),
new Talaba("Nodira", 85, "A"),
new Talaba("Aziza", 95, "B"),
new Talaba("Kamola", 64, "A"));
String natija = sinf.stream()
.filter(t -> t.ball() > 80)
.map(Talaba::ism)
.sorted()
.collect(Collectors.joining(", "));
System.out.println(natija);
}
}
Aziza, Husanboy, Nodira
Oraliq o'zgaruvchi yo'q, maqsad ko'rinib turibdi.
Oqimning uch bosqichi #
Kechiktirilgan bajarish #
import java.util.*;
import java.util.stream.*;
public class Kechikish {
public static void main(String[] args) {
List<String> sozlar = List.of("bir", "ikki", "uch");
System.out.println("Oqim yaratildi, lekin yakuniy amal yo'q:");
Stream<String> oqim = sozlar.stream()
.filter(s -> {
System.out.println(" tekshirilmoqda: " + s);
return s.length() > 3;
});
System.out.println("Hali hech narsa chiqmadi.");
System.out.println("Endi count() chaqiramiz:");
System.out.println(" natija: " + oqim.count());
}
}
Oqim yaratildi, lekin yakuniy amal yo'q:
Hali hech narsa chiqmadi.
Endi count() chaqiramiz:
tekshirilmoqda: bir
tekshirilmoqda: ikki
tekshirilmoqda: uch
natija: 1
Diqqat qiling: "tekshirilmoqda" qatorlari count() chaqirilgandan
keyin chiqdi, oqim e'lon qilinganda emas.
Ya'ni filter ichidagi kod oqim qurilganda umuman bajarilmadi - u
yakuniy amalni kutib turdi. Bu kechiktirilgan bajarishning aniq
isboti.
import java.util.List;
import java.util.stream.Stream;
public class BirMarta {
public static void main(String[] args) {
Stream<String> oqim = List.of("bir", "ikki").stream();
System.out.println("Birinchi marta: " + oqim.count());
try {
System.out.println(oqim.count());
} catch (IllegalStateException x) {
System.out.println("Ikkinchi marta: " + x.getMessage());
}
}
}
Birinchi marta: 2
Ikkinchi marta: stream has already been operated upon or closed
Yakuniy amal oqimni yopadi. Qayta kerak bo'lsa, manbadan yangi
oqim yarating: sinf.stream() ni qaytadan chaqiring.
Shuning uchun oqimni o'zgaruvchida saqlash odatda yomon fikr - uni bir zanjirda yozib, darhol yakunlang.
filter, map, sorted #
import java.util.*;
import java.util.stream.*;
public class Asosiy {
public static void main(String[] args) {
List<Talaba> sinf = List.of(
new Talaba("Husanboy", 92, "A"),
new Talaba("Malika", 78, "B"),
new Talaba("Nodira", 85, "A"),
new Talaba("Aziza", 95, "B"));
System.out.println("Ismlar: "
+ sinf.stream().map(Talaba::ism).toList());
System.out.println("85+: "
+ sinf.stream()
.filter(t -> t.ball() >= 85)
.map(Talaba::ism)
.toList());
System.out.println("Ball bo'yicha: "
+ sinf.stream()
.sorted(Comparator
.comparingInt(Talaba::ball).reversed())
.map(t -> t.ism() + "(" + t.ball() + ")")
.toList());
System.out.println("Birinchi 2 ta: "
+ sinf.stream().limit(2).map(Talaba::ism).toList());
System.out.println("2 tasini o'tkazib: "
+ sinf.stream().skip(2).map(Talaba::ism).toList());
}
}
Ismlar: [Husanboy, Malika, Nodira, Aziza]
85+: [Husanboy, Nodira, Aziza]
Ball bo'yicha: [Aziza(95), Husanboy(92), Nodira(85), Malika(78)]
Birinchi 2 ta: [Husanboy, Malika]
2 tasini o'tkazib: [Nodira, Aziza]
Yig'uvchi amallar #
import java.util.*;
import java.util.stream.*;
public class Yigish {
public static void main(String[] args) {
List<Talaba> sinf = List.of(
new Talaba("Husanboy", 92, "A"),
new Talaba("Malika", 78, "B"),
new Talaba("Nodira", 85, "A"),
new Talaba("Aziza", 95, "B"));
System.out.println("Soni: " + sinf.stream().count());
System.out.println("Yig'indi: "
+ sinf.stream().mapToInt(Talaba::ball).sum());
System.out.println("O'rtacha: "
+ sinf.stream().mapToInt(Talaba::ball).average().orElse(0));
System.out.println("Eng yuqori: "
+ sinf.stream().mapToInt(Talaba::ball).max().orElse(0));
System.out.println("Hammasi 70+: "
+ sinf.stream().allMatch(t -> t.ball() >= 70));
System.out.println("90+ bormi: "
+ sinf.stream().anyMatch(t -> t.ball() >= 90));
System.out.println("100 yo'qmi: "
+ sinf.stream().noneMatch(t -> t.ball() == 100));
IntSummaryStatistics stat =
sinf.stream().mapToInt(Talaba::ball).summaryStatistics();
System.out.println("Statistika: min=" + stat.getMin()
+ ", max=" + stat.getMax()
+ ", o'rtacha=" + stat.getAverage());
}
}
Soni: 4
Yig'indi: 350
O'rtacha: 87.5
Eng yuqori: 95
Hammasi 70+: true
90+ bormi: true
100 yo'qmi: true
Statistika: min=78, max=95, o'rtacha=87.5
mapToInt nega kerakStream<Talaba> da sum() metodi yo'q - u faqat IntStream,
LongStream va DoubleStream da mavjud.
mapToInt oqimni primitiv oqimga aylantiradi. Bu ikki foyda beradi:
sum,average,max,summaryStatisticskabi metodlar ochiladi;- Avtoqutilash yo'qoladi - katta hajmda sezilarli tezroq.
Teskarisi ham bor: boxed() primitiv oqimni yana obyekt oqimiga
qaytaradi.
collect va Collectors #
import java.util.*;
import java.util.stream.*;
public class Yigmoq {
public static void main(String[] args) {
List<Talaba> sinf = List.of(
new Talaba("Husanboy", 92, "A"),
new Talaba("Malika", 78, "B"),
new Talaba("Nodira", 85, "A"));
List<String> royxat = sinf.stream().map(Talaba::ism).toList();
Set<String> toplam = sinf.stream()
.map(Talaba::guruh)
.collect(Collectors.toCollection(TreeSet::new));
String matn = sinf.stream()
.map(Talaba::ism)
.collect(Collectors.joining(" | ", "[", "]"));
Map<String, Integer> lugat = sinf.stream()
.collect(Collectors.toMap(Talaba::ism, Talaba::ball,
(a, b) -> a, TreeMap::new));
System.out.println("Ro'yxat: " + royxat);
System.out.println("To'plam: " + toplam);
System.out.println("Matn: " + matn);
System.out.println("Lug'at: " + lugat);
}
}
Ro'yxat: [Husanboy, Malika, Nodira]
To'plam: [A, B]
Matn: [Husanboy | Malika | Nodira]
Lug'at: {Husanboy=92, Malika=78, Nodira=85}
Collectors.toMap ikkita tuzoqqa egaBirinchi tuzoq - takroriy kalit. Ikki element bir xil kalit
bersa, toMap IllegalStateException tashlaydi. Shuning uchun
yuqorida uchinchi argument berilgan: (a, b) -> a - "takror bo'lsa
birinchisini qoldir".
Ikkinchi tuzoq - tartib. Argumentsiz toMap HashMap
qaytaradi va uning tartibi bashoratli emas (12-bo'lim).
Shuning uchun yuqorida to'rtinchi argument sifatida TreeMap::new
berilgan - natija kalit bo'yicha saralangan bo'ladi va har doim bir
xil chiqadi.
Xuddi shu sabab toSet() o'rniga toCollection(TreeSet::new)
ishlatilgan.
Guruhlash #
import java.util.*;
import java.util.stream.*;
public class Guruhlash {
public static void main(String[] args) {
List<Talaba> sinf = List.of(
new Talaba("Husanboy", 92, "A"),
new Talaba("Malika", 78, "B"),
new Talaba("Nodira", 85, "A"),
new Talaba("Aziza", 95, "B"),
new Talaba("Kamola", 64, "A"));
Map<String, List<String>> guruhlar = sinf.stream()
.collect(Collectors.groupingBy(Talaba::guruh, TreeMap::new,
Collectors.mapping(Talaba::ism,
Collectors.toList())));
Map<String, Long> sonlar = sinf.stream()
.collect(Collectors.groupingBy(Talaba::guruh, TreeMap::new,
Collectors.counting()));
Map<String, Double> ortachalar = sinf.stream()
.collect(Collectors.groupingBy(Talaba::guruh, TreeMap::new,
Collectors.averagingInt(Talaba::ball)));
Map<Boolean, List<String>> otganlar = sinf.stream()
.collect(Collectors.partitioningBy(t -> t.ball() >= 80,
Collectors.mapping(Talaba::ism,
Collectors.toList())));
System.out.println("Guruhlar: " + guruhlar);
System.out.println("Sonlari: " + sonlar);
System.out.println("O'rtacha: " + ortachalar);
System.out.println("80+ / 80-: " + otganlar);
}
}
Guruhlar: {A=[Husanboy, Nodira, Kamola], B=[Malika, Aziza]}
Sonlari: {A=3, B=2}
O'rtacha: {A=80.33333333333333, B=86.5}
80+ / 80-: {false=[Malika, Kamola], true=[Husanboy, Nodira, Aziza]}
groupingBy ham sukut bo'yicha HashMap qaytaradiYuqorida ikkinchi argument sifatida TreeMap::new berilgan -
aks holda guruhlar tartibi bashoratli bo'lmasdi.
Bu darslikdagi barcha misollar bir xil natija berishi kerak, shuning uchun bunday joylarda tartib har doim oshkora belgilanadi.
O'z kodingizda ham shuni qiling: chiqish tartibi muhim bo'lsa - uni aniq ko'rsating, tasodifga tayanmang.
reduce #
import java.util.*;
import java.util.stream.*;
public class Reduce {
public static void main(String[] args) {
List<Integer> sonlar = List.of(1, 2, 3, 4, 5);
System.out.println("Yig'indi: "
+ sonlar.stream().reduce(0, Integer::sum));
System.out.println("Ko'paytma: "
+ sonlar.stream().reduce(1, (a, b) -> a * b));
System.out.println("Eng katta: "
+ sonlar.stream().reduce(Integer::max).orElse(0));
List<String> sozlar = List.of("Java", "juda", "qiziq");
System.out.println("Birlashtirish: "
+ sozlar.stream()
.reduce("", (a, b) -> a.isEmpty() ? b : a + " " + b));
}
}
Yig'indi: 15
Ko'paytma: 120
Eng katta: 5
Birlashtirish: Java juda qiziq
reduce ni kamroq ishlatingreduce kuchli, lekin o'qish qiyin. Ko'p hollarda tayyor metod bor:
reduce bilan | Yaxshiroq |
|---|---|
reduce(0, Integer::sum) | mapToInt(...).sum() |
reduce(Integer::max) | max(...) |
| Satrlarni birlashtirish | Collectors.joining(" ") |
reduce ni faqat tayyor metod bo'lmagan holatlarda ishlating -
masalan ko'paytma hisoblashda.
Oqim yaratishning boshqa usullari #
import java.util.*;
import java.util.stream.*;
public class Manbalar {
public static void main(String[] args) {
System.out.println("of: " + Stream.of("a", "b", "c").toList());
System.out.println("range: "
+ IntStream.range(1, 5).boxed().toList());
System.out.println("rangeClosed: "
+ IntStream.rangeClosed(1, 5).boxed().toList());
System.out.println("iterate: "
+ Stream.iterate(1, n -> n * 2).limit(5).toList());
System.out.println("massivdan: "
+ Arrays.stream(new int[]{3, 1, 2})
.sorted().boxed().toList());
System.out.println("satrdan: "
+ "salom dunyo".chars().filter(Character::isLetter).count());
}
}
of: [a, b, c]
range: [1, 2, 3, 4]
rangeClosed: [1, 2, 3, 4, 5]
iterate: [1, 2, 4, 8, 16]
massivdan: [1, 2, 3]
satrdan: 10
range oxirgi sonni qo'shmaydi, rangeClosed esa qo'shadi.
flatMap #
Ichma-ich to'plamlarni yoyish uchun:
import java.util.*;
import java.util.stream.*;
public class Yoyish {
public static void main(String[] args) {
List<List<String>> guruhlar = List.of(
List.of("Husanboy", "Nodira"),
List.of("Malika"),
List.of("Aziza", "Kamola"));
System.out.println("map bilan: "
+ guruhlar.stream().map(List::size).toList());
System.out.println("flatMap bilan: "
+ guruhlar.stream().flatMap(List::stream).sorted().toList());
List<String> jumlalar = List.of("bir ikki", "uch to'rt");
System.out.println("So'zlar: "
+ jumlalar.stream()
.flatMap(j -> Arrays.stream(j.split(" ")))
.toList());
}
}
map bilan: [2, 1, 2]
flatMap bilan: [Aziza, Husanboy, Kamola, Malika, Nodira]
So'zlar: [bir, ikki, uch, to'rt]
- Sikl bilan yozilgan filtrlashni oqimga aylantiring.
filter,mapvasortedni zanjirda ishlating.- Oqimni ikki marta ishlatishga urinib, istisnoni ko'ring.
mapToIntbilan yig'indi va o'rtachani hisoblang.summaryStatisticsnatijasini chiqaring.Collectors.joiningbilan prefiks va suffiks qo'shing.toMapda takroriy kalit berib, istisnoni ko'ring.groupingBybilan guruhlab,TreeMap::newqo'shing.partitioningBybilan ikkiga ajrating.flatMapbilan ichma-ich ro'yxatni yoying.
Xulosa #
- Oqim uch qismdan: manba → oraliq amallar → yakuniy amal.
- Oraliq amallar kechiktirilgan - yakuniy amal bo'lmasa hech narsa bajarilmaydi.
- Oqimni ikki marta ishlatib bo'lmaydi.
- Oqim manbani o'zgartirmaydi.
mapToIntprimitiv oqimga o'tkazadi vasum,average,summaryStatisticsni ochadi.toMaptakroriy kalitda istisno tashlaydi - uchinchi argument bering.groupingByvatoMapsukut bo'yichaHashMapqaytaradi - tartib kerak bo'lsaTreeMap::newbering.reduceni faqat tayyor metod bo'lmaganda ishlating.flatMapichma-ich to'plamlarni yoyadi.
Keyingi bo'limda Optional va null xavfsizligini ko'ramiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
Xatolik topdingizmi?
Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.