Java, Java 8’den sonra önemli ölçüde değişti. Özellikle records, sealed classes, pattern matching, virtual threads ve ScopedValue gibi birçok yeni özellik dile ve JDK’ya girdi. Buna rağmen gerçek projelerde hâlâ Java 6–8 döneminden kalan kullanım şekilleriyle sıkça karşılaşıyoruz.
Bu yazıda öncelikle eski ve modern Java kullanımlarını yan yana gösteren java.evolved projesine bakacağız. Ardından projenin sunduğu modern-java agent skill’i kullanarak bilerek eski Java alışkanlıklarıyla hazırladığım bir Student API’yi Java 25’e taşıyacağız.
Ayrıca örnekte kullandığım projenin tamamına GitHub üzerinden ulaşabilirsiniz.
java.evolved Nedir?
java.evolved, eski Java kullanımlarını modern karşılıklarıyla yan yana gösteren açık kaynaklı bir proje.
Şu anda proje, 17 JDK sürümünü kapsayan 135 modern Java desenine sahip. Üstelik her örnek, eski kullanım ile modern karşılığını yan yana gösteriyor.
Örneğin klasik bir Java sınıfı ile record, eski switch kullanımı ile switch expressions veya Thread tabanlı concurrency yaklaşımı ile virtual threads arasındaki farkı doğrudan görebiliyoruz.
java.evolved Neyi Amaçlıyor?
Java’nın altı aylık sürüm döngüsüyle birlikte düzenli olarak yeni dil özellikleri ve API’ler geliyor.
Ancak bunların tamamını JEP dokümanlarından takip etmek her zaman kolay değil. Öte yandan çalışan kodlara dokunmak istemediğimiz için eski kullanımları yeni projelere de taşımaya devam edebiliyoruz.
Bu nedenle proje, örnekleri farklı kategoriler altında topluyor:
| Kategori | Örnekler |
|---|---|
| Language | Records, sealed classes, pattern matching, switch expressions, var, unnamed variables |
| Collections | Immutable factory’ler, sequenced collections, unmodifiable collector’lar |
| Strings | Text blocks, isBlank(), strip(), repeat(), formatted() |
| Streams | toList(), mapMulti(), takeWhile(), gatherers |
| Concurrency | Virtual threads, structured concurrency, scoped values, ExecutorService |
| I/O | Files.readString(), Path.of(), transferTo(), HTTP Client |
| Errors | requireNonNullElse(), record tabanlı hatalar, helpful NPE |
| Date/Time | java.time, Duration, Period, DateTimeFormatter |
| Security | TLS, SecureRandom, KDF, PEM |
| Tooling | JShell, tek dosya çalıştırma, JFR, compact source files, AOT |
| Enterprise | EJB → CDI, JDBC → JPA / Jakarta Data, Spring yapılandırması |
Özellikle eski bir kod tabanını incelerken elimizdeki kullanımın modern Java’daki karşılığını hızlıca görmek için oldukça kullanışlı.
modern-java Agent Skill Nedir?
Bunun yanı sıra proje, yapay zeka tabanlı kodlama araçları için modern-java isminde bir agent skill’i de sunuyor.
Skill temel olarak üç adımda çalışıyor:
- Detect: Maven, Gradle, toolchain, CI ve runtime gibi kaynaklardan hedef Java sürümünü tespit ediyor.
- Bound: Önerileri bu Java sürümü ve öncesinde final olmuş özelliklerle sınırlandırıyor.
- Recommend: Kodu inceliyor ve uygun modern Java karşılıklarını öneriyor.
modern-java Skill Kurulumu
Örneğin Claude Code için repository’yi indirip skill’i ekleyebiliriz:
git clone --depth 1 https://github.com/javaevolved/javaevolved.github.io.git
mkdir -p ~/.claude/skills
cp -R javaevolved.github.io/agent-plugins/modern-java-development/skills/modern-java ~/.claude/skills/
Code language: JavaScript (javascript)
Ancak sadece belirli bir projede kullanmak istersek .claude/skills/modern-java altında tutmamız yeterli.
GitHub Copilot CLI tarafında ise:
copilot plugin marketplace add javaevolved/javaevolved.github.io
copilot plugin install modern-java-development@javaevolved
kullanabiliriz.
Örnek Proje: Eski Java ile Yazılmış Student API
Ardından skill’i biraz daha gerçekçi bir proje üzerinde denemek istedim.
Bunun için framework kullanmadan, JDK’nın com.sun.net.httpserver sunucusu üzerinde çalışan bir Student API hazırladım.
Proje; öğrenci CRUD işlemleri, ders kayıtları, kredi limiti, GNO hesaplama, transkript, istatistikler, CSV kalıcılığı, yedekleme, bildirim kuyruğu ve API key doğrulaması gibi özellikler içeriyor.
Ayrıca main branch’i Java 8 hedefliyor ve bilinçli olarak eski Java kullanımları içeriyor:
- POJO’lar ve
intsabitler Vector,Hashtable,Enumeration- Anonymous class’lar
SimpleDateFormatveCalendarinstanceof+ cast zincirleriwait/notifyTimer/TimerTask- double-checked locking
Randomile API key üretimiFileReader/FileWriterClass.newInstance()
Yani amacım bunların tamamını mekanik olarak değiştirmek değil, skill’in gerçek bir kod tabanında nasıl davrandığını görmekti.
Skill Projeyi Nasıl Ele Aldı ve Ne Yaptı?
İlk olarak projenin hedef Java sürümünü tespit etti.
Makinemde JDK 26 kurulu olmasına rağmen pom.xml içerisindeki Java 8 ayarını esas aldı:
selected: Java 8
source: maven-source
runtime: Java 26
Code language: HTTP (http)
Daha sonra modernizasyon hedefini Java 25 olarak verdiğimde ise mevcut Java 8 ayarı ile çakışmayı ayrıca raporladı.
Bu bence skill’in en önemli taraflarından biri. Makinedeki JDK sürümüne bakıp rastgele modern Java özelliği önermek yerine projenin gerçek build ayarlarını dikkate alıyor.
Önce yalnızca Java hedefini 25’e yükselttim ve mevcut testleri çalıştırdım. Sonuç olarak kod tarafında hiçbir değişiklik yapmadan 19 testin tamamı geçti.
Bundan sonra modernizasyon başladı.
Skill’in Yaptığı Modernizasyonlar
Bu aşamada skill, projedeki çok sayıda eski Java kullanımını modern karşılıklarıyla değiştirdi.
Örneğin klasik Student POJO’su record haline geldi:
Benzer şekilde int ile tutulan durumlar enum yapısına dönüştü.
Ayrıca uzun instanceof ve cast zincirlerinin yerini pattern matching for switch aldı:
Bunun yanı sıra skill, exception yapısını sealed class ile yeniden düzenledi ve HTTP response’larda record pattern kullandı.
Concurrency tarafında ise en belirgin değişikliklerden biri eski wait/notify kuyruğunun ortadan kalkması oldu.
Aynı şekilde:
Timer/TimerTask→ScheduledExecutorService- Fixed thread pool → Virtual Threads
- Request context →
ScopedValue SimpleDateFormat→java.timeRandom→SecureRandom- Elle hex üretimi →
HexFormat FileReader/FileWriter→Files+ UTF-8Class.newInstance()→getDeclaredConstructor().newInstance()trim().length() == 0→isBlank()- Anonymous Comparator →
Comparator.comparing() - JUnit 4 → JUnit 6
şeklinde dönüşümler de gerçekleşti.
Ancak burada önemli olan, her eski API’yi yenisiyle değiştirmek değil. Çünkü skill, kullanacağı özelliğin hedef Java sürümünde final olup olmadığını da dikkate alıyor.
Modernizasyon Sonrası Sonuçlar
Modernizasyon tamamlandığında iki branch arasında şöyle bir sonuç oluştu:
| Ölçüm | Java 8 | Java 25 |
|---|---|---|
javac -Xlint:all uyarısı | 269 | 0 |
| Java kod satırı | 2589 | 1963 |
| Birim test | 19 | 23 |
Böylece Java kodu yaklaşık %24 azaldı.
30 farklı HTTP senaryosunu iki branch üzerinde çalıştırarak sonuçlarını karşılaştırdım. Üstelik validation hataları, 401, 404, 409, transkript ve istatistik endpoint’leri dahil karşılaştırdığım HTTP çıktılarında fark oluşmadı.
Ayrıca modernizasyon sırasında eski koddaki birkaç problem de ortaya çıktı.
Örneğin başarısız bir öğrenci güncellemesinde 409 Conflict dönmesine rağmen mutable nesnenin bazı alanları değişebiliyordu. Buna karşın record tabanlı yeni yapı, nesneyi yalnızca bütün validation kuralları başarılı olduktan sonra kaydediyor.
Bunun dışında;
Randomile API key üretimi,- default locale ile
toLowerCase()kullanımı, - platform charset’ine bağlı dosya işlemleri,
- paylaşılan
SimpleDateFormat, InterruptedException‘ın yutulması
gibi problemler de modernizasyon sırasında ortadan kalktı.
Sonuç
Sonuç olarak java.evolved, eski Java kullanımlarının modern karşılıklarını hızlıca görmek için oldukça güzel bir kaynak.
modern-java agent skill ise bunun özellikle AI destekli geliştirme tarafındaki önemli bir problemini çözüyor: Kodlama asistanının önerilerini projenin gerçekten kullandığı Java sürümüne göre sınırlandırıyor.
Projenin Kaynak Kodu
main: Java 8 sürümümodernize/java-25: Java 25 sürümüMODERNIZATION.md: modernizasyon detayları
Leave a Reply