46 Effective Java İpuçları

Bu belge, Java programlama dilinde daha etkili kod yazmanıza yardımcı olacak 50 önemli ipucu içermektedir. Her ipucu, kısa bir açıklama ve örnek kod içerir.




1. Static Factory Metodları Kullanın

Yapıcılar yerine static factory metodları kullanmak, nesne oluşturma sürecini daha esnek hale getirir.

java
public class User { private String name; private int age; private User(String name, int age) { this.name = name; this.age = age; } public static User createAdult(String name) { return new User(name, 18); } public static User createChild(String name) { return new User(name, 10); } }

2. Builder Desenini Kullanın

Çok parametreli yapıcılar yerine Builder deseni kullanmak, daha okunabilir ve esnek kod sağlar.

java
public class Pizza { private final String size; private final boolean cheese; private final boolean pepperoni; private Pizza(Builder builder) { this.size = builder.size; this.cheese = builder.cheese; this.pepperoni = builder.pepperoni; } public static class Builder { private final String size; private boolean cheese = false; private boolean pepperoni = false; public Builder(String size) { this.size = size; } public Builder cheese(boolean value) { cheese = value; return this; } public Builder pepperoni(boolean value) { pepperoni = value; return this; } public Pizza build() { return new Pizza(this); } } } // Kullanım Pizza pizza = new Pizza.Builder("large") .cheese(true) .pepperoni(true) .build();

3. Singleton Desenini Enum ile Uygulayın

Singleton deseni uygulamanın en güvenli yolu, enum kullanmaktır.

java
public enum Singleton { INSTANCE; public void doSomething() { // method implementation } } // Kullanım Singleton.INSTANCE.doSomething();

4. Gereksiz Nesne Oluşturmaktan Kaçının

Gereksiz nesne oluşturmak performansı düşürebilir. Mümkün olduğunda, nesneleri yeniden kullanın.

java
// Kötü (her çağrıda yeni bir nesne oluşturur) String s = new String("hello"); // İyi (String havuzunu kullanır) String s = "hello";

5. Kullanılmayan Nesneleri Temizleyin

Artık kullanılmayan nesneleri null'a atayarak, garbage collector'a bu nesnelerin temizlenebileceğini bildirin.

java
public class Stack { private Object[] elements; private int size = 0; public Object pop() { if (size == 0) throw new EmptyStackException(); Object result = elements[--size]; elements[size] = null; // Kullanılmayan referansı temizle return result; } }

6. finalizer ve cleaner Kullanımından Kaçının

finalizer ve cleaner metodları öngörülemez ve genellikle tehlikelidir. Bunun yerine, AutoCloseable arayüzünü uygulayın.

java
public class Resource implements AutoCloseable { public void doSomething() { // resource kullanımı } @Override public void close() { // resource temizleme işlemleri } } // Kullanım try (Resource resource = new Resource()) { resource.doSomething(); } // close() otomatik olarak çağrılır

7. try-with-resources Kullanın

Kapatılması gereken kaynaklar için try-with-resources kullanın. Bu, kodunuzu daha temiz ve hata ayıklamasını daha kolay hale getirir.

java
try (BufferedReader br = new BufferedReader(new FileReader(path))) { return br.readLine(); }

8. Eşitlik için equals() Metodunu Geçersiz Kılın

Nesnelerin mantıksal eşitliğini kontrol etmek için equals() metodunu geçersiz kılın.

java
public class Point { private final int x; private final int y; // constructor @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Point)) return false; Point point = (Point) o; return x == point.x && y == point.y; } }

9. equals() Geçersiz Kılındığında hashCode() da Geçersiz Kılın

equals() metodunu geçersiz kıldığınızda, her zaman hashCode() metodunu da geçersiz kılın. Bu, HashMap ve HashSet gibi hash tabanlı koleksiyonlarda doğru çalışmayı sağlar.

java
public class Point { private final int x; private final int y; // constructor ve equals metodu @Override public int hashCode() { return Objects.hash(x, y); } }

10. toString() Metodunu Her Zaman Geçersiz Kılın

toString() metodunu geçersiz kılmak, nesnelerinizin anlamlı string temsillerini sağlar ve hata ayıklamayı kolaylaştırır.

java
public class Point { private final int x; private final int y; // constructor, equals ve hashCode metodları @Override public String toString() { return String.format("Point(%d, %d)", x, y); } }

11. Değiştirilemez Sınıflar Oluşturun

Mümkün olduğunca değiştirilemez (immutable) sınıflar oluşturun. Bu, thread-safe ve daha güvenli kod yazmanıza yardımcı olur.

java
public final class ImmutablePoint { private final int x; private final int y; public ImmutablePoint(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public int getY() { return y; } }

12. Kalıtım Yerine Kompozisyonu Tercih Edin

Kalıtım yerine kompozisyon kullanmak, daha esnek ve bakımı kolay kod sağlar.

java
// Kalıtım yerine public class Stack<E> extends Vector<E> { ... } // Kompozisyon kullanarak public class Stack<E> { private Vector<E> vector = new Vector<>(); public void push(E item) { vector.add(item); } public E pop() { return vector.remove(vector.size() - 1); } }

13. Soyut Sınıflar Yerine Arayüzleri Tercih Edin

Arayüzler, çoklu kalıtıma izin verir ve daha esnek bir tasarım sağlar.

java
public interface Drawable { void draw(); } public class Circle implements Drawable { @Override public void draw() { // Çember çizme işlemi } }

14. Fonksiyonel Arayüzler İçin Lambda İfadelerini Kullanın

Java 8 ve sonrasında, anonim sınıflar yerine lambda ifadelerini kullanın. Bu, kodunuzu daha kısa ve okunabilir hale getirir.

java
// Anonim sınıf kullanımı Collections.sort(list, new Comparator<String>() { @Override public int compare(String s1, String s2) { return s1.length() - s2.length(); } }); // Lambda ifadesi kullanımı Collections.sort(list, (s1, s2) -> s1.length() - s2.length());

15. Stream API'sini Etkin Kullanın

Java 8 ile gelen Stream API'si, koleksiyonlar üzerinde fonksiyonel stil işlemler yapmanıza olanak tanır.

java
List<String> filtered = list.stream() .filter(s -> s.startsWith("A")) .map(String::toUpperCase) .collect(Collectors.toList());

16. Optional Kullanarak null Dönüşlerden Kaçının

Metotlarınızdan null döndürmek yerine Optional kullanın. Bu, NullPointerException riskini azaltır.

java
public Optional<User> findUserById(int id) { // User bulunursa if (userExists(id)) { return Optional.of(new User(id)); } // User bulunamazsa return Optional.empty(); } // Kullanım Optional<User> user = findUserById(1); user.ifPresent(System.out::println);

17. Checked Exceptions'ları Dikkatli Kullanın

Checked exceptions'ları sadece geri kazanılabilir durumlarda kullanın. Aksi takdirde, runtime exceptions kullanmayı düşünün.

java
// Checked exception public void readFile(String path) throws IOException { // Dosya okuma işlemleri } // Runtime exception public int divide(int a, int b) { if (b == 0) { throw new IllegalArgumentException("Divisor cannot be zero"); } return a / b; }

18. Standart Exceptions Kullanın

Mümkün olduğunca, kendi özel exception sınıflarınızı oluşturmak yerine Java'nın standart exception sınıflarını kullanın.

java
// İyi kullanım throw new IllegalArgumentException("Age must be positive"); // Yerine // throw new InvalidAgeException("Age must be positive");

19. Hata Kodları Yerine Exceptions Kullanın

Metotlarınızdan hata kodları döndürmek yerine exceptions fırlatın. Bu, hata yönetimini daha net ve güvenilir hale getirir.

java
// Kötü public int withdraw(double amount) { if (amount > balance) { return -1; // Hata kodu } balance -= amount; return 0; // Başarı kodu } // İyi public void withdraw(double amount) throws InsufficientFundsException { if (amount > balance) { throw new InsufficientFundsException(); } balance -= amount; }

20. Generics Kullanın

Tip güvenliği sağlamak ve runtime hatalarını önlemek için generics kullanın.

java
// Generic olmayan versiyon List list = new ArrayList(); list.add("hello"); String s = (String) list.get(0); // Cast gerekiyor // Generic versiyon List<String> list = new ArrayList<>(); list.add("hello"); String s = list.get(0); // Cast gerekmiyor

21. Raw Tipleri Kullanmaktan Kaçının

Java 5'ten beri, raw tipler yerine parameterize tipleri kullanın.

java
// Kötü (raw tip) List list = new ArrayList(); // İyi (parameterize tip) List<String> list = new ArrayList<>();

22. Wildcard Generics'i Anlamaya Çalışın

Wildcard generics, kodunuzu daha esnek hale getirebilir.

java
// Üst sınır wildcard public void processElements(List<? extends Number> list) { for (Number n : list) { // işlemler } } // Alt sınır wildcard public void addNumbers(List<? super Integer> list) { list.add(1); list.add(2); }

23. Varargs'ı Dikkatli Kullanın

Varargs kullanışlı olabilir, ancak dikkatli kullanılmalıdır.

java
public void printAll(String... strings) { for (String s : strings) { System.out.println(s); } } // Kullanım printAll("Hello", "World"); printAll("One", "Two", "Three");

24. Null Yerine Boş Koleksiyonlar Döndürün

Null bir koleksiyon döndürmek yerine, boş bir koleksiyon döndürün. Bu, NullPointerException riskini azaltır.

java
// Kötü public List<Customer> getCustomers() { if (customerData.isEmpty()) { return null; } return customerData; } // İyi public List<Customer> getCustomers() { return new ArrayList<>(customerData); // Boş olabilir, ama asla null değil }

25. Defensive Copying Kullanın

Değiştirilebilir nesneleri parametre olarak alan veya döndüren metotlarda defensive copying kullanın.

java
public final class Period { private final Date start; private final Date end; public Period(Date start, Date end) { this.start = new Date(start.getTime()); this.end = new Date(end.getTime()); if (this.start.compareTo(this.end) > 0) throw new IllegalArgumentException(); } public Date getStart() { return new Date(start.getTime()); } public Date getEnd() { return new Date(end.getTime()); } }

28. Soyut Sınıflar Yerine Arayüzleri Tercih Edin

Arayüzler, çoklu kalıtıma izin verir ve daha esnek bir tasarım sağlar.

java
public interface Drawable { void draw(); } public interface Resizable { void resize(); } public class Circle implements Drawable, Resizable { @Override public void draw() { // Çizim işlemi } @Override public void resize() { // Yeniden boyutlandırma işlemi } }

29. Arayüzleri Sadece Tip Tanımlamak İçin Kullanın

Arayüzler, sabitleri gruplamak için kullanılmamalıdır.

java
// Kötü kullanım public interface PhysicalConstants { static final double AVOGADROS_NUMBER = 6.022_140_857e23; static final double BOLTZMANN_CONSTANT = 1.380_648_52e-23; } // İyi kullanım public final class PhysicalConstants { private PhysicalConstants() {} // Örneklemeyi engelle public static final double AVOGADROS_NUMBER = 6.022_140_857e23; public static final double BOLTZMANN_CONSTANT = 1.380_648_52e-23; }

30. Tag Sınıfları Yerine Sınıf Hiyerarşisini Tercih Edin

Tag alanları kullanan sınıflar yerine, sınıf hiyerarşisi kullanın.

java
// Kötü (tag sınıfı) class Figure { enum Shape { RECTANGLE, CIRCLE }; final Shape shape; // rectangle özelliği double length; double width; // circle özelliği double radius; // constructor... } // İyi (sınıf hiyerarşisi) abstract class Figure { abstract double area(); } class Rectangle extends Figure { final double length; final double width; Rectangle(double length, double width) { this.length = length; this.width = width; } @Override double area() { return length * width; } } class Circle extends Figure { final double radius; Circle(double radius) { this.radius = radius; } @Override double area() { return Math.PI * (radius * radius); } }

31. İç İçe Sınıfları Uygun Şekilde Kullanın

İç içe sınıflar, kodun organizasyonunu ve enkapsülasyonu artırabilir.

java
public class OuterClass { private int value; public class InnerClass { public void printValue() { System.out.println("Value is " + value); } } public static class StaticNestedClass { public void printSomething() { System.out.println("Static nested class"); } } } // Kullanım OuterClass outer = new OuterClass(); OuterClass.InnerClass inner = outer.new InnerClass(); OuterClass.StaticNestedClass staticNested = new OuterClass.StaticNestedClass();

32. Erişim Belirleyicilerini Doğru Kullanın

Sınıfları ve üyelerini mümkün olduğunca erişilmez yapın.

java
public class Account { private double balance; // Sadece bu sınıf içinden erişilebilir public void deposit(double amount) { if (amount > 0) { balance += amount; } } public void withdraw(double amount) { if (amount > 0 && balance >= amount) { balance -= amount; } } public double getBalance() { return balance; } }

33. Public Sınıflarda Public Alanlar Yerine Accessor Metodları Kullanın

Encapsulation'ı korumak için, public sınıflarda public alanlar yerine accessor metodları kullanın.

java
// Kötü public class Point { public double x; public double y; } // İyi public class Point { private double x; private double y; public double getX() { return x; } public double getY() { return y; } public void setX(double x) { this.x = x; } public void setY(double y) { this.y = y; } }

34. Değiştirilebilirliği Minimize Edin

Mümkün olduğunca değişmez (immutable) sınıflar oluşturun.

java
public final class Complex { private final double re; private final double im; public Complex(double re, double im) { this.re = re; this.im = im; } public double realPart() { return re; } public double imaginaryPart() { return im; } public Complex plus(Complex c) { return new Complex(re + c.re, im + c.im); } // diğer metodlar... }

35. Kompozisyonu Kalıtıma Tercih Edin

Kalıtım yerine kompozisyon kullanmak, daha esnek ve bakımı kolay kod sağlar.

java
// Kalıtım yerine public class Stack<E> extends Vector<E> { ... } // Kompozisyon kullanarak public class Stack<E> { private Vector<E> vector = new Vector<>(); public void push(E item) { vector.add(item); } public E pop() { return vector.remove(vector.size() - 1); } }

36. Metotları Aşırı Yükleme Konusunda Dikkatli Olun

Aşırı yüklenmiş metotlar, açık ve tahmin edilebilir olmalıdır.

java
public class CollectionClassifier { public static String classify(Set<?> s) { return "Set"; } public static String classify(List<?> lst) { return "List"; } public static String classify(Collection<?> c) { return "Unknown Collection"; } } // Kullanım Collection<?>[] collections = { new HashSet<String>(), new ArrayList<BigInteger>(), new HashMap<String, String>().values() }; for (Collection<?> c : collections) System.out.println(classify(c)); // Tüm çağrılar "Unknown Collection" döndürür!

37. Varargs'ı Dikkatli Kullanın

Varargs kullanışlı olabilir, ancak dikkatli kullanılmalıdır.

java
// Tehlikeli varargs kullanımı static int min(int... args) { if (args.length == 0) throw new IllegalArgumentException("Too few arguments"); int min = args[0]; for (int i = 1; i < args.length; i++) if (args[i] < min) min = args[i]; return min; } // Daha güvenli alternatif static int min(int firstArg, int... remainingArgs) { int min = firstArg; for (int arg : remainingArgs) if (arg < min) min = arg; return min; }

38. Null Yerine Boş Koleksiyonlar veya Diziler Döndürün

Null bir koleksiyon veya dizi döndürmek yerine, boş bir koleksiyon veya dizi döndürün.

java
// Kötü public List<Customer> getCustomers() { if (customerData.isEmpty()) { return null; } return customerData; } // İyi public List<Customer> getCustomers() { return new ArrayList<>(customerData); // Boş olabilir, ama asla null değil } // Diziler için public Cheese[] getCheeses() { return cheesesInStock.toArray(new Cheese[0]); }

39. Kontrol Edilmiş İstisnaları Dikkatli Kullanın

Kontrol edilmiş istisnalar (checked exceptions) sadece geri kazanılabilir durumlarda kullanılmalıdır.

java
// Kontrol edilmiş istisna public void readFile(String filename) throws IOException { // Dosya okuma işlemleri } // Kontrol edilmemiş istisna public int divide(int a, int b) { if (b == 0) { throw new IllegalArgumentException("Divisor cannot be zero"); } return a / b; }

40. Standart İstisna Sınıflarını Kullanın

Mümkün olduğunca, kendi özel istisna sınıflarınızı oluşturmak yerine Java'nın standart istisna sınıflarını kullanın.

java
// Yaygın kullanılan standart istisnalar throw new IllegalArgumentException(); throw new IllegalStateException(); throw new NullPointerException(); throw new IndexOutOfBoundsException(); throw new ConcurrentModificationException(); throw new UnsupportedOperationException();

41. İstisnalar İçin Bilgilendirici Mesajlar Throw Edin

İstisna mesajları, hatanın nedenini açıkça belirtmelidir.

java
// Kötü throw new IllegalArgumentException(); // İyi throw new IllegalArgumentException("Employees must be at least 18 years old.");

42. Metodların Throw Ettiği Tüm İstisnaları Belgeleyin

Bir metodun fırlatabileceği tüm istisnaları, @throws etiketiyle Javadoc'ta belgeleyin.

java
/** * Belirtilen kullanıcıyı veritabanından siler. * * @param userId Silinecek kullanıcının ID'si * @throws SQLException Veritabanı hatası durumunda * @throws UserNotFoundException Belirtilen ID'ye sahip kullanıcı bulunamazsa */ public void deleteUser(int userId) throws SQLException, UserNotFoundException { // Metot implementasyonu }

43. İstisna Ayrıntılarını Günlüğe Kaydedin

Catch bloklarında, istisna ayrıntılarını günlüğe kaydedin.

java
try { // Riskli işlem } catch (Exception e) { logger.log(Level.SEVERE, "İşlem başarısız oldu", e); throw e; // Yeniden fırlatma (gerekirse) }

44. Senkronizasyonu Dikkatli Kullanın

Senkronizasyon, thread güvenliği sağlar ancak performansı düşürebilir. Sadece gerektiğinde kullanın.

java
public class ThreadSafeCounter { private int count = 0; public synchronized void increment() { count++; } public synchronized int getCount() { return count; } }

45. Thread-safe Sınıflar İçin Senkronize Erişimi Tercih Edin

Thread-safe sınıflar oluştururken, senkronize erişimi tercih edin.

java
public class SafePoint { private int x, y; public synchronized int getX() { return x; } public synchronized int getY() { return y; } public synchronized void setXY(int x, int y) { this.x = x; this.y = y; } }

46. Aşırı Senkronizasyondan Kaçının

Aşırı senkronizasyon, performans sorunlarına ve hatta deadlock'lara neden olabilir.

java
// Kötü (aşırı senkronizasyon) public class ListHelper<E> { public synchronized boolean putIfAbsent(List<E> list, E x) { boolean absent = !list.contains(x); if (absent) list.add(x); return absent; } } // İyi (daha iyi performans) public class ListHelper<E> { public boolean putIfAbsent(List<E> list, E x) { synchronized(list) { boolean absent = !list.contains(x); if (absent) list.add(x); return absent; } } }

47. Lazy Initialization'ı Dikkatli Kullanın

Lazy initialization, gereksiz nesne oluşturmayı önleyebilir, ancak dikkatli kullanılmalıdır.

java
// Thread-safe lazy initialization private static class FieldHolder { static final FieldType field = computeFieldValue(); } private static FieldType getField() { return FieldHolder.field; }

48. Sistem Özelliklerini Dikkatli Kullanın

Sistem özelliklerini kullanırken dikkatli olun, çünkü bunlar JVM'in dışından değiştirilebilir.

java
// Sistem özelliği kullanımı String userDir = System.getProperty("user.dir"); // Varsayılan değerle kullanım String configDir = System.getProperty("custom.config.dir", "/default/config/path");

Please Select Embedded Mode To Show The Comment System.*

Daha yeni Daha eski

نموذج الاتصال