Java 25 Ekosisteminde Guava Kütüphanesi: Kapsamlı Rehber

20 Temmuz 2026 · netologist · 9 dakika, 1745 kelime ·

İçindekiler

  1. Giriş
  2. Kurulum
  3. Immutable (Değiştirilemez) Koleksiyonlar
  4. Yeni Koleksiyon Tipleri
  5. Caching (Önbellekleme)
  6. Concurrency (Eşzamanlılık) Araçları
  7. String İşlemleri
  8. I/O Yardımcıları
  9. Preconditions (Ön Koşullar)
  10. Fonksiyonel İdiomlar: Optional, Predicate, Function
  11. Matematik Yardımcıları
  12. Hashing
  13. EventBus
  14. Graph (Grafik) API’si
  15. Sıralama: Ordering ve ComparisonChain
  16. Guava ile Java 25’in Yeni Özellikleri
  17. Guava mı, Java Standart Kütüphanesi mi?
  18. En İyi Uygulamalar ve Tuzaklar
  19. Kaynaklar

Giriş

Guava, Google tarafından geliştirilen ve Java dünyasında onlarca yıldır kullanılan bir “çekirdek kütüphaneler” setidir (com.google.guava:guava). İçerisinde koleksiyonlar, önbellekleme, eşzamanlılık yardımcıları, string işlemleri, I/O yardımcıları, hashing, grafik yapıları ve daha fazlası bulunur.

Java zamanla java.util.Optional, List.of(), Map.of() gibi Guava’dan ilham alan özellikler kazandı; fakat Guava hâlâ birçok senaryoda daha zengin ve olgun bir API sunar. Java 25 (LTS, Eylül 2025’te yayımlandı) ile birlikte gelen sanal thread’ler (virtual threads), pattern matching, record’lar ve yapılandırılmış eşzamanlılık (structured concurrency) gibi özellikler Guava ile birlikte gayet uyumlu çalışır; Guava, JDK’nın sunmadığı tamamlayıcı araçları sağlamaya devam eder.

Güncel sürüm: Bu rehberin yazıldığı tarih itibarıyla Guava’nın güncel sürümü 33.6.0-jre‘dir (JRE varyantı; Android için -android varyantı mevcuttur). Guava, Java 8 ve üzerini destekler, dolayısıyla Java 25 ile tam uyumludur.

Not: Guava sürüm numaraları sık güncellenir; projenizde her zaman Maven Central üzerinden en güncel sürümü kontrol edin.


Kurulum

Maven

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>33.6.0-jre</version>
</dependency>

Gradle (Kotlin DSL)

dependencies {
    // Sadece implementasyonda kullanılacaksa:
    implementation("com.google.guava:guava:33.6.0-jre")

    // Guava tiplerini public API'de kullanacaksanız:
    api("com.google.guava:guava:33.6.0-jre")
}

Java 25 modül sistemi (JPMS) ile kullanım

Guava 33.4.8 ve sonrası, bir Java modülü olarak derlenmiştir. module-info.java içerisinde şu şekilde tanımlayabilirsiniz:

module com.benim.uygulamam {
    requires com.google.common;
}

Immutable (Değiştirilemez) Koleksiyonlar

Java’nın kendi List.of(), Map.of() metotları Guava’nın ImmutableList, ImmutableMap ailesinden ilham almıştır, ancak Guava daha zengin builder API’leri ve daha fazla esneklik sunar.

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;

// Basit oluşturma
ImmutableList<String> renkler = ImmutableList.of("kırmızı", "yeşil", "mavi");

// Builder ile
ImmutableMap<String, Integer> yaslar = ImmutableMap.<String, Integer>builder()
        .put("Ayşe", 30)
        .put("Mehmet", 25)
        .buildOrThrow(); // 33.x'te build() yerine buildOrThrow() önerilir

// Mevcut bir koleksiyondan kopyalama
List<String> kaynak = new ArrayList<>(List.of("a", "b", "c"));
ImmutableSet<String> kopya = ImmutableSet.copyOf(kaynak);

// Stream ile toplama
ImmutableList<Integer> kareler = Stream.of(1, 2, 3, 4)
        .map(x -> x * x)
        .collect(ImmutableList.toImmutableList());

Neden ImmutableList/Map kullanmalı?


Yeni Koleksiyon Tipleri

Guava, JDK’da bulunmayan birçok koleksiyon tipi sunar:

Multimap - Bir anahtara birden fazla değer

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;

Multimap<String, String> dersOgrenciler = ArrayListMultimap.create();
dersOgrenciler.put("Matematik", "Ali");
dersOgrenciler.put("Matematik", "Veli");
dersOgrenciler.put("Fizik", "Ayşe");

Collection<String> matematikOgrencileri = dersOgrenciler.get("Matematik");
// [Ali, Veli]

Multiset - Eleman sayısını tutan koleksiyon

import com.google.common.collect.HashMultiset;
import com.google.common.collect.Multiset;

Multiset<String> kelimeSayaci = HashMultiset.create();
for (String kelime : "elma armut elma muz elma armut".split(" ")) {
    kelimeSayaci.add(kelime);
}
System.out.println(kelimeSayaci.count("elma")); // 3

BiMap - İki yönlü eşleme

import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;

BiMap<String, Integer> isimSira = HashBiMap.create();
isimSira.put("Ali", 1);
isimSira.put("Veli", 2);

Integer sira = isimSira.get("Ali");           // 1
String isim = isimSira.inverse().get(2);      // Veli

Table - İki boyutlu anahtar-değer yapısı

import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;

Table<String, String, Double> notlar = HashBasedTable.create();
notlar.put("Ali", "Matematik", 85.0);
notlar.put("Ali", "Fizik", 90.0);
notlar.put("Veli", "Matematik", 70.0);

Double aliMatematik = notlar.get("Ali", "Matematik"); // 85.0
Map<String, Double> aliTumNotlari = notlar.row("Ali");

RangeSet / RangeMap - Aralık tabanlı veri yapıları

import com.google.common.collect.Range;
import com.google.common.collect.RangeSet;
import com.google.common.collect.TreeRangeSet;

RangeSet<Integer> araliklar = TreeRangeSet.create();
araliklar.add(Range.closed(1, 5));
araliklar.add(Range.closed(10, 15));
araliklar.add(Range.closed(4, 11)); // birleşir -> [1, 15]

boolean icindeMi = araliklar.contains(7); // true

Caching (Önbellekleme)

Guava’nın LoadingCache yapısı, Caffeine yaygınlaşmadan önce Java’da en çok tercih edilen bellek içi önbellekleme çözümüydü ve hâlâ birçok eski/yeni projede aktif kullanılır.

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;

import java.util.concurrent.TimeUnit;

LoadingCache<String, ExpensiveObject> onbellek = CacheBuilder.newBuilder()
        .maximumSize(1000)
        .expireAfterWrite(10, TimeUnit.MINUTES)
        .expireAfterAccess(5, TimeUnit.MINUTES)
        .recordStats()
        .build(new CacheLoader<String, ExpensiveObject>() {
            @Override
            public ExpensiveObject load(String anahtar) {
                return maliyetliHesapla(anahtar);
            }
        });

ExpensiveObject deger = onbellek.getUnchecked("anahtar1");
System.out.println(onbellek.stats()); // isabet oranı, kaçırma sayısı vb.

Java 25 ile ilişkisi: Sanal thread’lerle yüksek eşzamanlı I/O senaryolarında LoadingCache‘in synchronized bloklarına dayalı bazı iç mekanizmaları thread pinning’e yol açabilir. Yoğun sanal thread kullanımı olan projelerde (özellikle expireAfterAccess gibi zaman damgası güncellemesi gerektiren durumlarda), Caffeine kütüphanesine geçiş değerlendirilebilir; ancak orta ölçekli, senkron çalışan uygulamalarda Guava Cache hâlâ gayet performanslıdır.


Concurrency (Eşzamanlılık) Araçları

ListenableFuture ve Futures

import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;

import java.util.concurrent.Executors;

ListeningExecutorService havuz =
        MoreExecutors.listeningDecorator(Executors.newVirtualThreadPerTaskExecutor());

ListenableFuture<String> gelecek = havuz.submit(() -> {
    Thread.sleep(100);
    return "sonuç";
});

Futures.addCallback(gelecek, new FutureCallback<String>() {
    @Override
    public void onSuccess(String sonuc) {
        System.out.println("Başarılı: " + sonuc);
    }

    @Override
    public void onFailure(Throwable hata) {
        System.err.println("Hata: " + hata.getMessage());
    }
}, havuz);

Dikkat: Java 25’te Executors.newVirtualThreadPerTaskExecutor() ile MoreExecutors.listeningDecorator(...) gayet uyumlu çalışır; Guava’nın ListenableFuture‘ı, CompletableFuture‘dan önceki dönemde geliştirilmiş olsa da callback tabanlı zincirleme senaryolarında hâlâ tercih edilebilir bir API sunar.

RateLimiter - Hız sınırlama

import com.google.common.util.concurrent.RateLimiter;

RateLimiter limiter = RateLimiter.create(5.0); // saniyede 5 istek

for (int i = 0; i < 10; i++) {
    limiter.acquire(); // gerekirse bekler
    apiCagrisiYap();
}

Striped - Anahtar bazlı kilitler

import com.google.common.util.concurrent.Striped;
import java.util.concurrent.locks.Lock;

Striped<Lock> kilitler = Striped.lock(16);

Lock kilit = kilitler.get(kullaniciId);
kilit.lock();
try {
    kullaniciBakiyesiGuncelle(kullaniciId);
} finally {
    kilit.unlock();
}

Monitor - synchronized’a modern alternatif

import com.google.common.util.concurrent.Monitor;

Monitor monitor = new Monitor();

monitor.enter();
try {
    // kritik bölge
} finally {
    monitor.leave();
}

String İşlemleri

Joiner ve Splitter

import com.google.common.base.Joiner;
import com.google.common.base.Splitter;

String birlesik = Joiner.on(", ").skipNulls().join("a", null, "b", "c");
// "a, b, c"

List<String> parcalar = Splitter.on(",")
        .trimResults()
        .omitEmptyStrings()
        .splitToList(" elma, , armut ,muz");
// [elma, armut, muz]

CharMatcher

import com.google.common.base.CharMatcher;

String temiz = CharMatcher.whitespace().trimFrom("   merhaba dünya   ");
String sadeceRakamlar = CharMatcher.inRange('0', '9').retainFrom("Ürün-Kodu-4521-AX");
// "4521"

Strings sınıfı

import com.google.common.base.Strings;

String bosSaKontrol = Strings.nullToEmpty(null); // ""
boolean bosMu = Strings.isNullOrEmpty("");        // true
String doldurulmus = Strings.padStart("42", 5, '0'); // "00042"

I/O Yardımcıları

import com.google.common.io.Files;
import com.google.common.io.ByteStreams;
import com.google.common.io.CharStreams;

import java.io.File;
import java.nio.charset.StandardCharsets;

// Dosya içeriğini okuma
String icerik = Files.asCharSource(new File("veri.txt"), StandardCharsets.UTF_8).read();

// Dosyaya yazma
Files.asCharSink(new File("cikti.txt"), StandardCharsets.UTF_8).write("merhaba dünya");

// Bir dizini gezme
Files.fileTraverser().depthFirstPreOrder(new File("./proje"))
        .forEach(dosya -> System.out.println(dosya.getName()));

Not: Java 25’te java.nio.file.Files çoğu senaryo için yeterlidir (Files.readString, Files.writeString gibi metotlarla); Guava’nın I/O paketi ise ByteSource/CharSource gibi kompozisyona uygun soyutlamalarıyla daha karmaşık veri akışı senaryolarında değerli olmaya devam eder.


Preconditions (Ön Koşullar)

import static com.google.common.base.Preconditions.*;

public void kullaniciOlustur(String isim, int yas) {
    checkNotNull(isim, "İsim boş olamaz");
    checkArgument(yas >= 0, "Yaş negatif olamaz: %s", yas);
    checkState(veritabaniBagliMi(), "Veritabanı bağlantısı yok");
    // ...
}

Java 25’in pattern matching ve record’larıyla birlikte kullanıldığında, Preconditions sınıfı özellikle record kurucularında (compact constructor) doğrulama yapmak için hâlâ pratik bir seçenektir:

public record Kullanici(String isim, int yas) {
    public Kullanici {
        checkArgument(yas >= 0, "Yaş negatif olamaz: %s", yas);
        checkNotNull(isim);
    }
}

Fonksiyonel İdiomlar

Guava Optional vs java.util.Optional

Java 8 öncesinde Guava’nın kendi com.google.common.base.Optional sınıfı vardı. Günümüzde yeni kodda java.util.Optional tercih edilmelidir; Guava’nın Optional‘ı ise eski API’lerle uyum için hâlâ mevcuttur ve iki tür arasında dönüşüm sağlanabilir:

import com.google.common.base.Optional;

Optional<String> guavaOpt = Optional.of("değer");
java.util.Optional<String> javaOpt = guavaOpt.toJavaUtil();

Predicates ve Functional Idioms

import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;

Predicate<String> uzunMu = s -> s.length() > 5;
Collection<String> uzunlar = Collections2.filter(List.of("kısa", "oldukça uzun kelime"), uzunMu);

Not: Java 8’in java.util.function.Predicate‘i ve Stream API’si, günlük filtreleme/dönüştürme işlerinde artık birinci tercih olmalıdır. Guava’nın fonksiyonel yardımcıları, eski API’lerle (örneğin Multimaps.filterValues) entegrasyon gerektiğinde önem taşır.


Matematik Yardımcıları

import com.google.common.math.IntMath;
import com.google.common.math.LongMath;
import com.google.common.math.DoubleMath;

int ebob = IntMath.gcd(48, 18);               // 6
boolean asalMi = IntMath.isPrime(17);         // true
int tavan = IntMath.divide(7, 2, java.math.RoundingMode.CEILING); // 4

long faktoriyel = LongMath.factorial(10);
boolean yaklasikEsit = DoubleMath.fuzzyEquals(0.1 + 0.2, 0.3, 1e-9); // true

Hashing

import com.google.common.hash.Hashing;
import com.google.common.hash.HashFunction;
import com.google.common.hash.HashCode;

HashFunction hf = Hashing.sha256();
HashCode hash = hf.hashString("merhaba dünya", StandardCharsets.UTF_8);
System.out.println(hash.toString());

// Bloom Filter
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;

BloomFilter<String> filtre = BloomFilter.create(Funnels.stringFunnel(StandardCharsets.UTF_8), 1_000_000, 0.01);
filtre.put("kullanici123");
boolean muhtemelenVar = filtre.mightContain("kullanici123"); // true (yanlış pozitif olabilir, yanlış negatif olamaz)

EventBus

Guava’nın EventBus‘ı basit, uygulama içi yayın/abone (pub-sub) modeli sunar:

import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;

class SiparisDinleyici {
    @Subscribe
    public void siparisOlusturuldu(SiparisOlayi olay) {
        System.out.println("Yeni sipariş: " + olay.getSiparisId());
    }
}

EventBus veriYolu = new EventBus();
veriYolu.register(new SiparisDinleyici());
veriYolu.post(new SiparisOlayi("SIP-1001"));

Not: Yeni projelerde reaktif akışlar veya Java 25’in yapılandırılmış eşzamanlılığı (structured concurrency, StructuredTaskScope) tercih edilebilir; ancak basit, tek JVM içi olay yönetimi için EventBus hâlâ hafif ve kullanışlı bir seçenektir.


Graph (Grafik) API’si

com.google.common.graph paketi, yönlü/yönsüz grafik yapıları modellemek için kullanılır:

import com.google.common.graph.GraphBuilder;
import com.google.common.graph.MutableGraph;

MutableGraph<String> sehirGrafigi = GraphBuilder.undirected().build();
sehirGrafigi.putEdge("İstanbul", "Ankara");
sehirGrafigi.putEdge("Ankara", "İzmir");

Set<String> komsular = sehirGrafigi.adjacentNodes("Ankara");
// [İstanbul, İzmir]

Sıralama: Ordering ve ComparisonChain

import com.google.common.collect.Ordering;
import com.google.common.collect.ComparisonChain;

Ordering<String> uzunlugaGore = Ordering.natural().onResultOf(String::length);
List<String> siraliListe = uzunlugaGore.sortedCopy(List.of("uzun kelime", "az", "orta"));

public int compareTo(Kullanici diger) {
    return ComparisonChain.start()
            .compare(this.soyad, diger.soyad)
            .compare(this.ad, diger.ad)
            .compare(this.yas, diger.yas)
            .result();
}

Guava ile Java 25’in Yeni Özellikleri

Java 25 (LTS), önceki sürümlerden gelen birçok özelliği kalıcı hale getirdi ve yeni önizlemeler ekledi. Guava ile etkileşimleri şu şekilde özetlenebilir:

Java 25 ÖzelliğiGuava ile İlişkisi
Sanal Thread’ler (Virtual Threads)MoreExecutors.listeningDecorator() ile Executors.newVirtualThreadPerTaskExecutor() birlikte kullanılabilir. Striped kilitleri ve synchronized bloklu eski Guava API’leri sanal thread pinning riski taşıyabilir; kritik yollarda ReentrantLock tabanlı alternatifler tercih edilebilir.
Record’larPreconditions ile compact constructor doğrulamaları; ImmutableMap/ImmutableList record alanlarında değişmezliği pekiştirmek için idealdir.
Pattern Matching (switch ifadeleri)Guava’nın Range, Optional gibi tipleriyle birlikte okunabilir switch blokları yazılabilir.
Yapılandırılmış Eşzamanlılık (Structured Concurrency)StructuredTaskScope, Guava’nın ListenableFuture tabanlı callback modeline göre daha modern bir alternatiftir; yeni kodda structured concurrency, eski kodda ListenableFuture bir arada bulunabilir.
Modül Sistemi (JPMS)Guava 33.4.8+ artık gerçek bir Java modülü; module-info.java ile temiz entegrasyon sağlanır.

Guava mı, Java Standart Kütüphanesi mi?

İhtiyaçÖnerilen
Basit değişmez liste/map/setJava List.of()/Map.of() (basit durumlar) veya Guava ImmutableList (builder, zengin API gerektiğinde)
Multimap, Multiset, BiMap, TableGuava (JDK’da karşılığı yok)
Bellek içi önbelleklemeGuava LoadingCache veya Caffeine (yüksek performans/sanal thread yoğun senaryolar için)
Optionaljava.util.Optional (yeni kod için)
String birleştirme/bölmeGuava Joiner/Splitter (zengin seçenekler) veya String.join/split (basit durumlar)
Asenkron programlamaJava CompletableFuture / sanal thread’ler (yeni kod) veya Guava ListenableFuture (eski kod tabanı, callback zincirleme)
Hashing / Bloom FilterGuava (JDK’da Bloom Filter yok)
Grafik veri yapılarıGuava common.graph

En İyi Uygulamalar ve Tuzaklar

  1. @Beta API’lerden kaçının: Guava’da @Beta işaretli sınıflar herhangi bir zamanda değişebilir veya kaldırılabilir. Kütüphane geliştiriyorsanız Guava Beta Checker kullanın.
  2. buildOrThrow() kullanın: ImmutableMap.Builder.build() yerine, çakışan anahtarlarda daha net hata mesajı veren buildOrThrow() tercih edilmelidir.
  3. Modül geçişine dikkat: 33.4.5–33.4.7 sürümlerinde modülerleştirme ile ilgili bilinen sorunlar vardı; doğrudan 33.4.8 veya sonrası kullanın.
  4. Sanal thread’lerle senkronizasyon: synchronized blok içeren eski Guava API’lerini yoğun sanal thread kullanılan kod yollarında dikkatli kullanın (thread pinning riski).
  5. Gereksiz bağımlılık şişkinliğinden kaçının: Sadece birkaç yardımcı metot için tüm Guava’yı eklemek yerine, gerçekten ihtiyaç olup olmadığını değerlendirin; modern JDK birçok temel ihtiyacı zaten karşılıyor.
  6. Nullness açıklamaları: Yeni Guava sürümleri JSpecify null-safety açıklamalarına geçiş yapıyor; Kotlin ile birlikte kullanıyorsanız derleme uyarılarına dikkat edin.

Kaynaklar


Bu belge, Guava 33.6.0-jre sürümü ve Java 25 (LTS) baz alınarak hazırlanmıştır. Kütüphane sürümleri sık güncellendiğinden, üretim projelerinde her zaman güncel sürüm notlarını kontrol ediniz.