İçeriğe geç
Educora
İleri22 dk12 / 18

Modern Java ve proje: öğrenci not defteri

record, var, lambdalar ve akışlarla tanış; ardından kursta öğrendiklerini birleştirerek bir öğrenci not defteri programı geliştir.

Kendini test et
Bu derste öğreneceklerin
  • Basit bir veri sınıfını record ile yazmak ve var'ı yerinde kullanmak
  • Lambda ifadeleri ve metot referansları yazmak
  • Koleksiyonları akışlarla (filter, map, sorted) işlemek ve hepsini bir projede birleştirmek

Java 30 yaşını geçti ama eskimedi: son yıllarda dile kodu epey kısaltan özellikler eklendi. Eskiden 40 satır tutan bir sınıf artık tek satırlık bir record'a, beş satırlık bir döngü de tek satırlık bir akışa dönüşüyor. Bu derste bu özelliklerle tanışacak, ardından kurs boyunca öğrendiklerini birleştirerek küçük ama gerçek bir proje, yani bir öğrenci not defteri geliştireceksin.

record ve var

Record (kayıt, Java 16'dan beri), değişmez verileri tutan bir sınıfın kısa yazılışıdır. record Point(int x, int y) yazdığında Java; private final alanları, yapıcıyı, x() ve y() metotlarını, ayrıca equals, hashCode ve toString metotlarını kendisi oluşturur. Bir record'a kendi metotlarını da ekleyebilirsin. var ise yerel bir değişkenin türünü derleyicinin belirlemesini sağlar.

Java
public class Main {
    public static void main(String[] args) {
        Point a = new Point(3, 4);
        Point b = new Point(3, 4);
        System.out.println(a);
        System.out.println(a.x() + a.y());
        System.out.println(a.equals(b) + " " + (a == b));
        System.out.println(a.distanceToOrigin());
        var message = "Records save time";
        var count = message.length();
        System.out.println(message + " (" + count + " chars)");
    }
}

record Point(int x, int y) {
    double distanceToOrigin() {
        return Math.sqrt(x * x + y * y);
    }
}
Beklenen çıktı
Point[x=3, y=4]
7
true false
5.0
Records save time (17 chars)

a.equals(b) sonucu true oldu: record'lar içeriklerine göre karşılaştırılır. a == b ise false'tur, çünkü bunlar iki ayrı nesnedir. Getter adlarında get olmadığına dikkat et: getX() değil, sadece x().

Lambdalar ve metot referansları

Lambda ifadesi, adı olmayan kısa bir fonksiyondur: n -> n * n, “n al, n * n döndür” demektir. Lambdalar fonksiyonel arayüzlerin, yani tek bir soyut metodu olan arayüzlerin yerine kullanılır: Predicate (koşulu sınar), Function (değeri dönüştürür), Comparator (iki nesneyi karşılaştırır). Bir lambda yalnızca hazır bir metodu çağırıyorsa, onu bir metot referansıyla daha da kısa yazabilirsin: System.out::println.

Java
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;

public class Main {
    public static void main(String[] args) {
        Predicate<Integer> isEven = n -> n % 2 == 0;
        Function<Integer, Integer> square = n -> n * n;
        System.out.println(isEven.test(4) + " " + square.apply(7));

        List<String> names = new ArrayList<>(List.of("Murad", "Aysel", "Elvin", "Leyla"));
        names.sort((a, b) -> a.compareTo(b));
        names.removeIf(name -> name.startsWith("E"));
        names.forEach(name -> System.out.print(name + " "));
        System.out.println();
        names.forEach(System.out::println);
    }
}
Beklenen çıktı
true 49
Aysel Leyla Murad 
Aysel
Leyla
Murad

Akışlar (Stream API)

Bir akış (stream), bir koleksiyonun elemanlarını bir üretim bandı gibi işler: filter koşula uyanları tutar, map her elemanı dönüştürür, sorted sıralar; toList, count, sum ya da average ise sonucu toplar. Akış, kaynak koleksiyonu değiştirmez. Kod “nasıl” değil “ne” yapılacağını söyler; bu yüzden kolay okunur.

Java
import java.util.List;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        List<Integer> scores = List.of(78, 95, 62, 88, 45, 91);
        List<Integer> passed = scores.stream()
                .filter(s -> s >= 60)
                .sorted()
                .toList();
        System.out.println(passed);
        int total = scores.stream().mapToInt(Integer::intValue).sum();
        double avg = scores.stream().mapToInt(Integer::intValue).average().orElse(0);
        System.out.println(total + " " + avg);
        String initials = List.of("Baku", "Ganja", "Shaki").stream()
                .map(c -> c.substring(0, 1))
                .collect(Collectors.joining("-"));
        System.out.println(initials);
        long count = scores.stream().filter(s -> s > 80).count();
        System.out.println(count);
    }
}
Beklenen çıktı
[62, 78, 88, 91, 95]
459 76.5
B-G-S
3

Proje: öğrenci not defteri

  1. 1
    Veriyi modelle

    Öğrenci, adı ve puan listesi olan bir record'dur. Kompakt yapıcısı 0–100 aralığı dışındaki puanları IllegalArgumentException ile reddeder.

  2. 2
    Hesaplamaları ekle

    average() ortalama puanı bir akışla bulur ve tek ondalık basamağa yuvarlar; letter() ise bir switch ifadesiyle harf notu verir.

  3. 3
    Not defteri sınıfını yaz

    GradeBook, öğrencileri private bir ArrayList'te tutar, sıralı bir rapor yazdırır ve sınıf ortalamasını hesaplar.

  4. 4
    Hepsini main'de birleştir

    Öğrencileri ekle, hatalı veriyi try/catch ile yakala ve raporu yazdır.

Java
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        GradeBook book = new GradeBook();
        book.add(new Student("Aysel", List.of(92, 88, 95)));
        book.add(new Student("Murad", List.of(85, 78, 84)));
        book.add(new Student("Leyla", List.of(58, 49, 61)));
        book.add(new Student("Nigar", List.of(70, 65, 72)));
        try {
            book.add(new Student("Elvin", List.of(90, 120)));
        } catch (IllegalArgumentException e) {
            System.out.println("Skipped: " + e.getMessage());
        }
        book.printReport();
        System.out.println("Class average: " + book.classAverage());
    }
}

record Student(String name, List<Integer> scores) {
    Student {
        for (int s : scores) {
            if (s < 0 || s > 100) throw new IllegalArgumentException(name + " has score " + s);
        }
    }

    double average() {
        double avg = scores.stream().mapToInt(Integer::intValue).average().orElse(0);
        return Math.round(avg * 10) / 10.0;
    }

    String letter() {
        return switch ((int) average() / 10) {
            case 10, 9 -> "A";
            case 8 -> "B";
            case 7 -> "C";
            case 6 -> "D";
            default -> "F";
        };
    }
}

class GradeBook {
    private final List<Student> students = new ArrayList<>();

    void add(Student s) { students.add(s); }

    double classAverage() {
        double avg = students.stream().mapToDouble(Student::average).average().orElse(0);
        return Math.round(avg * 10) / 10.0;
    }

    void printReport() {
        students.stream()
                .sorted(Comparator.comparingDouble(Student::average).reversed())
                .forEach(s -> System.out.println(s.name() + ": " + s.average() + " (" + s.letter() + ")"));
    }
}
Beklenen çıktı
Skipped: Elvin has score 120
Aysel: 91.7 (A)
Murad: 82.3 (B)
Nigar: 69.0 (D)
Leyla: 56.0 (F)
Class average: 74.8
Projenin tamamı tek dosyada — Main.java
ProjedeHangi konudan
record Student, Student { ... }record'lar, yapıcılar
throw new IllegalArgumentException, try/catchistisnalar
switch ((int) average() / 10)switch ifadeleri, tür dönüşümü
private final List<Student>kapsülleme, koleksiyonlar, generic'ler
stream(), Student::average, s -> ...akışlar, metot referansları, lambdalar

Student { ... }, record'un kompakt yapıcısıdır: parametreleri tekrar yazmadan veriyi doğrulamanı sağlar; alanlar ise ardından otomatik doldurulur. Elvin'in 120 puanı kabul edilmedi ve not defterine girmedi, ama program çalışmaya devam etti; tıpkı istisnalar dersindeki gibi.

Önemli noktalar

  • record, değişmez bir veri sınıfını tek satırda oluşturur: alanlar, yapıcı, getter'lar, equals ve toString otomatik gelir.
  • var, yerel bir değişkenin türünü derleyiciye belirletir, ama tür yine de sabittir.
  • Lambda (x -> ...), fonksiyonel bir arayüzün kısa gerçekleştirimidir; Type::method ise bir metot referansıdır.
  • Akış: stream() → filter / map / sorted → toList, count, sum, average; kaynak koleksiyon değişmez.
  • Gerçek bir proje kursun tüm parçalarını bir araya getirir: sınıflar, istisnalar, koleksiyonlar ve modern Java.

Kendini test et

10 soru. Her doğru cevap XP kazandırır.

1 / 10
record Point(int x, int y) için x koordinatı nasıl okunur?