Kotlin 10- Data Classes

Cenker Aydın
5 min readAug 22, 2023

--

Merhabalar, bugün sizlerle Data Class yapısını inceleyeceğiz, Beğenmeyi ve takip etmeyi unutmayın. Tüm seriye buradan erişebilirsiniz. Keyifli Okumalar!

Data class

Kotlin’de data class olarak adlandırılan sınıf türü, genellikle veri taşımak amacıyla kullanılan ve bazı temel işlevleri otomatik olarak sağlayan bir yapıdır. Bu sınıf türü, verileri tutmak, erişmek ve karşılaştırma yapmak gibi yaygın operasyonları kolaylaştırmak için kullanılır. Kodunuzun daha temiz ve okunabilir olmasını istiyorsanız data class kullanabilirsiniz.

  • Class ismi başına data keywordu getirerek kullanılır.
data class User(val name:String)
  • Primary constructor içermektedir ve bu constructor içerisinde en az bir tane parametre yazılmak zorundadır ve bu parametre val veya var ile tanımlanmalıdır.
data class User(var name: String, var surname:String) 
  • Open, abstract, sealed, inner class yapılamaz. Tüm data classları default olarak final olduğu için final modifieri redundant uyarısı verir.
  • Final olduğu için bir class miras alamaz ama data classlar abstract ya da open classları miras alabilir. Interfaceleri implement edebilir.
open class C:User() 

Bu kullanım hata verecektir çünkü data classlar miras alınamaz.

Hata: This type is final, so it cannot be inherited

  • equals, hashCode, toString, copy, componentN fonksiyonları arka planda default olarak oluştururlar. Bu java koduna göre daha temiz görünüm ve kolaylık sağlar.

Bir tane Kotlin kodu yazalım ve bunu shift+shift -> Show Kotlin ByteCode -> Decompile yaparak java koduna bakalım.

Kotlin kodu:

data class User(val name:String)

Java kodu:

public final class User {
@NotNull
private final String name;

@NotNull
public final String getName() {
return this.name;
}

public User(@NotNull String name) {
Intrinsics.checkNotNullParameter(name, "name");
super();
this.name = name;
}

@NotNull
public final String component1() {
return this.name;
}

@NotNull
public final User copy(@NotNull String name) {
Intrinsics.checkNotNullParameter(name, "name");
return new User(name);
}

// $FF: synthetic method
public static User copy$default(User var0, String var1, int var2, Object var3) {
if ((var2 & 1) != 0) {
var1 = var0.name;
}

return var0.copy(var1);
}

@NotNull
public String toString() {
return "User(name=" + this.name + ")";
}

public int hashCode() {
String var10000 = this.name;
return var10000 != null ? var10000.hashCode() : 0;
}

public boolean equals(@Nullable Object var1) {
if (this != var1) {
if (var1 instanceof User) {
User var2 = (User)var1;
if (Intrinsics.areEqual(this.name, var2.name)) {
return true;
}
}

return false;
} else {
return true;
}
}
}

Gördüğünüz gibi 1 satır kod, kaç satır koda karşılık geliyor :) Kotlin diline teşekkür edelim ve konumuza devam edelim.

Data classlar’ın equals, hashCode, toString, copy ve componentN fonksiyonlarını otomatik olarak oluşturduğunu söylemiştik, şimdi gelin birlikte bu fonksiyonlar ne işe yarar tek tek inceleyelim:

equals() fonksiyonu

Bir nesneyi başka bir nesne ile karşılaştırmak için kullanılan bir yöntemdir. Data classlarda otomatik olarak oluşturulur.

data class User(val name:String,val age:Int)

fun main() {
val user1=User("Cenker",21)
val user2=User("Aydın",18)
val user3=User("Cenker",21)

println( user1.equals(user2)) //false
println( user1.equals(user3)) //true
println( user2.equals(user3)) //false

}

hashCode() fonksiyonu

hashCode() fonksiyonu, bir nesnenin benzersiz bir tamsayı değerini temsil eden bir karma kod (hash code) üretmek için kullanılan bir yöntemdir. Bu değer, genellikle nesnenin içeriği veya özellikleri temel alınarak hesaplanır. Hash kodları, veri yapılarının ve koleksiyonların performanslı bir şekilde çalışmasını sağlamak için önemlidir.

data class User(val name:String,val age:Int)

fun main() {
val user1=User("Cenker",21)
val user2=User("Aydın",18)
val user3=User("Cenker",21)

println(user1.hashCode()) //-1965342999
println(user2.hashCode()) //1975916489
println(user3.hashCode()) //-1965342999
}

toString() fonksiyonu

Bir nesneyi insan tarafından okunabilir bir metin temsiline dönüştürmek için kullanılan bir yöntemdir. Bu metot, nesnenin içeriğini veya durumunu bir metin olarak göstermeye yardımcı olur.

data class User(val name:String,val age:Int)

fun main() {
val user1=User("Cenker",21)
val user2=User("Aydın",18)
val user3=User("Cenker",21)

println(user1.toString())
println(user2.toString())
println(user3.toString())
}
Kodun çıktısı

copy() fonksiyonu

Kotlin’deki data class’ların özelliklerini değiştirerek yeni bir kopya oluşturmak için kullanılan bir yöntemdir. Bu fonksiyon, mevcut nesnenin tüm özelliklerini koruyarak istenen özellikleri değiştirmenizi sağlar.

data class User(val name:String,val age:Int)

fun main() {
val user1=User("Cenker",21)
val user2=user1.copy(name = "John")
val user3=user2.copy(name = "Bob",12)

println(user1.toString())
println(user2.toString())
println(user3.toString())
}
Kodun çıktısı

componentN() fonksiyonu

Veri sınıflarının bileşenlerine erişmek için kullanılır. Bu fonksiyonlar, data class’ların özelliklerini sırayla indeks numaralarıyla çağırmanıza olanak tanır. Primary constructor içerisinde tanımlayıp data class içerisinde tanımlanan propertylerin component fonksiyonu yazılmaz.

data class User(val name:String,val age:Int)

fun main() {
val user1=User("Cenker",21)
println(user1.component1()) //Cenker
println(user1.component2()) //21
}

componentN fonksiyonları özellikle descructuring declaration gibi yerlerde kullanışlıdır.

Descructuring Declaration

Kotlin gibi bazı programlama dillerinde özellikle veri sınıfları veya veri yapısı taşıyan nesnelerin içeriğini parçalayarak ayrı değişkenlere atanmasını sağlayan bir yapıdır. Bu özellik, nesnelerin içeriğini kolayca çıkartarak kullanılmasını sağlar ve bu kodun daha temiz ve okunabilir olmasını sağlar.

Bir örnek ile açıklayalım:

data class User(val name:String,val age:Int)

fun main() {
val (user,age)=User("Cenker",21) //Descructuring declaration
}

Destructuring declaration, koleksiyonlar, haritalar, veritabanı sorgu sonuçları gibi veri yapılarıyla da kullanılabilir ve kodun daha kompakt hale gelmesini sağlar. Aynı zamanda, belirli özelliklere daha hızlı erişim ve kodun okunabilirliğini artırma avantajına sahiptir.

Yukarıda bahsettiğim fonksiyonlardan biri özelleştirmek için override edilirse otomatik olarak generate edilen hali yazılmaz, özelleştirilen hali yazılır. Yukarıdaki fonksiyonlar sadece primary const. içerisindeki değişkenlerle çalışır. Primary cons. içerisindeki değişkenlerin var ya da val olması zorunluluğu da buradan gelir, sınıf içerisinde yazılan fonksiyon içinde kullanılabilmesini sağlar.

Pair, Triple gibi özelleştirilmiş generic data classlar mevcuttur.

Data Class Avantajları

  1. Otomatik Özellikler ve Metotlar: Data class’lar, özellikleri tanımladığınızda otomatik olarak getter ve setter metotları da oluşturur. Ayrıca equals(), hashCode(), toString() ve copy() gibi yaygın metotları da otomatik olarak sağlar. Bu sayede basit veri taşıma amaçları için kodunuzu daha temiz ve az sayıda kodla yazabilirsiniz.
  2. Destructuring Declaration Desteği: Data class’lar, ayrıştırma deklarasyonu ile kullanıldığında nesnenin özelliklerini kolayca ayrıştırarak değişkenlere atama yapmanıza olanak tanır. Bu, kodun daha okunabilir ve kompakt hale gelmesini sağlar.
  3. Koleksiyonlarda Kullanım Kolaylığı: Data class’lar, koleksiyonlarda nesneleri taşımanın ve işlemenin daha kolay olmasını sağlar. Özellikle koleksiyon işlemleri yaparken, eşitlik ve karşılaştırma gibi işlemleri daha hızlı ve hatasız bir şekilde gerçekleştirmenizi sağlar.

Okuduğunuz için teşekkür ederim. Yazılar hakkında feedback vermek veya herhangi bir konu hakkında bana ulaşmak için: Linkedin

--

--