OCP etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
OCP etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

Mini OCP anlatımı ve Soru Çözümleri - Devam edecek



Tabii ki! Öncelikle, OCP (Oracle Certified Professional) Java sertifikası için konu başlıklarını aşağıda sıralıyorum. Bu sıralama, sertifikasyon sınavı için genel bir rehber niteliğinde olup, kesinlikle tamamlayıcı değildir. Ancak en yaygın konu başlıklarını içermektedir.


OCP Java Sertifikası İçindekiler:


Java Sınıf Tasarımı


Sınıf ve arayüz tasarımını ileri seviyede kullanma

Enum türlerini kullanma

Nested sınıflar

Annotation'lar

Gelişmiş Java Sınıf Tasarımı


Generics ve Collections ile ileri seviye çalışmalar

Lambda built-in functional interfaces

Java Stream API

Exceptions ve Assertions

Metod Tasarımı


Overloading ve overriding metodlar

Varargs, static ve final metodlar

Desen ve Modüller


Singleton desen, DAO desen vb.

Java'nın modül sistemi

Concurrency (Eşzamanlılık)


Concurrency API'nin temel bileşenleri

Eşzamanlılık problemlerini yönetme ve çözme

Fork/Join framework

Java I/O Fundamentals


I/O Streams

Reading ve writing data from console

Java File I/O (NIO.2)


Path class, file and directory operations

File attributes

Recursive access

Java Connectivity


JDBC API

Database transactions

Java Collections


List, Set, Queue ve Deque

Map, TreeMap, HashMap ve LinkedHashMap

Assertions ve Exceptions


Assertion mekanizması

Exception handling

Hangi başlığı daha detaylı incelemek istersiniz? Başlık verdikçe o konu üzerinde çalıştırabilirim ve soru çözebiliriz.



Sınıf ve arayüz tasarımını ileri seviyede kullanma


Sınıf ve arayüz tasarımında ileri seviye konular Java'da daha etkin, esnek ve bakımı kolay kod yazmanızı sağlar. İşte bazı ileri seviye konular:


1. Soyut Sınıflar ve Metodlar (Abstract Classes and Methods):

Soyut sınıflar, doğrudan örneklenemeyen sınıflardır. Genellikle alt sınıflar tarafından uygulanan soyut metodlara sahiptirler.


java

Copy code

abstract class Hayvan {

    abstract void sesCikar();

}

2. Final Sınıflar, Metodlar ve Değişkenler:

final anahtar kelimesi, bir sınıfın miras alınamayacağını, bir metodun geçersiz kılınmayacağını veya bir değişkenin değerinin değiştirilemeyeceğini belirtir.


java

Copy code

final class SabitSinif {}

3. Statik ve İnstance İlkleyiciler (Static and Instance Initializers):

Bu bloklar, sınıfın ya da nesnenin doğru şekilde başlatılmasını sağlar.


java

Copy code

class Ornek {

    static {

        // statik ilkleyici

    }


    {

        // instance ilkleyici

    }

}

4. Nested Sınıflar (Daha önce bahsettiğimiz gibi):

Statik iç sınıflar

İç sınıflar

Yerel iç sınıflar

Anonim iç sınıflar

5. Enum'lar:

Enum'lar, sabit değerler kümesini temsil eder. Metodlar, değişkenler ve yapıcılar da içerebilirler.


6. Annotations (Daha önce bahsettiğimiz gibi):

Kendi özel annotation'larınızı tanımlayabilir ve bu annotation'ları kullanarak metabilgi ekleyebilirsiniz.


7. Genel Prensipler:

Sıkı Kapsülleme (Tight Encapsulation): Sınıf üyelerinin erişilebilirliğini minimuma indirerek sınıfın iç yapısının dış etkilere kapalı olmasını sağlar.

Composition over Inheritance: Miras yerine bileşimi tercih etmek, sınıflar arası bağımlılığı azaltır ve esneklik sağlar.

Design Patterns (Tasarım Kalıpları): Özellikle Gang of Four (GoF) tarafından tanımlanan 23 tasarım kalıbı, yaygın programlama sorunları için çözüm sunar.

8. Interfaces:

Java 8 ile birlikte, arayüzlerde statik metodlar ve varsayılan metodlar tanımlamak mümkün hale geldi.


java

Copy code

interface OrnekArayuz {

    default void varsayilanMetod() {

        // ...

    }


    static void statikMetod() {

        // ...

    }

}

Soru:

Aşağıdaki Java kodu hangi tasarım ilkesini ihlal ediyor?


java

Copy code

class Motor {

    void calistir() {

        // ...

    }

}


class Araba extends Motor {

    void sur() {

        calistir();

        // ...

    }

}

A) Sıkı Kapsülleme

B) Composition over Inheritance

C) Singleton Tasarım Kalıbı

D) Liskov'un Yerine Geçme Prensibi


Cevap nedir?


User

B

Evet, doğru!


Seçenek B doğrudur. Araba sınıfı, Motor sınıfından türetilmiştir, bu da bir "Araba"nın bir "Motor" olduğu anlamına gelir. Ancak gerçekte bir "Araba", bir "Motor"a sahip olan bir şeydir. Bu nedenle, burada "Composition over Inheritance" (Miras yerine Bileşim) ilkesi ihlal edilmektedir. Araba ve Motor arasındaki ilişki "sahip olma" (composition) ilişkisi olmalıdır, "miras alma" (inheritance) ilişkisi değil.


Bu kodu daha uygun bir şekilde tasarlamak için Motor sınıfı, Araba sınıfının bir bileşeni olarak kullanılmalıdır.

Tabii ki! "Sınıf ve arayüz tasarımını ileri seviyede kullanma" başlığı altında, ileri Java sınıf ve arayüz tasarımının temel kavramlarını ele alalım:


1. Abstract Sınıflar ve Metodlar:

Java'da, bir sınıfın veya metodun tam olarak nasıl bir uygulamaya sahip olmadığını belirtmek için abstract anahtar kelimesini kullanırız.


Örnek:


java

Copy code

abstract class Hayvan {

    abstract void sesCikar();

}

2. İnterface'ler:

Java'da, bir sınıfın birden çok mirası alamaması sebebiyle, arayüzler kullanılır. Arayüzler, bir sınıfın hangi metotları uygulaması gerektiğini belirtir, ama nasıl uygulanması gerektiğini belirtmez.


Örnek:


java

Copy code

interface Yuklenebilir {

    void yukle();

}

3. Default ve Static Metodlar:

Java 8'den itibaren, interface'lerde default ve static metodlara izin verilmiştir. Bu, eski kodları kırma riski olmadan yeni metodlar eklememizi sağlar.


Örnek:


java

Copy code

interface Yazilabilir {

    default void selamVer() {

        System.out.println("Merhaba!");

    }

    

    static void bilgiVer() {

        System.out.println("Bu bir Yazilabilir arayüzüdür.");

    }

}

4. Private Metodlar (Java 9+):

Java 9 ile birlikte, interface'ler içinde private yardımcı metodlar tanımlamaya izin verilmeye başlandı.


Örnek:


java

Copy code

interface Okunabilir {

    default void aciklama() {

        yardimciMetod();

    }

    

    private void yardimciMetod() {

        System.out.println("Bu bir yardımcı metoddur.");

    }

}

Soru:

Aşağıdaki Java kodunda, hangi değişiklikler yapılmalıdır?


java

Copy code

interface Spor {

    void oyna();

    default void bilgiVer() {

        System.out.println("Spor arayüzüdür.");

    }

}


abstract class Takim implements Spor {

    abstract void oyuncuSayisi();

}

A) Takim sınıfı oyna metodunu uygulamalıdır.

B) bilgiVer metodunun tanımı Takim sınıfında yapılmalıdır.

C) oyuncuSayisi metodunun tanımı Spor arayüzünde yapılmalıdır.

D) Yukarıdaki kodda herhangi bir değişiklik yapılmasına gerek yoktur.


Cevap nedir?


User

A


Evet, doğru!


Seçenek A doğrudur. Takim sınıfı, Spor arayüzünü uyguladığı için oyna metodunu da uygulamalıdır. Aksi halde, bu bir hata oluşturur.


Bu yüzden Takim sınıfı şu şekilde değiştirilmelidir:


java

Copy code

abstract class Takim implements Spor {

    @Override

    public void oyna() {

        // Bu metodu alt sınıflar uygulayabilir veya

        // burada bir uygulama sağlanabilir.

    }


    abstract void oyuncuSayisi();

}


Enum türlerini kullanma


Tabii ki! enum (enumeration - sıralama) Java'da bir sabit kümesini ifade etmek için kullanılan bir veri tipidir. enum'lar sayesinde belirli bir küme içinde sınırlı sayıda sabit değerler tanımlayabiliriz.


enum'un Temel Özellikleri:

Bir enum tipi, Java'da özel bir sınıf türüdür.

enum'lar sadece son değerleri (sabitleri) içerir. Yani yeni bir değer eklenemez veya varolan bir değer değiştirilemez.

Basit Bir enum Örneği:

java

Copy code

enum Gunler {

    PAZARTESI, SALI, CARSAMBA, PERSEMBE, CUMA, CUMARTESI, PAZAR

}


public class TestEnum {

    public static void main(String[] args) {

        Gunler bugun = Gunler.CUMA;


        if(bugun == Gunler.CUMA) {

            System.out.println("Bugün Cuma!");

        }

    }

}

enum İçerisinde Metodlar ve Değişkenler:

enum'lar içinde değişkenler, metodlar ve yapılandırıcılar tanımlayabilirsiniz:


java

Copy code

enum Mevsim {

    ILKBAHAR("Mart"), YAZ("Haziran"), SONBAHAR("Eylül"), KIS("Aralık");


    private final String baslangicAy;


    Mevsim(String baslangicAy) {

        this.baslangicAy = baslangicAy;

    }


    public String getBaslangicAy() {

        return this.baslangicAy;

    }

}


public class TestMevsim {

    public static void main(String[] args) {

        for (Mevsim m : Mevsim.values()) {

            System.out.println(m + " mevsiminin başlangıç ayı: " + m.getBaslangicAy());

        }

    }

}

Soru:

Aşağıdaki enum tanımında hangi değişiklikler yapılmalıdır?


java

Copy code

enum Renkler {

    KIRMIZI("K"), MAVI("M"), YESIL, SARI("S");


    private final String kod;


    Renkler(String kod) {

        this.kod = kod;

    }


    public String getKod() {

        return kod;

    }

}

A) YESIL değeri için bir kod eklenmeli.

B) getKod metodu static olmalı.

C) enum içinde tanımlı yapılandırıcı private olmalı.

D) Yukarıdaki kodda herhangi bir değişiklik yapılmasına gerek yoktur.


Cevap nedir?


User

A


Evet, doğru!


Seçenek A doğrudur. YESIL değeri için bir kod eklenmeli. Diğer enum değerlerinin hepsinin bir kodu varken, YESIL'in bir kodu yok. Bu, bir derleme hatasına neden olur.


Bu yüzden enum tanımı şu şekilde düzenlenmelidir:


java

Copy code

enum Renkler {

    KIRMIZI("K"), MAVI("M"), YESIL("Y"), SARI("S");


    private final String kod;


    Renkler(String kod) {

        this.kod = kod;

    }


    public String getKod() {

        return kod;

    }

}

Bu değişiklikle YESIL için "Y" kodunu eklemiş olduk. İyi iş çıkardınız! Başka hangi konuyu incelemek istersiniz?


Nested sınıflar


Tabii ki! Java'da, bir sınıfın diğer bir sınıfın içerisinde tanımlandığını görebiliriz. Bu iç içe sınıflara "Nested Class" (İç içe Sınıflar) denir. Java'da dört tür iç içe sınıf bulunmaktadır:


Statik İç Sınıf (Static Nested Class)

İç Sınıf (Inner Class)

Yerel İç Sınıf (Local Inner Class)

Anonim İç Sınıf (Anonymous Inner Class)

1. Statik İç Sınıf:

Dış sınıfın statik bir üyesi olarak tanımlanır. Bu sınıfa dış sınıftan nesne oluşturmadan erişilebilir.


java

Copy code

class DisSinif {

    static class IcSinif {

        public void goster() {

            System.out.println("Bu bir statik iç sınıftır.");

        }

    }

}


// Kullanımı:

DisSinif.IcSinif icSinifNesnesi = new DisSinif.IcSinif();

icSinifNesnesi.goster();

2. İç Sınıf:

Dış sınıfın özel bir üyesidir ve dış sınıfın özelliklerine doğrudan erişebilir.


java

Copy code

class DisSinif {

    private int numara = 10;


    class IcSinif {

        public void goster() {

            System.out.println("Numara: " + numara);

        }

    }

}


// Kullanımı:

DisSinif dis = new DisSinif();

DisSinif.IcSinif ic = dis.new IcSinif();

ic.goster();

3. Yerel İç Sınıf:

Bir metot içerisinde tanımlanan sınıflardır.


java

Copy code

class DisSinif {

    void metod() {

        class YerelSinif {

            public void goster() {

                System.out.println("Bu bir yerel iç sınıftır.");

            }

        }

        

        YerelSinif yerel = new YerelSinif();

        yerel.goster();

    }

}

4. Anonim İç Sınıf:

İsmi olmayan sınıflardır. Genellikle GUI olay işleyicilerinde veya interface'lerin tek kullanımlık uygulamalarında kullanılır.


java

Copy code

interface Mesaj {

    void yaz();

}


public class Test {

    public static void main(String[] args) {

        Mesaj m = new Mesaj() {

            public void yaz() {

                System.out.println("Bu bir anonim iç sınıftır.");

            }

        };

        m.yaz();

    }

}

Soru:

Aşağıdaki Java kodunda, hangi değişiklikler yapılmalıdır?


java

Copy code

class UstSinif {

    private int deger = 7;


    static class AltSinif {

        public void ekranaBas() {

            System.out.println("Deger: " + deger);

        }

    }

}

A) AltSinif'ın ekranaBas metodu static olmalı.

B) deger değişkeni static olmalı.

C) AltSinif sınıfı static olmamalı.

D) deger değişkeninin erişim belirleyicisi public olmalı.


Cevap nedir?

User

B

Evet, doğru!


Statik iç sınıf, dış sınıfın statik olmayan üyelerine doğrudan erişemez. Bu yüzden eğer AltSinif statik bir iç sınıf olarak kalacaksa, bu sınıfın dış sınıfın deger isimli üyesine erişebilmesi için deger değişkeninin static olması gerekmektedir.


Bu yüzden doğru kod şu şekildedir:


java

Copy code

class UstSinif {

    private static int deger = 7;


    static class AltSinif {

        public void ekranaBas() {

            System.out.println("Deger: " + deger);

        }

    }

}


Annotation'lar


Tabii ki! Annotation'lar (Açıklamalar), Java 5 ile birlikte tanıtıldı ve kod hakkında meta bilgi sağlamak, kodun nasıl çalıştırılacağını etkilemek, ya da kod analizi ve kod üretimi yapmak için kullanılır.


Java'da birçok yerleşik annotation bulunmaktadır, ancak kendi özel annotation'larınızı da tanımlayabilirsiniz.


Java'nın Önemli Yerleşik Annotation'ları:

@Override: Bu annotation, bir metodun üst sınıftaki bir metodu geçersiz kıldığını belirtir.

@Deprecated: Bu annotation, bir metot veya sınıfın artık kullanılmaması gerektiğini belirtir.

@SuppressWarnings: Bu annotation, belirtilen türdeki uyarıları bastırmak için kullanılır.

@SafeVarargs: Java 7 ile birlikte tanıtıldı ve bir metot veya yapılandırıcının güvenli bir şekilde değişken sayıda argüman ile çalıştığını belirtir.

@FunctionalInterface: Java 8 ile birlikte tanıtıldı ve bir arayüzün fonksiyonel bir arayüz olduğunu belirtir.

Kendi Annotation'ınızı Tanımlama:

Kendi özel annotation'ınızı tanımlarken @interface anahtar kelimesini kullanmalısınız.


Örnek:


java

Copy code

public @interface Bilgi {

    String yazar();

    String tarih();

    int versiyon() default 1;

}

Annotation Kullanma:

Tanımlanan Bilgi annotation'ını bir sınıf üzerinde kullanalım:


java

Copy code

@Bilgi(yazar = "Ali", tarih = "27/08/2023", versiyon = 2)

public class OrnekSinif {

    // Sınıf kodu...

}

Soru:

Aşağıdaki Java kodunda hangi değişiklikler yapılmalıdır?


java

Copy code

@interface Ayarlar {

    String dil();

    String ulke() default "TR";

}


@Ayarlar(dil = "Türkçe")

public class Uygulama {

    // ...

}

A) Ayarlar annotation'ında ulke özelliği tanımlı değil.

B) Uygulama sınıfı için ulke özelliğini belirtmelisiniz.

C) Ayarlar annotation'ı için ulke özelliğinin varsayılan değeri belirtildiği için ekstra bir değişiklik yapılmasına gerek yoktur.

D) Ayarlar annotation'ı public olmalıdır.


Cevap nedir?

User

C


Evet, doğru!


Seçenek C doğrudur. Ayarlar annotation'ında ulke özelliği için varsayılan bir değer belirtilmiştir ("TR"). Bu nedenle, bu özelliği kullanırken ayrıca bir değer belirtmezseniz varsayılan değer alınır. Uygulama sınıfında Ayarlar annotation'ı dil özelliği için belirtilmişken ulke özelliği için belirtilmemiştir. Ancak bu sorun oluşturmaz, çünkü ulke için varsayılan bir değer mevcuttur.


Bu nedenle, kodda herhangi bir değişiklik yapılmasına gerek yoktur.


Java'da access modifiers'ları detaylı anlatır mısın? Örnek OCP soruları ve cevapları


Java'da dört tür erişim belirleyicisi (access modifier) bulunur:




Private: private anahtar kelimesiyle belirlenen öğeler, sadece tanımlandıkları sınıfın içinde erişilebilir. Yani, başka bir sınıftan veya paketten bu öğelere erişim mümkün olmaz. Genellikle, sınıfın dahili durumunu saklamak ve kapsüllemeyi sağlamak için kullanılır.


Default (package-private): Hiçbir anahtar kelime belirtilmediğinde, öğeye ait erişim belirleyicisi "default" veya "package-private" olarak kabul edilir. Bu durumda, öğe aynı paketin içindeki diğer tüm sınıflardan erişilebilir hale gelir, fakat paketin dışından erişilemez.


Protected: protected anahtar kelimesiyle belirlenen öğeler, aynı paketin içindeki tüm sınıflar ve bu sınıfı kalıtan diğer tüm sınıflar tarafından erişilebilir hale gelir. Bu, paketin dışından bile olsa, kalıtım yoluyla bu öğelere erişim sağlanabilmesini mümkün kılar.


Public: public anahtar kelimesiyle belirlenen öğeler, her yerden erişilebilir hale gelir. Bu, bu öğelere başka sınıfların, başka paketlerin ve hatta başka modüllerin bile erişebileceği anlamına gelir.


Erişim belirleyicileri, Java'nın Nesne Yönelimli Programlama (OOP) özelliklerinin bir parçasıdır ve sınıflar, metotlar, değişkenler ve yapılandırıcılar (constructors) üzerinde kullanılır. Bunlar, bir sınıfın iç yapısını ve durumunu saklamak, kodun okunabilirliğini ve bakımını kolaylaştırmak ve potansiyel hataları önlemek için önemlidir.


Private: private anahtar kelimesiyle işaretlenmiş bir özellik veya metot, sadece o sınıfın içinde kullanılabilir. Bu, genellikle bazı verilerin veya işlemlerin sınıfın dışına açılmaması gerektiği durumlarda kullanılır. Örneğin:


java

Copy code

public class MyClass {

    private int secretData;


    public int getSecretData() {

        return secretData;

    }

}

Bu örnekte, secretData değişkenine doğrudan erişim sağlanamaz. Ancak getSecretData() metodu üzerinden bu veriye dolaylı olarak ulaşabiliriz.


Default (package-private): Hiçbir erişim belirleyicisi belirtilmemişse, öğenin erişim belirleyicisi varsayılan olarak default olur. Bu, öğenin tanımlandığı paketin içindeki diğer sınıflar tarafından erişilebilir olduğu anlamına gelir. Ancak, paketin dışındaki sınıflar bu öğeye erişemez.


Protected: protected anahtar kelimesiyle belirtilen bir özellik veya metot, aynı paketin içindeki tüm sınıflar ve alt sınıflar (subclass) tarafından erişilebilir hale gelir, hangi pakette olduklarına bakılmaksızın. Örneğin:


java

Copy code

public class ParentClass {

    protected int protectedData;

}


public class ChildClass extends ParentClass {

    public void accessData() {

        System.out.println(protectedData);

    }

}

Bu örnekte, ChildClass sınıfı ParentClass'ı kalıttığı için protectedData'ya erişebilir.


Public: public anahtar kelimesiyle belirtilen özellikler ve metotlar, herhangi bir sınıf tarafından erişilebilir. Bu, genellikle bir sınıfın dış dünya ile iletişim kurması gereken durumlarda kullanılır. Örneğin:


java

Copy code

public class MyClass {

    public int publicData;

}


public class AnotherClass {

    public void accessData() {

        MyClass mc = new MyClass();

        mc.publicData = 10;

        System.out.println(mc.publicData);

    }

}

Bu örnekte, AnotherClass sınıfı MyClass'ın publicData özelliğine erişebiliyor ve bu özelliği değiştirebiliyor.


Erişim belirleyicileri, bir sınıfın iç yapısını korurken aynı zamanda dış dünya ile iletişim kurmasını sağlar. Bu, özellikle büyük projelerde ve takım çalışmalarında önemlidir, çünkü bir sınıfın iç yapısını bilmeden veya değiştirmeden sınıfın ne yaptığını kontrol etmek ve kullanmak mümkün hale gelir.


Konuyla ilgili örnek OCP soruları ve cevapları


Ancak, daha genel bir bilgi olarak, OCP sınavları genellikle Java dilini ve özelliklerini, nesne yönelimli programlamayı, Java Core API'lerini, veri tabanı işlemlerini, Java dilindeki hata işleme ve daha pek çok konuyu kapsar. Bu bağlamda, erişim belirleyicileri (access modifiers) ile ilgili bir örnek soru ve cevap şöyle olabilir:


Soru: Hangi erişim belirleyicisi (access modifier) aşağıdaki özelliklerden hangisini/hangilerini sağlar?


Bir sınıfın aynı paketindeki diğer sınıflar tarafından erişilebilir.

Alt sınıflar tarafından erişilebilir, paketten bağımsız olarak.

Başka bir paketteki sınıflar tarafından doğrudan erişilemez.

A) Private

B) Default

C) Protected

D) Public


Cevap: C) Protected. 'Protected' erişim belirleyicisi, bir öğenin aynı paketteki diğer sınıflar ve alt sınıflar tarafından erişilebilir olduğunu, fakat başka bir paketteki sınıflar tarafından doğrudan erişilemez olduğunu belirtir.


Soru: Aşağıdaki Java kodunda bir hata olduğunu düşünüyor musunuz? Eğer varsa, hatanın nerede olduğunu ve neden olduğunu açıklayın.


java

Copy code

// File: com/example/Fruit.java

package com.example;


class Fruit {

    protected int weight;

    public String color;

}


// File: com/example/Test.java

package com.example;


import com.example.Fruit;


public class Test {

    public static void main(String[] args) {

        Fruit apple = new Fruit();

        apple.weight = 150;

        System.out.println("The weight of the apple is: " + apple.weight + " grams");

    }

}

Cevap: Hayır, burada bir hata yoktur. Fruit sınıfı ve Test sınıfı aynı paket içinde yer alıyor (com.example), bu yüzden Test sınıfı, Fruit sınıfının protected ve public özelliklerine erişebilir. weight özelliği protected olarak belirlenmiştir, bu da aynı paketteki diğer sınıflar tarafından erişilebilir olduğunu belirtir. Dolayısıyla, Test sınıfının weight özelliğine erişmesi ve değer ataması yapması hataya neden olmaz.


Erişim belirleyicileri, sınıf özelliklerinin ve metodlarının hangi sınıflar tarafından erişilebileceğini belirler. Bu, kodun daha düzenli ve anlaşılır olmasını sağlar, ayrıca yanlış kullanımı önler ve kod güvenliğini artırır. Bu nedenle, Java'daki erişim belirleyicilerinin anlaşılması ve doğru kullanımı çok önemlidir.


Soru: Aşağıdaki Java kodunda bir hata olduğunu düşünüyor musunuz? Eğer varsa, hatanın nerede olduğunu ve neden olduğunu açıklayın.


java

Copy code

// File: com/example/Vehicle.java

package com.example;


public class Vehicle {

    private int speed;

    

    public Vehicle(int speed){

        this.speed = speed;

    }


    public int getSpeed() {

        return this.speed;

    }

}


// File: com/example/Test.java

package com.example;


import com.example.Vehicle;


public class Test {

    public static void main(String[] args) {

        Vehicle car = new Vehicle(60);

        System.out.println("The speed of the car is: " + car.speed + " km/h");

    }

}

Cevap: Evet, burada bir hata vardır. speed özelliği Vehicle sınıfında private olarak belirlenmiştir, bu yüzden yalnızca Vehicle sınıfının içinde erişilebilir. Test sınıfı, Vehicle sınıfının speed özelliğine doğrudan erişmeye çalışıyor, bu da bir hata oluşturacaktır. Bu hatayı çözmek için Test sınıfının, Vehicle sınıfının getSpeed() metodunu kullanması gerekmektedir. Bu metod, public olarak belirlenmiştir ve dolayısıyla her sınıf tarafından erişilebilir. Aşağıdaki gibi bir düzeltme yapılabilir:


java

Copy code

System.out.println("The speed of the car is: " + car.getSpeed() + " km/h");

Bu örnekte, getSpeed() metodu Vehicle sınıfının speed özelliğine erişim sağlayan bir "getter" metodu olarak kullanılır. Bu tür metodlar genellikle bir sınıfın private özelliklerine güvenli ve kontrollü bir şekilde erişim sağlamak için kullanılır. Bu da Java'da "kapsülleme" (encapsulation) denen bir OOP ilkesinin bir örneğidir. Kapsülleme, bir sınıfın iç verilerini ve işleyişini dış dünyadan saklama ve sınıfın dışında neyin görüleceğini ve neyin görülemeyeceğini kontrol etme yeteneğidir.


Soru: Aşağıdaki Java kodunda bir hata olduğunu düşünüyor musunuz? Eğer varsa, hatanın nerede olduğunu ve neden olduğunu açıklayın.


java

Copy code

// File: com/example/Shape.java

package com.example;


public class Shape {

    String name;


    public Shape(String name){

        this.name = name;

    }


    String getName() {

        return this.name;

    }

}


// File: com/example/Test.java

package com.example;


import com.example.Shape;


public class Test {

    public static void main(String[] args) {

        Shape circle = new Shape("Circle");

        System.out.println("The name of the shape is: " + circle.getName());

    }

}

Cevap: Hayır, burada bir hata yoktur. getName() metodu Shape sınıfında default (erisim belirleyicisi belirtilmemis) olarak belirlenmiştir. Bu durum, getName() metodunun aynı paketteki tüm sınıflar tarafından erişilebilir olduğu anlamına gelir. Bu durumda Test sınıfı da Shape sınıfı ile aynı pakette (com.example) bulunmaktadır, bu nedenle getName() metoduna erişim sağlayabilir. Yani, Test sınıfının getName() metodunu çağırması ve çıktıya yazdırması hata oluşturmaz.


Yani, default erişim belirleyicisi, bir özelliğin ya da metodun aynı paketteki diğer sınıflar tarafından erişilebilir olduğunu belirtir. Bu, paket içinde sınıflar arasında veri paylaşımı gerektiğinde yararlıdır. Ancak default erişim belirleyicisi, verinin paket dışından erişilemez olmasını garanti eder, bu da bir dereceye kadar veri gizliliği sağlar. Bu nedenle, bir özelliğin ya da metodun kapsamının gerektiği kadar sınırlı olmasını sağlamak için uygun erişim belirleyicinin seçilmesi önemlidir.


Soru: Aşağıdaki Java kodunda bir hata olduğunu düşünüyor musunuz? Eğer varsa, hatanın nerede olduğunu ve neden olduğunu açıklayın.


java

Copy code

// File: com/example/Book.java

package com.example;


public class Book {

    public String title;

    private String author;


    public Book(String title, String author){

        this.title = title;

        this.author = author;

    }


    private String getAuthor() {

        return this.author;

    }


    public String getTitle() {

        return this.title;

    }

}


// File: com/example/Test.java

package com.example;


import com.example.Book;


public class Test {

    public static void main(String[] args) {

        Book book = new Book("1984", "George Orwell");

        System.out.println("The author of the book is: " + book.getAuthor());

    }

}

Cevap: Evet, burada bir hata vardır. getAuthor() metodu Book sınıfında private olarak belirlenmiştir ve bu yüzden yalnızca Book sınıfının içinde erişilebilir. Test sınıfı, Book sınıfının getAuthor() metoduna doğrudan erişmeye çalışıyor ve bu bir hata oluşturacaktır. Bu hatayı çözmek için, getAuthor() metodunu public veya protected yapabiliriz veya Test sınıfında Book sınıfının getAuthor() metoduna erişim yerine, Book sınıfındaki public erişime sahip olan title özelliğini kullanabiliriz. Yani, aşağıdaki gibi bir düzeltme yapabiliriz:


java

Copy code

System.out.println("The title of the book is: " + book.getTitle());

Bu örnek, Java'da erişim belirleyicilerin önemini vurgulamaktadır. Erişim belirleyicileri, sınıfın içindeki verilere ve metotlara hangi diğer sınıfların erişebileceğini kontrol etmek için kullanılır. Bu, verilerin yanlışlıkla veya kötü niyetle değiştirilmesini önlemek için önemli bir güvenlik önlemidir. Aynı zamanda, bir sınıfın nasıl ve ne zaman kullanılacağını belirleme yeteneği sağlar, bu da kodun düzenlenmesini ve bakımını daha kolay hale getirir.


Soru: Aşağıdaki Java kodunda bir hata olduğunu düşünüyor musunuz? Eğer varsa, hatanın nerede olduğunu ve neden olduğunu açıklayın.


java

Copy code

// File: com/example/Person.java

package com.example;


public class Person {

    public String name;

    private int age;


    public Person(String name, int age){

        this.name = name;

        this.age = age;

    }


    private int getAge() {

        return this.age;

    }


    public String getName() {

        return this.name;

    }

}


// File: com/example/Test.java

package com.example;


import com.example.Person;


public class Test {

    public static void main(String[] args) {

        Person person = new Person("John Doe", 30);

        System.out.println("The age of the person is: " + person.getAge());

    }

}

Cevap: Evet, burada bir hata vardır. getAge() metodu Person sınıfında private olarak belirlenmiştir ve bu yüzden yalnızca Person sınıfının içinde erişilebilir. Test sınıfı, Person sınıfının getAge() metoduna doğrudan erişmeye çalışıyor, bu da bir hata oluşturacaktır. Bu hatayı çözmek için getAge() metodunun erişim belirleyicisini public veya protected olarak değiştirebiliriz, böylece Test sınıfı bu metoda erişebilir. İşte düzeltme:


java

Copy code

// File: com/example/Person.java

public int getAge() { // change the access modifier to public

    return this.age;

}

Bu örnekte, getAge() metodu Person sınıfının age özelliğine erişim sağlayan bir "getter" metodu olarak kullanılır. Bu tür metodlar genellikle bir sınıfın private özelliklerine güvenli ve kontrollü bir şekilde erişim sağlamak için kullanılır. Bu, verinin yanlışlıkla veya kötü niyetle değiştirilmesini önlemek için önemli bir güvenlik önlemidir. Ayrıca, bir sınıfın nasıl ve ne zaman kullanılacağını belirleme yeteneği sağlar, bu da kodun düzenlenmesini ve bakımını daha kolay hale getirir. Bu yüzden, Java'daki erişim belirleyicilerinin anlaşılması ve doğru kullanımı çok önemlidir.


Başka bir pakette yer alan bir sub class extend ettiği classın protected alanına erişemiyorsa Default (package-private) dan bir farkı kalmıyor. Sence hata yapmadın mı?


Özür dilerim, hatayı belirttiğiniz için teşekkür ederim. Gerçekten de yanıltıcı bir bilgi vermiş olabilirim. Aslında, Java'da protected ve default (package-private) erişim belirleyicileri arasında önemli bir fark vardır:


default (package-private): Erişim belirleyicisi belirtilmemiş bir üye (field ya da method) aynı paket içerisindeki tüm sınıflardan erişilebilir hale gelir, ancak paketin dışındaki sınıflar tarafından erişilemez.


protected: Bir üye protected olarak işaretlendiğinde, bu üyeye aynı paketin tüm sınıfları ve ayrıca bu sınıfı extend eden farklı paketlerdeki tüm alt sınıflar (subclass) erişebilir.


Bu nedenle, protected erişim belirleyicisi, default (package-private) erişim belirleyicisinden daha geniş bir erişim sağlar çünkü protected erişim belirleyicisi aynı zamanda alt sınıfların farklı paketlerde bile olsa protected üyeye erişimine izin verir.


Bu durumla ilgili olarak soru ve cevapla ilerleyecek olursak:


Soru: Aşağıdaki Java kodunda bir hata olduğunu düşünüyor musunuz? Eğer varsa, hatanın nerede olduğunu ve neden olduğunu açıklayın.


java

Copy code

// File: com/example/Animal.java

package com.example;


public class Animal {

    protected String type;


    public Animal(String type){

        this.type = type;

    }


    protected String getType() {

        return this.type;

    }

}


// File: com/other/Zebra.java

package com.other;


import com.example.Animal;


public class Zebra extends Animal {

    public Zebra(String type){

        super(type);

    }


    public void printType() {

        System.out.println("The type of the animal is: " + getType());

    }

}


// File: com/other/Test.java

package com.other;


import com.other.Zebra;


public class Test {

    public static void main(String[] args) {

        Zebra zebra = new Zebra("Mammal");

        zebra.printType();

    }

}

Cevap: Hayır, burada bir hata yoktur. Zebra sınıfı, Animal sınıfını extend eder ve getType() metodunu çağırabilir çünkü getType() metodu protected olarak belirlenmiştir. Bu, Zebra sınıfının getType() metoduna erişim sağlamasına ve printType() metodu içinde kullanmasına izin verir. Bu nedenle, Test sınıfının Zebra sınıfının printType() metodunu çağırması ve çıktıya yazdırması hata oluşturmaz.


Daha advanced access modifiers OCP soruları sor ve cevap ver


Elbette, Java OCP sertifikası için erişim belirleyicileri hakkında daha ileri düzeyde bazı sorular sunabilirim:


Soru 1:


Aşağıdaki kod parçasına bakın:


java

Copy code

// File: com/example/Parent.java

package com.example;


public class Parent {

    protected int x = 5;

}


Daha advanced access modifiers OCP soruları sor ve çözümleri ver


Tabii ki, Java OCP sertifikası için erişim belirleyicileri hakkında daha ileri düzeyde birkaç soru ve çözümlerini sunabilirim:


Soru 1:


Aşağıdaki kod parçasına bakın:


java

Copy code

// File: com/example/Foo.java

package com.example;


public class Foo {

    int a = 10;

    protected int b = 20;

    private int c = 30;

    public int d = 40;

}


// File: com/example/Bar.java

package com.example;


public class Bar extends Foo {

    public void print() {

        System.out.println(a);

        System.out.println(b);

        System.out.println(c);

        System.out.println(d);

    }

}

Bar sınıfının print metodu çağrıldığında ne olur?


A) 10, 20, 30 ve 40 çıktısını alırız.

B) 10, 20 ve 40 çıktısını alırız.

C) Derleme hatası alırız.

D) Çalışma zamanında bir hata oluşur.


Soru 2:


Aşağıdaki kod parçasına bakın:


java

Copy code

// File: com/example/Foo.java

package com.example;


public class Foo {

    private int a = 10;

    

    public class Bar {

        public int getA() {

            return a;

        }

    }

}


// File: com/example/Test.java

package com.example;


public class Test {

    public static void main(String[] args) {

        Foo foo = new Foo();

        Foo.Bar bar = foo.new Bar();

        System.out.println(bar.getA());

    }

}

Bu kod çalıştırıldığında ne olur?


A) "10" çıktısını alırız.

B) Bar sınıfı a'yı bulamaz ve derleme hatası alırız.

C) Test sınıfı getA() metodunu bulamaz ve derleme hatası alırız.

D) Çalışma zamanında bir hata oluşur.


Soru 1 Çözümü:


Doğru yanıt C seçeneğidir. 


Bar sınıfı, Foo sınıfını genişletir ve Foo sınıfındaki a, b ve d alanlarına erişebilir çünkü a (package-private), b (protected) ve d (public) erişim belirleyicilerine sahip. Ancak Foo sınıfındaki c alanına private olduğu için erişemez. Bu yüzden System.out.println(c); satırı bir derleme hatası verecektir.


Soru 2 Çözümü:


Doğru yanıt A seçeneğidir. "10" çıktısını alırız.


Bar bir iç sınıf olduğu için Foo sınıfının tüm üyelerine (halka açık, korunan, paket özel veya özel) erişebilir. Bu, Bar'ın Foo'nun a alanına erişimine ve bu değeri çıktıya yazmasına olanak sağlar.

// File: com/other/Child.java

package com.other;


import com.example.Parent;


public class Child extends Parent {

    public void printX() {

        System.out.println(x);

    }

}


// File: com/other/Test.java

package com.other;


public class Test {

    public static void main(String[] args) {

        Child child = new Child();

        child.printX();

    }

}

Bu kod çalıştırıldığında ne olur?


A) "5" çıktısını alırız

B) Child sınıfı x'i bulamaz ve derleme hatası alırız

C) Test sınıfı x'i bulamaz ve derleme hatası alırız

D) Çalışma zamanında bir hata oluşur


Soru 2:


Aşağıdaki kod parçasına bakın:


java

Copy code

// File: com/example/Base.java

package com.example;


public class Base {

    private String secret = "Shh!";


    protected String getSecret() {

        return secret;

    }

}


// File: com/other/Derived.java

package com.other;


import com.example.Base;


public class Derived extends Base {

    public void spill() {

        System.out.println(getSecret());

    }

}


// File: com/other/Test.java

package com.other;


public class Test {

    public static void main(String[] args) {

        Derived derived = new Derived();

        derived.spill();

    }

}

Bu kod çalıştırıldığında ne olur?


A) "Shh!" çıktısını alırız

B) Derived sınıfı getSecret() metodunu bulamaz ve derleme hatası alırız

C) Test sınıfı getSecret() metodunu bulamaz ve derleme hatası alırız

D) Çalışma zamanında bir hata oluşur


Tabii ki, soruların çözümlerini aşağıda bulabilirsiniz:


Soru 1 Çözümü:


Doğru yanıt A seçeneğidir. "5" çıktısını alırız.


Child sınıfı, Parent sınıfını extend eder ve Parent sınıfındaki protected alan x'e erişebilir. Bu durum, protected alanların aynı paket içindeki veya farklı bir paketteki alt sınıflar tarafından erişilebilir olduğunu gösterir.


Soru 2 Çözümü:


Doğru yanıt A seçeneğidir. "Shh!" çıktısını alırız.


Derived sınıfı, Base sınıfını extend eder ve getSecret() metodu protected olduğu için Derived sınıfından erişilebilir hale gelir. Bu, Derived sınıfının getSecret() metodunu çağırarak secret değerini çıktıya yazdırmasına olanak sağlar. Erişim belirleyicileri ve kalıtım hakkındaki bu bilgi, Java Sertifikasyonu (Java OCP) için önemli bir konudur. Bu örnek, protected alanların veya metodların, onları extend eden alt sınıflar tarafından nasıl kullanılabileceğini göstermektedir.


Soru:Farklı bir pakette yer alan child class'ın metodunda parent class'ın bir instance'nı oluştursak bu objenin protected alanına erişebilir miyiz? Örnek bir kodla açıklar mısın?

Erişemez. aşağıda örnek bir kod verilmiştir.

package package1;


public class ParentClass {

    public void testPublic() {

    }


    protected void testProtected() {

    }

}



package package2;


import package1.ParentClass;


public class ChildClass extends ParentClass {

   void test() {

        ParentClass par = new ParentClass();

        par.testProtected(); // Line 1 : ERROR: testProtected() has protected access in ParentClass

        testProtected();     // Line 2 : No error


        ChildClass ch = new ChildClass();

        ch.testProtected(); // Line 3 : No ERROR

        testProtected();    // Line 4 : No error

    }    

}

Java Threads kod örnekleri ile ExecuterService nedir? Neden kullanılır? Avantajları nelerdir? Dezavantajları nelerdir? Mülakat soruları ve cevapları


ExecutorService, Java'nın java.util.concurrent paketinde yer alan bir arayüzdür. İş parçacığı (thread) havuzunu yönetmek ve iş parçacığı tabanlı çoklu görev yürütmek için kullanılır. ExecutorService, yüksek düzeyde bir arayüz sağlar ve gelişmiş bir iş parçacığı yönetimi sağlar.




ExecutorService kullanmanın bazı nedenleri şunlardır:


İş parçacığı oluşturma ve yönetme işlemlerini gizler: ExecutorService, iş parçacığı oluşturma ve yönetmeyle ilgili tüm karmaşıklığı gizler. Bu sayede geliştiriciler, iş parçacığı oluşturma, başlatma ve sonlandırma gibi düşük seviyeli detaylarla uğraşmak zorunda kalmadan daha yüksek seviyeli bir arayüz üzerinden işlerini gerçekleştirebilirler.


İş parçacığı havuzunu kullanarak performansı artırır: ExecutorService, bir iş parçacığı havuzu kullanarak işleri dağıtabilir ve aynı anda birden çok işi eşzamanlı olarak çalıştırabilir. Bu, sistem kaynaklarını daha etkin bir şekilde kullanmanızı ve performansı artırmanızı sağlar.


İşler arasındaki iletişimi ve senkronizasyonu yönetir: ExecutorService, iş parçacıkları arasındaki iletişimi ve senkronizasyonu yönetmek için çeşitli mekanizmalar sağlar. Örneğin, Future nesnelerini kullanarak işin sonucunu elde edebilir veya başka bir iş parçacığı üzerinde beklemek için CountDownLatch veya CyclicBarrier gibi senkronizasyon araçlarını kullanabilirsiniz.


ExecutorService'in bazı avantajları şunlardır:


Daha iyi performans: İş parçacığı havuzunu kullanarak çoklu görevleri eşzamanlı olarak yürütebilir ve böylece performansı artırabilirsiniz. İş parçacıklarını tekrar tekrar oluşturmak yerine, havuzdaki mevcut iş parçacıklarını kullanabilirsiniz.


Kaynak yönetimi: ExecutorService, iş parçacıklarının oluşturulmasını ve sonlandırılmasını otomatik olarak yönetir. Bu sayede, kaynakların etkin bir şekilde kullanılmasını sağlar ve olası hataları en aza indirir.


İş parçacıkları arasındaki iletişimi kolaylaştırır: ExecutorService, iş parçacıkları arasında iletişim ve senkronizasyon için hazır araçlar sağlar. Bu sayede, iş parçacıkları arasında veri paylaşımı veya senkronizasyonu kolayca gerçekleştirebilirsiniz.


Bununla birlikte, ExecutorService'in bazı dezavantajları da vardır:


Kaynak tükenmesi: Eğer iş parçacığı havuzunda çok fazla iş parçacığı oluşturursanız, sistem kaynaklarının tükenmesine neden olabilirsiniz. Bu durumda, performans yerine sistem performansı düşebilir.


İş parçacığı oluşturma maliyeti: Her iş parçacığı oluşturma işlemi bir maliyete sahiptir. Eğer çok küçük işler için sürekli olarak yeni iş parçacıkları oluşturursanız, bu iş parçacığı oluşturma maliyeti zamanla artabilir.


Java'da ExecutorService kullanarak bir iş parçacığı havuzu oluşturmanın örnek kodu aşağıdaki gibidir:


java

Copy code

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;


public class Example {


    public static void main(String[] args) {

        // İş parçacığı havuzu oluşturma

        ExecutorService executor = Executors.newFixedThreadPool(5);


        // İşleri havuza gönderme

        for (int i = 0; i < 10; i++) {

            Runnable worker = new WorkerThread("Task " + i);

            executor.execute(worker);

        }


        // İş parçacığı havuzunu kapatma

        executor.shutdown();

        while (!executor.isTerminated()) {

            // Havuzun tamamen sonlandırılmasını bekleyin

        }


        System.out.println("İşler tamamlandı.");

    }

}


class WorkerThread implements Runnable {

    private String taskName;


    public WorkerThread(String taskName) {

        this.taskName = taskName;

    }


    public void run() {

        System.out.println(Thread.currentThread().getName() + " çalışıyor - " + taskName);

        // İş parçacığı tarafından gerçekleştirilecek görevi burada tanımlayın

    }

}

Bu örnekte, ExecutorService'in bir örneği olan executor oluşturuluyor. Ardından, execute() yöntemi kullanılarak işler havuza gönderiliyor. WorkerThread sınıfı, her bir işi temsil eden iş parçacığı görevini gerçekleştiriyor. İşler tamamlandıktan sonra shutdown() yöntemi ile havuz kapatılıyor ve isTerminated() yöntemi ile tamamen sonlandırılması bekleniyor.


Bu şekilde, ExecutorService kullanarak iş parçacığı havuzunu yönetebilir ve işleri daha verimli bir şekilde yürütebilirsiniz.


Senaryo 1: Birden çok işi eşzamanlı olarak yürütmek


java

Copy code

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;


public class Example {


    public static void main(String[] args) {

        // İş parçacığı havuzu oluşturma

        ExecutorService executor = Executors.newFixedThreadPool(3);


        // İşleri havuza gönderme

        executor.execute(new WorkerThread("Task 1"));

        executor.execute(new WorkerThread("Task 2"));

        executor.execute(new WorkerThread("Task 3"));


        // İş parçacığı havuzunu kapatma

        executor.shutdown();

    }

}


class WorkerThread implements Runnable {

    private String taskName;


    public WorkerThread(String taskName) {

        this.taskName = taskName;

    }


    public void run() {

        System.out.println(Thread.currentThread().getName() + " çalışıyor - " + taskName);

        // İş parçacığı tarafından gerçekleştirilecek görevi burada tanımlayın

    }

}

Bu örnekte, newFixedThreadPool(3) yöntemiyle iş parçacığı havuzu oluşturuluyor ve 3 iş gönderiliyor. Havuz, maksimum 3 iş parçacığına sahip olacak ve bu işler eşzamanlı olarak yürütülecektir.


Senaryo 2: İşlerin sonuçlarını elde etmek




java

Copy code

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.Future;


public class Example {


    public static void main(String[] args) {

        // İş parçacığı havuzu oluşturma

        ExecutorService executor = Executors.newFixedThreadPool(2);


        // İşleri havuza gönderme ve Future nesnelerini alıma

        Future<Integer> result1 = executor.submit(new CalculationTask(5));

        Future<Integer> result2 = executor.submit(new CalculationTask(10));


        // Sonuçları elde etme

        try {

            int sum = result1.get() + result2.get();

            System.out.println("Toplam: " + sum);

        } catch (Exception e) {

            e.printStackTrace();

        }


        // İş parçacığı havuzunu kapatma

        executor.shutdown();

    }

}


class CalculationTask implements Callable<Integer> {

    private int number;


    public CalculationTask(int number) {

        this.number = number;

    }


    public Integer call() throws Exception {

        // İş parçacığı tarafından gerçekleştirilecek hesaplama görevini burada tanımlayın

        int sum = 0;

        for (int i = 1; i <= number; i++) {

            sum += i;

        }

        return sum;

    }

}

Bu örnekte, submit() yöntemiyle işler havuza gönderilir ve her bir işin sonucunu temsil eden Future nesneleri elde edilir. Daha sonra get() yöntemi kullanılarak Future nesnelerinden sonuçlar alınır. Sonuçlar elde edildikten sonra iş parçacığı havuzu kapatılır.


ExecutorService, Java'da çoklu iş parçacığı yürütmek için güçlü bir araçtır. İş parçacığı havuzunu yönetmek, performansı artırmak ve iş parçacıkları arasında iletişimi kolaylaştırmak için kullanılabilir. Ancak, iş parçacığı sayısının dikkatlice yönetilmemesi ve iş parçacığı oluşturma maliyetinin göz ardı edilmesi gibi durumlarda dezavantajlara yol açabilir. Bu nedenle, ExecutorService'i kullanırken, uygulamanızın gereksinimlerine uygun olarak iş parçacığı sayısını ve kaynak kullanımını dikkatlice ayarlamalısınız.

Senaryo 3: İş Parçacığı Havuzu İçinde Belirli Aralıklarla Tekrarlanan Görevler


java

Copy code

import java.util.concurrent.Executors;

import java.util.concurrent.ScheduledExecutorService;

import java.util.concurrent.TimeUnit;


public class Example {


    public static void main(String[] args) {

        // İş parçacığı havuzu oluşturma

        ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);


        // Görevi belirli aralıklarla tekrar etmesi için planlama

        executor.scheduleAtFixedRate(new Task(), 0, 1, TimeUnit.SECONDS);


        // Belirli bir süre sonra iş parçacığı havuzunu kapatma

        try {

            Thread.sleep(5000);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        executor.shutdown();

    }

}


class Task implements Runnable {

    public void run() {

        System.out.println("Görev çalışıyor...");

        // İş parçacığı tarafından gerçekleştirilecek görevi burada tanımlayın

    }

}

Bu örnekte, newScheduledThreadPool(1) yöntemiyle iş parçacığı havuzu oluşturulur ve belirli aralıklarla tekrar eden bir görev planlanır. scheduleAtFixedRate() yöntemi kullanılarak görev belirli bir süre sonra başlatılır ve belirtilen aralıklarla tekrarlanır. Daha sonra Thread.sleep() yöntemiyle havuzun belirli bir süre çalışmasını bekleriz ve ardından havuzu kapatırız.


Senaryo 4: İş Parçacığı Havuzunda Senkronizasyon Araçları Kullanma


java

Copy code

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.TimeUnit;


public class Example {


    public static void main(String[] args) {

        // İş parçacığı havuzu oluşturma

        ExecutorService executor = Executors.newFixedThreadPool(2);


        // Senkronizasyon aracı olarak CountDownLatch kullanma

        final CountDownLatch latch = new CountDownLatch(3);


        // İşleri havuza gönderme

        executor.execute(new WorkerThread(latch, "Task 1"));

        executor.execute(new WorkerThread(latch, "Task 2"));

        executor.execute(new WorkerThread(latch, "Task 3"));


        // Tüm işlerin tamamlanmasını bekleyin

        try {

            latch.await();

        } catch (InterruptedException e) {

            e.printStackTrace();

        }


        // İş parçacığı havuzunu kapatma

        executor.shutdown();

    }

}


class WorkerThread implements Runnable {

    private CountDownLatch latch;

    private String taskName;


    public WorkerThread(CountDownLatch latch, String taskName) {

        this.latch = latch;

        this.taskName = taskName;

    }


    public void run() {

        System.out.println(Thread.currentThread().getName() + " çalışıyor - " + taskName);

        // İş parçacığı tarafından gerçekleştirilecek görevi burada tanımlayın

        try {

            TimeUnit.SECONDS.sleep(2);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        latch.countDown();

    }

}

Bu örnekte, CountDownLatch senkronizasyon aracını kullanarak iş parçacığı havuzunda görevlerin senkronize bir şekilde tamamlanmasını sağlıyoruz. Her iş parçacığı, görevi tamamladığında latch.countDown() yöntemini çağırarak bir sayaç değerini azaltır. Ana programda ise latch.await() yöntemi kullanılarak tüm işlerin tamamlanmasını bekleriz.


ExecutorService, iş parçacığı yönetimi için güçlü ve esnek bir araçtır. Farklı senaryolara uygun olarak iş parçacığı havuzunu oluşturabilir ve işleri yönetebilirsiniz. Bu sayede, çoklu görev yürütmeyi daha verimli hale getirebilir, iş parçacığı oluşturma ve yönetme işlemlerini kolaylaştırabilirsiniz. Ancak, iş parçacığı sayısı ve kaynak kullanımı gibi faktörleri dikkatlice ayarlamak önemlidir. Ayrıca, senkronizasyon ve iletişim gerektiren durumlarda uygun senkronizasyon araçlarını kullanmak önemlidir.


Senaryo 5: İş Parçacığı Havuzunda Gelecekte Gerçekleşecek Görevleri Planlama


java

Copy code

import java.util.concurrent.Executors;

import java.util.concurrent.ScheduledExecutorService;

import java.util.concurrent.TimeUnit;


public class Example {


    public static void main(String[] args) {

        // İş parçacığı havuzu oluşturma

        ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);


        // Gelecekte gerçekleşecek bir görevi planlama

        executor.schedule(new Task(), 5, TimeUnit.SECONDS);


        // Belirli bir süre sonra iş parçacığı havuzunu kapatma

        try {

            Thread.sleep(10000);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        executor.shutdown();

    }

}


class Task implements Runnable {

    public void run() {

        System.out.println("Gelecekte gerçekleşecek görev çalıştı.");

        // İş parçacığı tarafından gerçekleştirilecek görevi burada tanımlayın

    }

}

Bu örnekte, schedule() yöntemi kullanılarak gelecekte gerçekleşecek bir görev planlanır. Görev, belirli bir süre sonra (5 saniye) iş parçacığı havuzunda çalıştırılacaktır. Daha sonra Thread.sleep() yöntemiyle havuzun belirli bir süre çalışmasını bekleriz ve ardından havuzu kapatırız.


Senaryo 6: İş Parçacığı Havuzunda İş Parçacıkları Arasında Veri Paylaşımı


java

Copy code

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;


public class Example {


    public static void main(String[] args) {

        // İş parçacığı havuzu oluşturma

        ExecutorService executor = Executors.newFixedThreadPool(2);


        // Paylaşılan veriyi kullanarak işleri havuza gönderme

        SharedData sharedData = new SharedData();

        executor.execute(new WorkerThread(sharedData, "Task 1"));

        executor.execute(new WorkerThread(sharedData, "Task 2"));


        // İş parçacığı havuzunu kapatma

        executor.shutdown();

    }

}


class WorkerThread implements Runnable {

    private SharedData sharedData;

    private String taskName;


    public WorkerThread(SharedData sharedData, String taskName) {

        this.sharedData = sharedData;

        this.taskName = taskName;

    }


    public void run() {

        System.out.println(Thread.currentThread().getName() + " çalışıyor - " + taskName);

        // Paylaşılan veriye erişerek işi gerçekleştirme

        int data = sharedData.getData();

        System.out.println(taskName + " tarafından paylaşılan veri: " + data);

        // İş parçacığı tarafından gerçekleştirilecek görevi burada tanımlayın

    }

}


class SharedData {

    private int data;


    public SharedData() {

        this.data = 100;

    }


    public int getData() {

        return data;

    }

}

Bu örnekte, SharedData adında bir sınıf oluşturduk ve bu sınıf paylaşılan bir veri tutuyor. İş parçacığı havuzunda çalışan her iş parçacığı, SharedData nesnesine erişerek veriyi alıyor ve kullanıyor. Bu sayede iş parçacıkları arasında veri paylaşımı gerçekleştirilmiş oluyor.


ExecutorService, iş parçacığı havuzu yönetimini kolaylaştıran bir araçtır. Farklı senaryolara göre iş parçacığı havuzunu yapılandırabilir ve işleri yönetebilirsiniz. Bu sayede, çoklu görev yürütme, performans iyileştirmesi, senkronizasyon ve veri paylaşımı gibi iş parçacığı yönetimi konularında kolaylık sağlar. Yine de, iş parçacığı sayısını ve kaynak kullanımını dikkatli bir şekilde yönetmek önemlidir. Ayrıca, senkronizasyon araçlarını ve veri paylaşımı stratejilerini doğru şekilde kullanarak uygulamanızın doğruluğunu sağlamalısınız.


Senaryo 7: İş Parçacığı Havuzunda İşleri İptal Etme


java

Copy code

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.Future;


public class Example {


    public static void main(String[] args) {

        // İş parçacığı havuzu oluşturma

        ExecutorService executor = Executors.newFixedThreadPool(2);


        // İşleri havuza gönderme ve Future nesnelerini alıma

        Future<?> future1 = executor.submit(new Task());

        Future<?> future2 = executor.submit(new Task());


        // İşleri iptal etme

        future1.cancel(true);

        future2.cancel(true);


        // İş parçacığı havuzunu kapatma

        executor.shutdown();

    }

}


class Task implements Runnable {

    public void run() {

        while (!Thread.currentThread().isInterrupted()) {

            // İş parçacığı tarafından gerçekleştirilecek görevi burada tanımlayın

        }

        System.out.println(Thread.currentThread().getName() + " işi iptal edildi.");

    }

}

Bu örnekte, submit() yöntemi kullanılarak işler havuza gönderilir ve her bir işin sonucunu temsil eden Future nesneleri alınır. Ardından, cancel() yöntemi ile işler iptal edilir. cancel(true) parametresi, işin çalıştırıldığı iş parçacığına iptal sinyali gönderir.


Senaryo 8: İş Parçacığı Havuzunda İstisnaları Yakalama


java

Copy code

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;


public class Example {


    public static void main(String[] args) {

        // İş parçacığı havuzu oluşturma

        ExecutorService executor = Executors.newFixedThreadPool(2);


        // İşleri havuza gönderme

        executor.execute(new Task());

        executor.execute(new Task());


        // İş parçacığı havuzunu kapatma

        executor.shutdown();

    }

}


class Task implements Runnable {

    public void run() {

        try {

            // İş parçacığı tarafından gerçekleştirilecek görevi burada tanımlayın

            throw new Exception("Bir istisna oluştu.");

        } catch (Exception e) {

            System.err.println(Thread.currentThread().getName() + " işinde hata oluştu: " + e.getMessage());

        }

    }

}

Bu örnekte, iş parçacığı havuzunda çalıştırılan her işin içinde bir istisna oluşturuyoruz. try-catch bloğu içinde istisnayı yakalayarak hatayı işliyoruz. System.err.println() yöntemiyle hata mesajını konsola yazdırıyoruz.


ExecutorService, Java'da iş parçacığı yönetimini kolaylaştıran güçlü bir araçtır. Çeşitli senaryolara uygun olarak iş parçacığı havuzunu yapılandırabilir ve işleri yönetebilirsiniz. Bu sayede, çoklu görev yürütme, performans iyileştirmesi, senkronizasyon, veri paylaşımı ve iş iptali gibi iş parçacığı yönetimi konularında kolaylık sağlar. Ancak, iş parçacığı sayısını, kaynak kullanımını ve hata yönetimini dikkatli bir şekilde ele almanız önemlidir.


ExecuterService mülakat soruları ve cevapları


İşte ExecutorService ile ilgili mülakat soruları ve cevapları:


Soru 1: ExecutorService nedir?


Cevap: ExecutorService, Java'nın java.util.concurrent paketinde yer alan bir arayüzdür. İş parçacığı havuzunu yönetmek ve iş parçacığı tabanlı çoklu görev yürütmek için kullanılır. ExecutorService, yüksek düzeyde bir arayüz sağlar ve gelişmiş bir iş parçacığı yönetimi sağlar.


Soru 2: ExecutorService'in avantajları nelerdir?


Cevap: ExecutorService kullanmanın bazı avantajları şunlardır:


Daha iyi performans: İş parçacığı havuzu kullanarak çoklu görevleri eşzamanlı olarak yürütebilir ve performansı artırabilirsiniz.

Kaynak yönetimi: ExecutorService, iş parçacıklarının oluşturulmasını ve sonlandırılmasını otomatik olarak yönetir. Bu sayede, kaynakların etkin bir şekilde kullanılmasını sağlar ve hataları en aza indirir.

İş parçacıkları arasındaki iletişimi kolaylaştırır: ExecutorService, iş parçacıkları arasında iletişim ve senkronizasyon için hazır araçlar sağlar. Bu sayede, iş parçacıkları arasında veri paylaşımı veya senkronizasyonu kolayca gerçekleştirebilirsiniz.

Soru 3: ExecutorService'in dezavantajları nelerdir?


Cevap: ExecutorService'in bazı dezavantajları şunlar olabilir:


Kaynak tükenmesi: Eğer iş parçacığı havuzunda çok fazla iş parçacığı oluşturursanız, sistem kaynaklarının tükenmesine neden olabilirsiniz. Bu durumda, performans yerine sistem performansı düşebilir.

İş parçacığı oluşturma maliyeti: Her iş parçacığı oluşturma işlemi bir maliyete sahiptir. Eğer çok küçük işler için sürekli olarak yeni iş parçacıkları oluşturursanız, bu iş parçacığı oluşturma maliyeti zamanla artabilir.

Soru 4: ExecutorService ile nasıl iş parçacığı havuzu oluşturulur?


Cevap: ExecutorService ile iş parçacığı havuzu oluşturmak için Executors sınıfının yöntemlerini kullanabilirsiniz. Örneğin, newFixedThreadPool() yöntemi ile belirli bir boyutta (sabit) iş parçacığı havuzu oluşturabilirsiniz. newCachedThreadPool() yöntemi ile dinamik olarak boyutlandırılabilen bir iş parçacığı havuzu oluşturabilirsiniz. newSingleThreadExecutor() yöntemi ile sadece tek bir iş parçacığından oluşan bir havuz oluşturabilirsiniz.


Soru 5: ExecutorService ile işleri nasıl havuza gönderebiliriz?


Cevap: İşleri havuza göndermek için execute() veya submit() yöntemlerini kullanabilirsiniz. execute() yöntemi, Runnable nesnelerini kabul ederken, submit() yöntemi Runnable veya Callable nesnelerini kabul eder ve bir Future nesnesi döndürür.


Soru 6: ExecutorService ile bir işin sonucunu nasıl elde edebiliriz?


Cevap: submit() yöntemi ile gönderilen işlerin sonucunu temsil eden Future nesneleri elde edilebilir. Future nesneleri, get() yöntemi kullanılarak işin sonucunu almanızı sağlar. get() yöntemi iş tamamlanana kadar bekler ve sonucu döndürür.


Soru 7: ExecutorService ile işleri nasıl iptal edebiliriz?


Cevap: submit() yöntemi ile gönderilen işlerin iptal edilmesi için Future nesnelerinin cancel() yöntemi kullanılır. cancel() yöntemi ile işe iptal sinyali gönderilir ve iş parçacığı içinde çalışan işin iptal edilmesi sağlanır.


Soru 8: ExecutorService ile iş parçacığı havuzunu nasıl kapatırız?


Cevap: shutdown() veya shutdownNow() yöntemlerini kullanarak iş parçacığı havuzunu kapatabilirsiniz. shutdown() yöntemi, iş parçacığı havuzuna yeni işlerin kabul edilmesini durdurur ve havuzdaki mevcut işlerin tamamlanmasını bekler. shutdownNow() yöntemi ise yeni işlerin kabul edilmesini durdurur ve havuzdaki tüm işleri iptal eder.


Bu mülakat soruları ve cevapları, ExecutorService ile ilgili temel kavramları ve kullanım senaryolarını kapsamaktadır. ExecutorService'in iş parçacığı yönetimi ve çoklu görev yürütme konularında ne kadar bilgi sahibi olduğunuzu ölçmek için kullanılabilir.


Soru 1: ExecutorService ile submit() ve execute() yöntemleri arasındaki fark nedir?


Cevap: ExecutorService'in submit() yöntemi, Runnable veya Callable nesnelerini kabul eder ve bir Future nesnesi döndürür. Bu Future nesnesi, işin sonucunu temsil eder ve get() yöntemi ile sonuç alınabilir. Öte yandan, execute() yöntemi sadece Runnable nesnelerini kabul eder ve işin sonucunu döndürmez. Yani, execute() yöntemi daha basit bir şekilde işi havuza gönderirken, submit() yöntemi daha esneklik sağlar ve işin sonucunu elde etmeyi mümkün kılar.


Soru 2: ExecutorService ile bir işin tamamlanmasını nasıl bekleyebiliriz?


Cevap: Future nesnelerini kullanarak bir işin tamamlanmasını bekleyebilirsiniz. submit() yöntemi ile gönderilen işlerin sonucunu temsil eden Future nesneleri elde edilebilir. Future nesnelerinin get() yöntemini kullanarak işin tamamlanmasını bekleyebilirsiniz. get() yöntemi, iş tamamlanana kadar bekler ve sonucu döndürür. Eğer birden fazla Future nesnesi varsa, CompletableFuture sınıfı veya CountDownLatch gibi senkronizasyon araçlarını kullanarak tüm işlerin tamamlanmasını bekleyebilirsiniz.


Soru 3: ExecutorService ile bir işin zamanlanmasını nasıl yapabiliriz?


Cevap: ScheduledExecutorService arayüzü, işlerin zamanlanmasını sağlar. Executors sınıfının newScheduledThreadPool() yöntemi kullanılarak bir ScheduledExecutorService nesnesi oluşturulabilir. Ardından, schedule() veya scheduleAtFixedRate() yöntemleri kullanılarak işler belirli bir süre sonra veya belirli aralıklarla çalıştırılabilir. schedule() yöntemi, işin belirli bir süre sonra başlatılmasını sağlar. scheduleAtFixedRate() yöntemi ise işin belirli aralıklarla düzenli olarak çalıştırılmasını sağlar.


Soru 4: ExecutorService'in shutdown() ve shutdownNow() yöntemleri arasındaki fark nedir?


Cevap: ExecutorService'in shutdown() yöntemi, iş parçacığı havuzuna yeni işlerin kabul edilmesini durdurur ve havuzdaki mevcut işlerin tamamlanmasını bekler. Yani, havuzdaki tüm işlerin bitirilmesini bekler, ancak işlemler tamamlanmadan program sonlanmaz. Diğer yandan, shutdownNow() yöntemi, iş parçacığı havuzuna yeni işlerin kabul edilmesini durdurur ve havuzdaki tüm işleri iptal eder. İşlemler anında sonlandırılır ve hangi işlerin tamamlandığına bakılmaksızın iptal edilir.


Soru 5: ExecutorService ile iş parçacığı havuzunu nasıl boyutlandırabiliriz?


Cevap: Executors sınıfının newFixedThreadPool() yöntemi ile sabit boyutlu bir iş parçacığı havuzu oluşturabilirsiniz. Bu yöntem belirli bir iş parçacığı sayısıyla bir havuz oluşturur ve her bir işi havuzdaki iş parçacıklarına dağıtır. Yine Executors sınıfının newCachedThreadPool() yöntemiyle dinamik boyutlandırılabilen bir iş parçacığı havuzu oluşturabilirsiniz. Bu yöntemde, ihtiyaç duyulan kadar iş parçacığı oluşturulur ve boşta kalan iş parçacıkları zamanla sonlandırılır.


Soru 6: ExecutorService'in yeni bir görevin başlatılmasını beklemek için hangi yöntemi kullanabiliriz?


Cevap: Future nesnelerini kullanarak yeni bir görevin başlatılmasını bekleyebilirsiniz. submit() yöntemi ile gönderilen işlerin sonucunu temsil eden Future nesnelerini alabilirsiniz. Future nesnelerinin get() yöntemini kullanarak yeni bir görevin tamamlanmasını bekleyebilirsiniz. get() yöntemi, yeni bir görev tamamlandığında sonucu döndürür.


Bu mülakat soruları ve cevapları, ExecutorService'in daha ileri düzeydeki konseptlerini ve kullanım senaryolarını kapsamaktadır. ExecutorService ile ilgili detaylı bilgi sahibi olmak ve mülakatlar için hazırlık yapmak için Java'nın java.util.concurrent paketinde yer alan diğer sınıfları (ScheduledExecutorService, CompletableFuture, Callable, vb.) da incelemeniz faydalı olacaktır.

Java Optional detaylı anlatım ve mülakat soruları ve cevapları

Java Optional detaylı anlatım



Java'da Optional sınıfı, Java 8'de tanıtılan bir sınıftır ve bir değerin var olup olmadığını ifade etmek için kullanılır. Optional sınıfı, null değerlerle ilgili sorunları ele almak için tasarlanmıştır ve NullPointerException'ları önlemek için kullanılabilir.


Optional sınıfı, genellikle bir metot tarafından döndürülen değerin null olabileceği durumları ele almak için kullanılır. Örneğin, bir metot bir String nesnesi döndürüyor olabilir, ancak bu String nesnesi null olabilir. Bu durumu ifade etmek için Optional<String> kullanabilirsiniz.


Optional sınıfını kullanırken, değeri boş (empty) veya dolu (present) olarak kontrol edebilirsiniz. Değerin var olup olmadığını kontrol etmek için isPresent() metodu kullanılır. Değer varsa, get() metoduyla değeri elde edebilirsiniz. Ancak, get() metodu kullanılırken değerin var olup olmadığını kontrol etmek önemlidir, çünkü değer yoksa bir NoSuchElementException fırlatılır.


java

Copy code

Optional<String> optionalValue = getValue();


if (optionalValue.isPresent()) {

    String value = optionalValue.get();

    System.out.println("Value is present: " + value);

} else {

    System.out.println("Value is empty");

}

Optional sınıfı, orElse() ve orElseGet() gibi metotlar aracılığıyla varsayılan bir değer sağlama yeteneği de sunar. orElse() metodu, değer varsa onu döndürür, aksi takdirde belirtilen varsayılan değeri döndürür. orElseGet() metodu ise değer varsa onu döndürür, aksi takdirde bir Supplier fonksiyonu aracılığıyla belirtilen varsayılan değeri döndürür. orElseGet() metodu, varsayılan değerin hesaplanması maliyetli bir işlem olduğunda kullanılabilir, çünkü değer varsa hesaplama yapılmaz.


java

Copy code

String value = getValue().orElse("Default Value");

String value = getValue().orElseGet(() -> calculateDefaultValue());

Optional sınıfı ayrıca, değerin var olmadığı durumda istisna fırlatmak için orElseThrow() metoduyla da kullanılabilir.


java

Copy code

String value = getValue().orElseThrow(() -> new IllegalStateException("Value not present"));

Optional sınıfı, değeri üzerinde işlemler yapmak için map(), flatMap() ve filter() gibi fonksiyonel metodları da destekler. map() metodu, değeri dönüştürmek veya üzerinde işlemler yapmak için kullanılırken, flatMap() metodu, değeri dönüştürmek ve Optional nesnesini düzleştirmek için kullanılır. filter() metodu ise belirli bir koşula göre değeri filtrelemek için kullanılır.


java

Copy code

Optional<String> optionalValue = getValue();


Optional<Integer> lengthOptional = optionalValue.map(String::length);


Optional<String> uppercaseOptional = optionalValue.flatMap(str -> Optional.ofNullable(str.toUpperCase()));


Optional<String> filteredOptional = optionalValue.filter(str -> str.length() > 5);

Java'da Optional sınıfı, null kontrollerini daha kolay hale getirir ve NullPointerException hatalarını önlemeye yardımcı olur. Bununla birlikte, Optional sınıfını kullanırken dikkatli olmak önemlidir. Her zaman değerin var olup olmadığını kontrol etmek ve gerektiğinde varsayılan değerler veya istisnalar sağlamak için uygun metodları kullanmak önemlidir.


Bir diğer önemli özellik, Optional sınıfının bir dizi yardımcı metodunu kullanarak null değerleri Optional nesnelerine dönüştürme yeteneğidir. Optional sınıfının statik metotları arasında of() ve ofNullable() bulunur. of() metodu, null olmayan bir değeri Optional nesnesine dönüştürürken, ofNullable() metodu null değeri de kabul eder ve gerektiğinde bir Optional nesnesini boş olarak oluşturur.


java

Copy code

String value = "Hello";

Optional<String> optionalValue = Optional.of(value);


String nullableValue = null;

Optional<String> optionalNullableValue = Optional.ofNullable(nullableValue);

Optional sınıfı, nesne zincirlemesi (chaining) yapısını destekler. Bu, bir Optional nesnesi üzerinde ardışık işlemler yapmanıza olanak tanır. Örneğin, bir metotun dönüş değeri olan Optional nesnesi üzerinde ardışık olarak map() ve filter() gibi metotları çağırabilirsiniz.


java

Copy code

Optional<String> optionalValue = getValue();


optionalValue.map(String::toUpperCase)

            .filter(str -> str.length() > 5)

            .ifPresent(System.out::println);

Yukarıdaki örnekte, getValue() metodu bir Optional nesnesi döndürüyor ve ardından map() metodu ile değeri büyük harflere dönüştürüyoruz. Daha sonra filter() metodu ile sadece belirli bir koşulu sağlayan değerleri filtreliyoruz. Son olarak, ifPresent() metodu ile sonuç değerini kullanarak bir eylem gerçekleştiriyoruz.


Optional sınıfı, null kontrolü ve varsayılan değer sağlama gibi durumları ele almak için kullanışlı bir araçtır. Bununla birlikte, gereksiz kullanımı veya kötü tasarımı önlemek için dikkatli olmak önemlidir. Bazı durumlarda, basit null kontrolü veya ifadelerin doğrudan kullanılması daha uygun olabilir. Optional sınıfını anlamlı ve uygun yerlerde kullanmak, kodun okunabilirliğini artırabilir ve NullPointerException hatalarını önleyebilir.

Optional ifPresent nedir


ifPresent() metodu, Java Optional sınıfının bir metodu olup, bir değer varsa üzerinde bir eylem gerçekleştirmek için kullanılır.


ifPresent() metodu, Optional nesnesi içinde bir değer bulunuyorsa (yani Optional nesnesi dolu veya boş değilse), belirtilen bir Consumer fonksiyonunu çağırır ve değeri bu fonksiyona iletir. Bu şekilde, değer varsa belli bir eylem gerçekleştirilebilir.


Örnek olarak, bir Optional nesnesi üzerinde ifPresent() metodu kullanımı:


java

Copy code

Optional<String> optionalValue = Optional.of("Hello");

optionalValue.ifPresent(value -> System.out.println("Value: " + value));

Yukarıdaki örnekte, optionalValue bir String değerine sahip olan bir Optional nesnesini temsil ediyor. ifPresent() metodu, değer varsa verilen lambda ifadesini (Consumer fonksiyonunu) çağırır ve değeri bu lambda ifadesine iletir. Bu durumda, değer "Hello" olduğu için lambda ifadesi çalışır ve "Value: Hello" şeklinde bir çıktı elde edilir.


ifPresent() metodu, Optional nesnesi içinde bir değer varsa belli bir eylem gerçekleştirmek için kullanışlıdır. Özellikle, değeri kontrol etmek ve üzerinde işlemler yapmak için kullanabiliriz. Böylece, değerin var olup olmadığına göre farklı kod bloklarını çalıştırabiliriz.


Eğer Optional nesnesi boş ise (yani içinde bir değer yoksa), ifPresent() metodu hiçbir şey yapmaz ve hiçbir eylem gerçekleştirmez. Bu nedenle, boş Optional nesneleri üzerinde ifPresent() metodu kullanıldığında herhangi bir hata veya istisna fırlatılmaz.


Optional empty nedir?


Optional.empty() metodu, Optional sınıfının statik bir metodu olup, boş bir Optional nesnesi oluşturmak için kullanılır. Yani, bu metot çağrıldığında, içinde hiçbir değer bulunmayan bir Optional nesnesi elde edilir.


Boş bir Optional nesnesi, değerin var olmadığı durumları ifade etmek için kullanılır. Örneğin, bir metot bir değer döndürse de döndürmese de, bu durumu Optional.empty() ile ifade edebilirsiniz.


java

Copy code

Optional<String> optionalValue = Optional.empty();

Bu şekilde oluşturulan boş Optional nesnesi, isPresent() metoduyla kontrol edildiğinde false dönecektir. Yani, içinde bir değer olmadığı anlaşılır.


java

Copy code

if (optionalValue.isPresent()) {

    // Değer varsa buraya girer

} else {

    // Değer yoksa buraya girer

}

Boş bir Optional nesnesi üzerinde get() metodu çağrıldığında ise NoSuchElementException hatası fırlatılır. Bu nedenle, get() metodu kullanılmadan önce isPresent() metoduyla varlığın kontrol edilmesi önemlidir.


Boş Optional nesneleri, genellikle bir değerin null olabileceği durumları ele almak veya varsayılan bir değer sağlamak için kullanılır. Örneğin, bir metot bir String değeri döndürse de döndürmese de, boş bir Optional nesnesiyle bu durumu ifade edebilir ve çağıran kodun varlığın kontrolünü yapmasını sağlayabilir.


java

Copy code

public Optional<String> getValue() {

    // Değer varsa

    if (/* değer var mı kontrolü */) {

        return Optional.of("Değer");

    }

    

    // Değer yoksa

    return Optional.empty();

}

Böylece, getValue() metodu çağrıldığında dönen Optional nesnesi üzerinde isPresent() metoduyla kontrol yapılabilir ve değerin var olup olmadığı anlaşılabilir.


Optional.empty() metodu, Optional sınıfının kullanımında boş bir değeri ifade etmek için yaygın olarak kullanılan bir yöntemdir ve null kontrollerini daha okunabilir bir şekilde gerçekleştirmeyi sağlar.


Optional.ofNullable(null) ile oluşturulan değeri get() ile çağırdığımızda ne döner?


Optional.ofNullable(null) ifadesiyle oluşturulan bir Optional nesnesini get() metoduyla çağırdığımızda NullPointerException hatası fırlatılır.


Optional.ofNullable() metodu, parametre olarak verilen değeri bir Optional nesnesine dönüştürür. Eğer verilen değer null ise, ofNullable() metodu boş bir Optional nesnesi oluşturur. Bu durumda, get() metodu çağrıldığında bir NullPointerException hatası alınır.


Aşağıdaki örnek bu durumu göstermektedir:


java

Copy code

String value = null;

Optional<String> optionalValue = Optional.ofNullable(value);


String result = optionalValue.get(); // NullPointerException hatası

Yukarıdaki kodda, value değişkeni null olduğu için Optional.ofNullable() metodu boş bir Optional nesnesi oluşturur. Ardından, get() metodu çağrıldığında NullPointerException hatası fırlatılır, çünkü value null olduğu için içerisinde bir değer bulunmamaktadır.


Bu nedenle, bir Optional nesnesini get() metoduyla çağırmadan önce her zaman isPresent() metoduyla varlığın kontrol edilmesi önemlidir. Alternatif olarak, orElse() veya orElseGet() gibi metotları kullanarak varsayılan bir değer belirleyebilirsiniz. Böylece, null değerlerden kaynaklanabilecek potansiyel hataları önleyebilirsiniz.


java

Copy code

String value = null;

Optional<String> optionalValue = Optional.ofNullable(value);


String result = optionalValue.orElse("Varsayılan Değer"); // Varsayılan Değer

Yukarıdaki örnekte, orElse() metodu kullanılarak bir varsayılan değer belirlenmiştir. Eğer optionalValue içerisinde bir değer yoksa, orElse() metodu belirtilen varsayılan değeri döndürecektir. Bu sayede NullPointerException hatası almadan güvenli bir şekilde çalışma sağlanır.


Kod örnekleri ve senaryolar ile Java Optional mülakat soruları ve cevapları


ChatGPT

Elbette! İşte Java Optional ile ilgili yaygın olarak sorulan mülakat sorularından bazıları ve olası cevapları:


Soru 1:

Java'da Optional sınıfı nedir ve nasıl kullanılır?


Cevap 1:

Optional sınıfı, Java 8'de tanıtılan bir sınıftır ve bir değerin var olup olmadığını ifade etmek için kullanılır. Değerin var olup olmadığını kontrol etmek için isPresent() metodu kullanılır. Değer varsa get() metoduyla değeri alabiliriz. Ayrıca, orElse() ve orElseGet() gibi metotlarla varsayılan değer sağlama yeteneği vardır. Optional sınıfı, null kontrollerini daha kolay hale getirir ve NullPointerException hatalarını önlemeye yardımcı olur.


Soru 2:

Optional.of() ve Optional.ofNullable() arasındaki fark nedir?


Cevap 2:

Optional.of() metodu, null olmayan bir değeri Optional nesnesine dönüştürür. Eğer parametre olarak null verilirse NullPointerException hatası fırlatır. Optional.ofNullable() metodu ise null değeri de kabul eder ve gerektiğinde bir boş Optional nesnesi oluşturur. Yani, Optional.ofNullable() ile null bir değeri Optional nesnesine dönüştürebiliriz.


Soru 3:

Optional sınıfının get() metodu hangi durumda hata fırlatır?


Cevap 3:

get() metodu, Optional nesnesi boş ise yani içinde bir değer yoksa NullPointerException hatası fırlatır. Bu nedenle, get() metodu çağrılmadan önce her zaman isPresent() metodu ile varlığın kontrol edilmesi önemlidir.


Soru 4:

Optional sınıfı neden kullanmalıyız? Hangi durumlarda kullanışlıdır?


Cevap 4:

Optional sınıfı, bir değerin var olup olmadığını ifade etmek için kullanılır ve null kontrollerini daha kolay hale getirir. NullPointerException hatalarını önlemeye yardımcı olur. Özellikle bir metot tarafından döndürülen değerin null olabileceği durumları ele almak veya varsayılan değer sağlamak için kullanışlıdır. Ayrıca, Optional sınıfı, değeri üzerinde işlemler yapmak ve fonksiyonel programlama tekniklerini kullanmak için de kullanılabilir.


Soru 5:

Optional sınıfı neden immutable (değiştirilemez) bir sınıftır?


Cevap 5:

Optional sınıfı immutable bir sınıftır, yani bir kez oluşturulduktan sonra içeriği değiştirilemez. Bu, Optional nesnelerinin güvenli bir şekilde paylaşılmasını ve thread güvenliğini sağlar. Aynı zamanda, değerlerin değiştirilemez olması, kodun daha tahmin edilebilir ve yan etkilerden uzak olmasını sağlar.


Bu sorular, Java Optional konusunda genel bir anlayışı değerlendirmek ve adayın Optional sınıfını nasıl kullanabileceğini görmek için yaygın olarak kullanılan sorulardan sadece birkaç örnektir. Mülakat durumuna göre, daha spesifik veya derinlemesine sorular da sorulabilir.


Soru 6:

Optional sınıfının map() ve flatMap() metotları arasındaki fark nedir? Ne zaman hangisini tercih etmeliyiz?


Cevap 6:

map() ve flatMap() metotları, Optional sınıfının fonksiyonel metodlarıdır ve değer üzerinde dönüşümler yapmak için kullanılırlar.


map() metodu, bir değeri dönüştürmek veya üzerinde işlemler yapmak için kullanılır. Bu metot, bir fonksiyonu uygular ve sonucu yeni bir Optional nesnesi olarak döndürür. Örneğin, bir String değerinin uzunluğunu hesaplamak için map() metodu kullanılabilir:


java

Copy code

Optional<String> optionalValue = Optional.of("Hello");

Optional<Integer> lengthOptional = optionalValue.map(String::length);

flatMap() metodu ise, değeri dönüştürmek ve Optional nesnesini düzleştirmek için kullanılır. Bu metot, bir fonksiyonu uygular ve sonucu bir Optional nesnesi olarak döndürür. Farkı, flatMap() metodu, dönüşüm sonucu olarak bir Optional nesnesi döndürebilirken, map() metodu sadece değeri dönüştürebilir. Örneğin, bir String değerini büyük harflere dönüştürmek ve sonucu yeni bir Optional nesnesi olarak döndürmek için flatMap() metodu kullanılabilir:


java

Copy code

Optional<String> optionalValue = Optional.of("Hello");

Optional<String> uppercaseOptional = optionalValue.flatMap(str -> Optional.ofNullable(str.toUpperCase()));

Hangi metodun tercih edilmesi gerektiği, dönüşüm işlemine bağlıdır. Eğer dönüşüm sonucunda bir Optional nesnesi dönmek isteniyorsa ve sonucun iç içe geçmiş bir Optional olmasında sakınca yoksa, flatMap() metodu tercih edilebilir. Aksi takdirde, sadece değeri dönüştürmek için map() metodu kullanılabilir.

Soru 7:

Optional sınıfıyla birlikte filter() metodunu nasıl kullanırız ve ne zaman kullanılır?


Cevap 7:

filter() metodu, Optional sınıfının bir fonksiyonel metodu olup, bir değeri belirli bir koşula göre filtrelemek için kullanılır.


filter() metodu, bir Predicate fonksiyonu alır ve bu koşulu karşılayan değerlerin Optional nesnesini döndürür. Eğer değer koşulu karşılamazsa veya Optional nesnesi boş ise, filter() metodu boş bir Optional nesnesini döndürür.


Örnek olarak, bir Integer değerini filtrelemek için filter() metodu kullanılabilir:


java

Copy code

Optional<Integer> optionalValue = Optional.of(10);

Optional<Integer> filteredOptional = optionalValue.filter(value -> value > 5);

Yukarıdaki örnekte, optionalValue, 10 değerine sahip bir Optional nesnesini temsil ediyor. filter() metodu, değeri 5'ten büyük olan değerlerin Optional nesnesini döndürür. Eğer değer 5'ten küçük veya eşitse, boş bir Optional nesnesi elde edilir.


filter() metodu, değeri filtrelemek için kullanışlıdır ve istenmeyen değerleri elerken veya belirli bir koşulu sağlayan değerleri elde etmek istediğimiz durumlarda kullanılabilir. Böylece, istenmeyen değerlerin üzerinde işlem yapmadan önce onları elemiş oluruz.


Umarım bu soru ve cevap, Java Optional ve filter() metodunun kullanımını anlamanıza yardımcı olur. Başka sorularınız varsa, sormaktan çekinmeyin.

Rastgele İçerik

DonanımHaber

© tüm hakları saklıdır
made with by templateszoo