1. Elementlərin sayılması: count()
Kolleksiyalarla (rəqəmlər və ya obyektlər) işləyərkən demək olar ki, həmişə nəyisə hesablamaq lazım olur: elementlərin sayı, cəm, orta, maksimum və ya minimum. Məsələn, şirkətdəki əməkdaşların sayı, bütün maaşların cəmi, tələbələrin orta yaşı, ən bahalı məhsul, ən böyük sifariş. Stream API sayəsində hər şey daha sadə və ifadəlidir.
Bu necə işləyir
count() metodu — axının (Stream API) elementlərinin sayını qaytaran terminal operatorudur.
long count = employees.stream().count();
Əgər yalnız şərtə uyğun gələn elementləri saymaq lazımdırsa — filter(...) filtrindən istifadə edin:
long richCount = employees.stream()
.filter(e -> e.getSalary() > 100_000)
.count();
Tətbiqimiz üçün nümunə:
Məhsullar siyahısı:
List<Product> products = List.of(
new Product("Süd", 80),
new Product("Pendir", 250),
new Product("Çörək", 40)
);
Gəlin 100-dən baha olan məhsulların sayını hesablayaq:
long expensiveCount = products.stream()
.filter(p -> p.getPrice() > 100)
.count();
System.out.println("Bahalı məhsulların sayı: " + expensiveCount);
Optional nədir
Javada xüsusi konteyner var — Optional. Bu, dəyər saxlayan və ya boş ola bilən obyekt-qablaşdırıcıdır. Nəticə olmayanda bunu açıq göstərmək üçün istifadə olunur. Məsələn, min(), max() və average() metodları, əgər kolleksiya boşdursa, boş nəticə qaytara bilər. null əvəzinə Optional qaytarılır.
Optional-ın əsas metodları
- isPresent() / isEmpty() — dəyərin olub-olmadığını yoxlamaq.
- orElse(dəyər) — dəyəri qaytarmaq və ya boşdursa standart (defolt) dəyəri vermək.
- orElseThrow() — boşdursa istisna atmaq.
- ifPresent(...) — dəyər olduqda hərəkət icra etmək.
Nümunə:
OptionalInt min = products.stream()
.mapToInt(Product::getPrice)
.min();
if (min.isPresent()) {
System.out.println("Minimal qiymət: " + min.getAsInt());
} else {
System.out.println("Siyahı boşdur");
}
Və ya daha qısa:
int minValue = min.orElse(-1);
System.out.println("Minimal qiymət: " + minValue);
Bu yanaşma NullPointerException-un qarşısını almağa kömək edir və kodu daha təhlükəsiz edir.
2. Rəqəmsal məlumatlar üçün cəm, orta, minimum və maksimum
Primitiv stream-lər: IntStream, DoubleStream, LongStream
Rəqəmsal məlumatlar üçün Stream API xüsusi stream-lər təklif edir: IntStream, DoubleStream, LongStream. Onlar cəmi, ortanı, minimumu və maksimumu asan və tez hesablamağa imkan verir.
Rəqəmsal stream-ə çevirmə
Obyekt axınından rəqəmsal stream almaq üçün mapToInt, mapToDouble, mapToLong metodlarından istifadə edin.
int sum = products.stream()
.mapToInt(Product::getPrice)
.sum();
System.out.println("Qiymətlərin ümumi cəmi: " + sum);
Metodlar
- sum() — bütün elementlərin cəmi.
- average() — ədədi orta (qaytarır: OptionalDouble).
- min(), max() — minimum və maksimum (qaytarır: OptionalInt/OptionalDouble/OptionalLong).
Nümunələr:
// Bütün qiymətlərin cəmi
int total = products.stream()
.mapToInt(Product::getPrice)
.sum();
// Orta qiymət
OptionalDouble avg = products.stream()
.mapToInt(Product::getPrice)
.average();
// Minimal və maksimal qiymət
OptionalInt min = products.stream()
.mapToInt(Product::getPrice)
.min();
OptionalInt max = products.stream()
.mapToInt(Product::getPrice)
.max();
Dəyəri Optional-dan necə almaq olar
double average = avg.orElse(0.0); // Kolleksiya boşdursa 0.0
int minValue = min.orElse(-1); // Kolleksiya boşdursa -1
int maxValue = max.orElse(-1); // Kolleksiya boşdursa -1
Proqramçı zarafatı: boş siyahı — bu, səhv deyil, sadəcə məlumatınızın olmadığı vəziyyətdir. Amma boş Optional-dan getAsInt() ilə dəyər almağa çalışsanız — NoSuchElementException alacaqsınız. Həmişə orElse və ya isPresent() istifadə edin!
3. Obyektlərin aqreqasiyası: Collectors.summingInt, averagingInt, maxBy, minBy
Əgər obyekt axınınız var və hansısa əlamətə görə dəyərləri aqreqasiya etmək istəyirsinizsə, Collectors sinfinin xüsusi kollektorlarından istifadə edin.
summingInt, averagingInt
int totalSalary = employees.stream()
.collect(Collectors.summingInt(Employee::getSalary));
double avgSalary = employees.stream()
.collect(Collectors.averagingInt(Employee::getSalary));
minBy, maxBy
Maksimal/minimal sahə dəyərinə malik obyekti tapmaq üçün:
Optional<Employee> richest = employees.stream()
.collect(Collectors.maxBy(Comparator.comparingInt(Employee::getSalary)));
Optional<Employee> poorest = employees.stream()
.collect(Collectors.minBy(Comparator.comparingInt(Employee::getSalary)));
Vacibdir: nəticə — Optional-dır, çünki kolleksiya boş ola bilər.
Nümunə
Product sinfini yaradaq:
public class Product {
private final String name;
private final int price;
public Product(String name, int price) {
this.name = name;
this.price = price;
}
public String getName() { return name; }
public int getPrice() { return price; }
}
Məhsullar siyahısını yaradaq:
List<Product> products = List.of(
new Product("Süd", 80),
new Product("Pendir", 250),
new Product("Çörək", 40)
);
Ən bahalı məhsulu tapaq:
Optional<Product> maxProduct = products.stream()
.collect(Collectors.maxBy(Comparator.comparingInt(Product::getPrice)));
maxProduct.ifPresent(p -> System.out.println("Ən bahalı məhsul: " + p.getName()));
4. Qruplaşdırma ilə birləşdirmə
Aqreqasiya metodları çox vaxt qruplaşdırma ilə birləşdirilir. Məsələn, məhsulların adının ilk hərfinə görə orta qiyməti tapa bilərsiniz:
Map<Character, Double> avgPriceByLetter = products.stream()
.collect(Collectors.groupingBy(
p -> p.getName().charAt(0),
Collectors.averagingInt(Product::getPrice)
));
System.out.println(avgPriceByLetter);
Nəticə:
{S=80.0, P=250.0, Ç=40.0}
5. Real həyatdan nümunələr
Nümunə 1: Tələbələr və ballar
Tələbələrin siyahısı və onların balları:
public class Student {
private final String name;
private final int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
public String getName() {
return name;
}
public int getScore() {
return score;
}
}
List<Student> students = List.of(
new Student("Alisa", 90),
new Student("Bob", 75),
new Student("Vasya", 100)
);
80-dən yüksək bal alan tələbələrin sayı nə qədərdir?
long count = students.stream()
.filter(s -> s.getScore() > 80)
.count();
System.out.println("Balı > 80 olan tələbələrin sayı: " + count);
Orta bal:
double avg = students.stream()
.mapToInt(Student::getScore)
.average()
.orElse(0.0);
System.out.println("Orta bal: " + avg);
Ən uğurlu tələbə:
students.stream()
.max(Comparator.comparingInt(Student::getScore))
.ifPresent(s -> System.out.println("Ən yaxşı tələbə: " + s.getName()));
Nümunə 2: Unikal malların sayı
long uniqueCount = products.stream()
.map(Product::getName)
.distinct()
.count();
System.out.println("Unikal məhsulların sayı: " + uniqueCount);
6. Faydalı nüanslar
Vizual sxem: aqreqasiya metodları necə işləyir
Obyektlər kolleksiyası
│
▼
stream()
│
▼
mapToInt/Double/Long (lazımdırsa)
│
▼
sum() / average() / min() / max() / count()
│
▼
Nəticə (int, double, long, Optional)
Optional ilə işləmə: dəyərləri təhlükəsiz necə çıxarmaq olar
Niyə metodlar Optional qaytarır?
Əgər kolleksiya boşdursa (məsələn, boş siyahıda maksimumu axtarırsınızsa), boş Optional qaytarılır. Dərhal getAsInt()/get() çağırılarsa, istisna atılacaq.
Düzgün yanaşma:
- orElse(susmaya görə dəyər) istifadə etmək
- Dəyər olduqda əməliyyat üçün ifPresent(...) istifadə etmək
- Aydın şəkildə istisna atmaq üçün orElseThrow(...) istifadə etmək
Nümunə:
OptionalDouble avg = products.stream()
.mapToInt(Product::getPrice)
.average();
System.out.println("Orta qiymət: " + avg.orElse(0.0));
Primitiv stream-ləri nə vaxt, Collectors-u nə vaxt istifadə etməli
- Sadəcə rəqəmsal sahə üzrə cəm/orta/minimum/maksimum lazımdırsa — mapToInt və uyğun metodu (sum, average, min, max) istifadə edin.
- Obyektləri aqreqasiya etmək (məsələn, sahəsi maksimum olan obyekti tapmaq) istəyirsinizsə, maxBy/minBy kollektorlarından istifadə edin.
- Qruplaşdırıb qruplar üzrə aqreqatları hesablamaq lazımdırsa — groupingBy ilə aqreqasiya kollektorlarının kombinasiyasından istifadə edin.
7. Aqreqasiya metodları ilə işləyərkən tipik səhvlər
Səhv №1: Optional işlənməyib. Tez-tez yeni başlayanlar min, max, average metodlarının Optional qaytardığını unudurlar. Nəticədə boş konteynerdən dəyər almağa cəhd ediləndə NoSuchElementException yaranır. Həmişə orElse, orElseThrow və ya ifPresent istifadə edin.
Səhv №2: mapToInt/mapToDouble əvəzinə adi stream istifadə olunur. Əgər stream().sum() yazsanız, kompilyator belə deyəcək: “Belə metod yoxdur!”. Cəm, orta, minimum və maksimum üçün primitiv stream-lər lazımdır.
Səhv №3: Müqayisədə tiplərin uyğun gəlməməsi. Obyektlər arasında maksimum/minimum axtararkən düzgün komparator istifadə edin: Comparator.comparingInt(Employee::getSalary). Əks halda kompilyasiya xətası və ya yanlış nəticə ala bilərsiniz.
Səhv №4: Obyektləri null ilə müqayisə etmək. Kolleksiyada null elementlər ola bilərsə, aqreqasiya NullPointerException ata bilər. Belə elementləri əvvəlcədən filtrələmək və ya Comparator.nullsLast(...)/nullsFirst(...) istifadə etmək daha yaxşıdır.
Səhv №5: Boş kolleksiyalarla sum/average/min/max istifadə edərkən nəticəni nəzərə almamaq. Kolleksiya boşdursa, sum() metodu 0 qaytarır, average()/min()/max() isə boş Optional. Bu halı mütləq işləyin.
GO TO FULL VERSION