Java’nin Temelleri
2026
---
title: "Java Programlama Kontrol Rehberi: Sık Hatalar ve Kod Kalitesi"
subtitle: "Profesyonel Java Geliştiricileri İçin Kapsamlı Rehber"
author: "Teknik İçerik Ekibi"
date: "2024"
lang: "tr"
keywords: ["Java", "kod kalitesi", "hata desenleri", "kod review", "clean code"]
abstract: "Bu bölüm, Java programlamada sık karşılaşılan hataları, kod kalite standartlarını ve en iyi uygulamaları kapsamlı bir şekilde ele alır. Kod review süreçleri için checklist ve pratik örnekler sunar."
license: "CC BY-NC-SA 4.0"
---Pedagojik Not: Bu bölüm, Java geliştiricilerinin günlük çalışmalarında karşılaştıkları yaygın hataları ve bunları önleme yöntemlerini öğretmeyi amaçlar. Her konsept, gerçek dünya senaryoları ve kod örnekleriyle desteklenmiştir.
Java programlama dünyasında, sadece çalışan kod yazmak yeterli değildir. Profesyonel bir geliştirici olarak, kodunuzun kalitesi, bakımı, okunabilirliği ve genişletilebilirliği de en az işlevselliği kadar önemlidir. Bu bölümde, sık yapılan hataları tanıyacak, kod kalite standartlarını öğrenecek ve etkili kod review süreçleri için gerekli araçları kazanacaksınız.
Kod kalitesi, bir yazılımın belirli standartlara uygunluğunu ve beklenen davranışları sergileme yeteneğini ifade eder. İyi kalite kod, sadece doğru çalışmakla kalmaz, aynı zamanda okunabilir, bakımı kolay ve genişletilebilir olmalıdır.
### 1.1 İyi Kalite Kodun Faydaları
İyi kalite kod, yazılım geliştirme sürecinde uzun vadeli faydalar sağlar:
Kötü kod (technical debt) aşağıdaki sorunlara yol açar:
Bu bölümde, Java geliştiricilerinin en sık karşılaştığı hata desenlerini inceleyeceğiz.
NullPointerException, Java’da en yaygın runtime hatasıdır.
// NullSafetyExample.java
public class NullSafetyExample {
// Hatalı yaklaşım
public String getCityNameHatali(User user) {
return user.getAddress().getCity().getName();
// NullPointerException riski!
}
// Doğru yaklaşım - null kontrolleri ile
public String getCityNameDogru(User user) {
if (user == null) return "Bilinmiyor";
Address address = user.getAddress();
if (address == null) return "Bilinmiyor";
City city = address.getCity();
if (city == null) return "Bilinmiyor";
return city.getName();
}
// Modern yaklaşım - Optional kullanımı
public String getCityNameModern(User user) {
return Optional.ofNullable(user)
.map(User::getAddress)
.map(Address::getCity)
.map(City::getName)
.orElse("Bilinmiyor");
}
}İpucu: Java 8’den itibaren
Optionalsınıfı, null güvenliği için güçlü bir araç sunar. Ancak, Optional’ı metod parametreleri veya alanlar için değil, dönüş değerleri için kullanın.
Döngü ve koşul yapılarındaki hatalar, mantıksal hatalara yol açar.
// LoopConditionExample.java
public class LoopConditionExample {
// Hatalı - sonsuz döngü
public void sonsuzDongu() {
int i = 0;
while (i < 10) {
System.out.println(i);
// i değeri artırılmıyor!
}
}
// Doğru
public void dogruDongu() {
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
}
// Hatalı - off-by-one hatası
public int[] yanlisDiziKopyala(int[] kaynak) {
int[] hedef = new int[kaynak.length];
for (int i = 0; i <= kaynak.length; i++) { // <= hatalı!
hedef[i] = kaynak[i];
}
return hedef;
}
// Doğru
public int[] dogruDiziKopyala(int[] kaynak) {
int[] hedef = new int[kaynak.length];
for (int i = 0; i < kaynak.length; i++) {
hedef[i] = kaynak[i];
}
return hedef;
}
}Kaynakların doğru yönetilmemesi, bellek sızıntılarına ve performans sorunlarına yol açar.
// ResourceManagementExample.java
import java.io.*;
public class ResourceManagementExample {
// Hatalı - kaynak kapatılmıyor
public void hataliDosyaOkuma(String dosyaYolu) throws IOException {
BufferedReader reader = new BufferedReader(new FileReader(dosyaYolu));
String line = reader.readLine();
System.out.println(line);
// reader.close() çağrılmıyor!
}
// Doğru - try-with-resources (Java 7+)
public void dogruDosyaOkuma(String dosyaYolu) {
try (BufferedReader reader = new BufferedReader(new FileReader(dosyaYolu))) {
String line = reader.readLine();
System.out.println(line);
} catch (IOException e) {
e.printStackTrace();
}
}
// Hatalı - finally bloğunda null kontrolü yok
public void hataliKaynakYonetimi(String dosyaYolu) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(dosyaYolu));
// işlemler
} catch (IOException e) {
e.printStackTrace();
} finally {
reader.close(); // NullPointerException riski!
}
}
// Doğru - finally bloğunda null kontrolü
public void dogruKaynakYonetimi(String dosyaYolu) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(dosyaYolu));
// işlemler
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}Çoklu iş parçacığı (multithreading) ortamında sık karşılaşılan hatalar.
// ConcurrencyExample.java
public class ConcurrencyExample {
private int counter = 0;
// Hatalı - thread-safe değil
public void incrementHatali() {
counter++; // atomik değil!
}
// Doğru - synchronized metod
public synchronized void incrementDogru() {
counter++;
}
// Alternatif - AtomicInteger
private java.util.concurrent.atomic.AtomicInteger atomicCounter =
new java.util.concurrent.atomic.AtomicInteger(0);
public void incrementAtomic() {
atomicCounter.incrementAndGet();
}
}String’lerin immutable olduğunu unutmak, performans sorunlarına yol açar.
// StringExample.java
public class StringExample {
// Hatalı - çok sayıda String nesnesi oluşturur
public String hataliStringBirlestirme(String[] kelimeler) {
String sonuc = "";
for (String kelime : kelimeler) {
sonuc += kelime + " "; // Her iterasyonda yeni String!
}
return sonuc;
}
// Doğru - StringBuilder kullanımı
public String dogruStringBirlestirme(String[] kelimeler) {
StringBuilder sb = new StringBuilder();
for (String kelime : kelimeler) {
sb.append(kelime).append(" ");
}
return sb.toString().trim();
}
}equals() ve hashCode() metodlarının uyumsuz implementasyonu, koleksiyonlarla ilgili hatalara yol açar.
// EqualsHashCodeExample.java
import java.util.Objects;
public class EqualsHashCodeExample {
private final int id;
private final String name;
public EqualsHashCodeExample(int id, String name) {
this.id = id;
this.name = name;
}
// Doğru equals implementasyonu
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
EqualsHashCodeExample that = (EqualsHashCodeExample) o;
return id == that.id && Objects.equals(name, that.name);
}
// Doğru hashCode implementasyonu
@Override
public int hashCode() {
return Objects.hash(id, name);
}
}Etkili bir kod review süreci için aşağıdaki kontrol listesini kullanın.
### 3.1 İsimlendirme Kuralları
| Öğe | Kural | Örnek |
|---|---|---|
| Sınıf | PascalCase | CustomerService |
| Metod | camelCase | getCustomerById() |
| Değişken | camelCase | customerName |
| Sabit | UPPER_SNAKE_CASE | MAX_RETRY_COUNT |
| Paket | lowercase | com.company.project |
// MethodDesignExample.java
public class MethodDesignExample {
// Hatalı - çok fazla sorumluluk
public void processOrder(Order order) {
// Validasyon
if (order == null || order.getItems().isEmpty()) {
throw new IllegalArgumentException("Geçersiz sipariş");
}
// Fiyat hesaplama
double total = 0;
for (Item item : order.getItems()) {
total += item.getPrice() * item.getQuantity();
}
// İndirim uygulama
if (order.getCustomer().isPremium()) {
total *= 0.9;
}
// Veritabanı kaydetme
saveToDatabase(order, total);
// Email gönderme
sendEmail(order.getCustomer().getEmail(), total);
}
// Doğru - tek sorumluluk
public void processOrderDogru(Order order) {
validateOrder(order);
double total = calculateTotal(order);
double discountedTotal = applyDiscount(order, total);
saveOrder(order, discountedTotal);
sendConfirmationEmail(order, discountedTotal);
}
private void validateOrder(Order order) {
if (order == null || order.getItems().isEmpty()) {
throw new IllegalArgumentException("Geçersiz sipariş");
}
}
private double calculateTotal(Order order) {
return order.getItems().stream()
.mapToDouble(item -> item.getPrice() * item.getQuantity())
.sum();
}
private double applyDiscount(Order order, double total) {
return order.getCustomer().isPremium() ? total * 0.9 : total;
}
}SOLID, nesne yönelimli programlamada beş temel prensibi ifade eder:
| Prensip | Açıklama |
|---|---|
| Single Responsibility | Bir sınıfın tek bir sorumluluğu olmalı |
| Open/Closed | Genişletmeye açık, değişikliğe kapalı |
| Liskov Substitution | Alt sınıflar, üst sınıfların yerine geçebilmeli |
| Interface Segregation | Küçük, spesifik interface’ler |
| Dependency Inversion | Soyutlamalara bağımlı olun, somut sınıflara değil |
Yaygın kullanılan tasarım desenleri:
Temiz Kod İlkeleri: - Kodu yorumlarla değil, kodun kendisiyle açıklayın - Anlamlı isimler kullanın - Fonksiyonlar küçük olmalı - DRY (Don’t Repeat Yourself) prensibi - YAGNI (You Aren’t Gonna Need It)
// PerformanceExample.java
import java.util.*;
public class PerformanceExample {
// Hatalı - gereksiz nesne oluşturma
public boolean hataliContains(List<String> list, String value) {
return list.contains(new String(value)); // Gereksiz String nesnesi!
}
// Doğru
public boolean dogruContains(List<String> list, String value) {
return list.contains(value);
}
// Hatalı - StringBuilder yerine String birleştirme
public String hataliLogOlustur(String[] messages) {
String log = "";
for (String msg : messages) {
log += msg + "\n"; // Her seferinde yeni String
}
return log;
}
// Doğru
public String dogruLogOlustur(String[] messages) {
StringBuilder sb = new StringBuilder();
for (String msg : messages) {
sb.append(msg).append("\n");
}
return sb.toString();
}
// Hatalı - ArrayList yerine LinkedList kullanımı
public void hataliListeKullanimi() {
List<Integer> list = new LinkedList<>();
for (int i = 0; i < 100000; i++) {
list.add(i); // LinkedList'te add O(1), get O(n)
}
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i)); // Çok yavaş!
}
}
// Doğru
public void dogruListeKullanimi() {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 100000; i++) {
list.add(i); // ArrayList'te add O(1)
}
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i)); // ArrayList'te get O(1)
}
}
// Alternatif - for-each döngüsü
public void dogruListeKullanimiForEach() {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 100000; i++) {
list.add(i);
}
for (Integer value : list) {
System.out.println(value);
}
}
}Bu bölümde, Java programlamada kod kalitesinin önemini, sık yapılan hata desenlerini, kod review checklist’ini ve en iyi uygulamaları öğrendik.
| Terim | Açıklama |
|---|---|
| Technical Debt | Kötü kodun gelecekte yaratacağı ek maliyet |
| NullPointerException | Null referans üzerinden metod çağırma hatası |
| Thread-safe | Çoklu iş parçacığında güvenli çalışan kod |
| Immutable | Oluşturulduktan sonra değiştirilemeyen nesne |
| Refactoring | Kodu dış davranışını değiştirmeden iyileştirme |
| SOLID | Nesne yönelimli programlamada beş temel prensip |
| DRY | Don’t Repeat Yourself - Kendini Tekrarlama |
| YAGNI | You Aren’t Gonna Need It - İhtiyacın Olmayacak |
Alıştırma 1: Null Güvenliği Aşağıdaki kodu null-safe hale getirin:
public String getUserFullName(User user) {
return user.getFirstName() + " " + user.getLastName();
}Alıştırma 2: Kaynak Yönetimi Aşağıdaki kodu try-with-resources kullanarak yeniden yazın:
public void readFile(String path) throws IOException {
FileInputStream fis = new FileInputStream(path);
BufferedReader br = new BufferedReader(new InputStreamReader(fis));
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
br.close();
}Alıştırma 3: Concurrency Aşağıdaki sınıfı thread-safe hale getirin:
public class Counter {
private int count = 0;
public void increment() {
count++;
}
public int getCount() {
return count;
}
}Alıştırma 4: Kod Review Aşağıdaki kodu review edin ve hataları bulun:
public class CustomerService {
public void saveCustomer(String name, String email, String phone) {
// TODO: validasyon ekle
Customer customer = new Customer();
customer.setName(name);
customer.setEmail(email);
customer.setPhone(phone);
// veritabanına kaydet
database.save(customer);
// email gönder
emailService.send(email, "Hoşgeldiniz!");
}
}Alıştırma 5: Performans Aşağıdaki kodu performans açısından iyileştirin:
public String generateReport(List<Transaction> transactions) {
String report = "";
for (Transaction t : transactions) {
report += t.getId() + " - " + t.getAmount() + "\n";
}
return report;
}Son Not: Kod kalitesi bir yolculuktur, varış noktası değil. Sürekli öğrenme ve iyileştirme ile kodunuzu her gün biraz daha iyi hale getirebilirsiniz. Unutmayın: “Her zaman kodu, bir sonraki geliştiricinin bir psikopat olacağını ve senin adresini bildiğini düşünerek yaz.”