├── .gitignore ├── build.gradle.kts ├── gradle.properties ├── gradle └── wrapper │ └── gradle-wrapper.properties ├── settings.gradle.kts └── src └── main └── kotlin ├── 1-Types.kt ├── 10-OperatorOverloading.kt ├── 11-1.jpg ├── 11-Generics.kt ├── 12-Generics.kt ├── 13-Generics.kt ├── 14-Reflection.kt ├── 15-Delegation.kt ├── 16-DelegatedProperties.kt ├── 17-FunctionalProgramming.kt ├── 18-FunctionalProgramming.kt ├── 19-FunctionalProgramming.kt ├── 2-Loops.kt ├── 20-FunctionalProgramming.kt ├── 21-FunctionalProgramming.kt ├── 3-Functions.kt ├── 4-InlineFunctions.kt ├── 5-Properties.kt ├── 6-Scope Functions.webp ├── 6-ScopeFunctions.kt ├── 7-Exceptions.kt ├── 8-AbstractClasses.kt └── 9-InlineValueClasses.kt /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | !**/src/main/**/build/ 5 | !**/src/test/**/build/ 6 | 7 | ### IntelliJ IDEA ### 8 | .idea/ 9 | .idea/modules.xml 10 | .idea/jarRepositories.xml 11 | .idea/compiler.xml 12 | .idea/libraries/ 13 | *.iws 14 | *.iml 15 | *.ipr 16 | out/ 17 | !**/src/main/**/out/ 18 | !**/src/test/**/out/ 19 | 20 | ### Eclipse ### 21 | .apt_generated 22 | .classpath 23 | .factorypath 24 | .project 25 | .settings 26 | .springBeans 27 | .sts4-cache 28 | bin/ 29 | !**/src/main/**/bin/ 30 | !**/src/test/**/bin/ 31 | 32 | ### NetBeans ### 33 | /nbproject/private/ 34 | /nbbuild/ 35 | /dist/ 36 | /nbdist/ 37 | /.nb-gradle/ 38 | 39 | ### VS Code ### 40 | .vscode/ 41 | 42 | ### Mac OS ### 43 | .DS_Store 44 | /gradle/wrapper/gradle-wrapper.jar 45 | /gradlew 46 | /gradlew.bat 47 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | kotlin("jvm") version "1.9.23" 3 | } 4 | 5 | group = "org.example" 6 | version = "1.0-SNAPSHOT" 7 | 8 | repositories { 9 | mavenCentral() 10 | } 11 | 12 | dependencies { 13 | testImplementation(kotlin("test")) 14 | implementation ("org.jetbrains.kotlin:kotlin-reflect:1.9.10") 15 | } 16 | 17 | tasks.test { 18 | useJUnitPlatform() 19 | } 20 | kotlin { 21 | jvmToolchain(17) 22 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.code.style=official 2 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri May 31 13:49:53 TRT 2024 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("org.gradle.toolchains.foojay-resolver-convention") version "0.5.0" 3 | } 4 | rootProject.name = "KotlinLastButNotLeast" 5 | 6 | -------------------------------------------------------------------------------- /src/main/kotlin/1-Types.kt: -------------------------------------------------------------------------------- 1 | package org.example 2 | 3 | /** 4 | * Eğer bir değişkeni nullable yaparsanız örneğin Int? aynı sınıf gibi davranır. Aksi takdirde 5 | * primitive gibi davranır. 6 | */ 7 | 8 | fun main() { 9 | val primitive: Int = 1967 10 | 11 | var nullable: Int? = null 12 | 13 | /** 14 | * -128 ile 127 arasında memory optimizasyonu yapıldığı için nullable ile normal değerler birbirine denktir. 15 | * Sınır aşıldığı durumlarda ise denk olmazlar. 16 | */ 17 | var a = 120 18 | 19 | var b: Int? = a 20 | 21 | var c:Int? = a 22 | 23 | println("eşitlik:${b == c} denklik:${b === c}") 24 | 25 | /** 26 | * Stringler immutable dır bir kere değer atandı mı o değiştirilemez. 27 | */ 28 | var str = "abcd" 29 | } -------------------------------------------------------------------------------- /src/main/kotlin/10-OperatorOverloading.kt: -------------------------------------------------------------------------------- 1 | package org.example 2 | 3 | data class Point(val x: Int, val y: Int) { 4 | operator fun invoke() = "X:$x Y:$y" 5 | } 6 | 7 | class ShapeOperator { 8 | private val points = mutableListOf() 9 | operator fun Point.unaryPlus() { 10 | points.add(this) 11 | } 12 | 13 | fun getPoints() = points 14 | } 15 | 16 | fun shape(init: ShapeOperator.() -> Unit): ShapeOperator { 17 | val shape = ShapeOperator() 18 | shape.init() 19 | return shape 20 | } 21 | 22 | operator fun String.minus(char: Char): String { 23 | return dropLastWhile { 24 | it != char 25 | } 26 | } 27 | 28 | operator fun String.unaryMinus(): String { 29 | return this.reversed() 30 | } 31 | 32 | fun main() { 33 | val shape = shape { 34 | +Point(0, 0) 35 | +Point(0, 1) 36 | } 37 | shape.getPoints() 38 | 39 | println("Hello" - 'e') 40 | 41 | println(-"Hello") 42 | } -------------------------------------------------------------------------------- /src/main/kotlin/11-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halilozcan/KotlinLastButNotLeast/7b9e81a62d108840b6612d4c733c66cd36b3a628/src/main/kotlin/11-1.jpg -------------------------------------------------------------------------------- /src/main/kotlin/11-Generics.kt: -------------------------------------------------------------------------------- 1 | package org.example 2 | 3 | open class A { 4 | //some methods & member variable 5 | } 6 | 7 | class B : A() { 8 | // some mehods & member variables 9 | } 10 | 11 | /** 12 | * Invariance; tam olarak belirlenen tipin kullanılmasıdır 13 | */ 14 | class InvarianceGenericClass { 15 | 16 | } 17 | 18 | /** 19 | * Covariance; super type yerine subtype kullanılması 20 | * Sadece out position da kullanılabilir yani fonksiyonun return type ı olarak 21 | * kullanılabilir. 22 | * val property olarak kullanılabilir, var property olarak kullanılmaz. 23 | */ 24 | class CovarianceGenericClass { 25 | 26 | } 27 | 28 | /** 29 | * Contravariance; subtype yerine supertype ın kullanılması 30 | * Sadece in position da yani parametre olarak kullanılabilir 31 | * out position olarak kullanılamaz yani val ya da var propery olarak kullanılmaz 32 | */ 33 | class ContravarianceGenericClass { 34 | 35 | } 36 | 37 | /** 38 | * Out ve in positionlarda constructorlar bu parametre olarak alma kuralına tabi 39 | * tutulmazlar. 40 | * Java nın aksine Kotlin tarafında declaration-site variance şeklinde sınıflar 41 | * yazılırken type parametreleri tanımlanabilir. Java da WildCards'a (*) ihtiyaç 42 | * bulunmaktadır. Böylece fazlasıyla boilerplate code yazılmamış olur. 43 | */ 44 | class ReadOnlyBox(private var item: T) { 45 | fun getItem(): T = item 46 | } 47 | 48 | class WriteOnlyBox(private var item: T) { 49 | fun setItem(newItem: T) { 50 | item = newItem 51 | } 52 | } 53 | 54 | fun main() { 55 | /** 56 | * B a nın alt tipidir. Bundan dolay B de anın alt tipi olduğu için üretilebilir 57 | */ 58 | val a: A = B() 59 | 60 | /** 61 | * Typelar uyuşmaz. Invariance demek bütün tam olarak verilen tipin kullanılması 62 | * demektir. 63 | */ 64 | // val invariance1: InvarianceGenericClass = InvarianceGenericClass() 65 | // val invariance2: InvarianceGenericClass = InvarianceGenericClass() 66 | 67 | /** 68 | * Sınıfın alt tipinin kullanılabilmesi için out ile işaretlenmesi gereklidir. 69 | */ 70 | val covarianceGenericClass: CovarianceGenericClass = CovarianceGenericClass() 71 | 72 | /** 73 | * Sınıfın üst tipinin kullanulabilmesi için in ile işaretlenmesi gereklidir. 74 | */ 75 | val contravarianceGenericClass: ContravarianceGenericClass = ContravarianceGenericClass() 76 | } -------------------------------------------------------------------------------- /src/main/kotlin/12-Generics.kt: -------------------------------------------------------------------------------- 1 | package org.example 2 | 3 | /** 4 | * Genericler inheritance kavramı normalden farklıdır. Örneğin X sınıfı Y sınıfının alt 5 | * sınıfı olarak düşünülürse Array, Array nin alt tipi olarak kabul edilmez. 6 | * Bu durum variance yaparak çözülür. 7 | */ 8 | 9 | /** 10 | * Type nesnelerin paylaştıkları propertyleri tanımlar. Yani derleyiciye yazılımcının 11 | * veriyi nasıl kullanmayı planladığını söyler. 12 | * 13 | * Class ise bu tipin bir implementasyonudur. 14 | */ 15 | 16 | data class Kitty(val kittyName: String) : Mammal(kittyName) { 17 | override fun eat() {} 18 | override fun sleep() {} 19 | } 20 | 21 | data class Lion(val lionName: String) : Mammal(lionName) { 22 | override fun eat() {} 23 | override fun sleep() {} 24 | } 25 | 26 | open class Mammal(val name: String) { 27 | open fun eat() {} 28 | open fun sleep() {} 29 | } 30 | 31 | /** 32 | * Burada Mammal belirtilip Kitty gönderilebilmesinin sebebi List in out ile işaretlenip 33 | * covariance sağlamasıdır. Covariance gönderilen tipin alt tipinin de gönderilmesini 34 | * sağlar. Fonksiyon parametresi ile gönderilen parametre eşleşmediklerinde kabul 35 | * kriterleri, bunların en azından tanımlanan tipin alt türü olmasıdır. 36 | */ 37 | fun feed(elements: List) { 38 | elements.forEach { 39 | it.eat() 40 | } 41 | } 42 | 43 | fun main() { 44 | val kitties = listOf(Kitty("A"), Kitty("B"), Kitty("C")) 45 | val lions = listOf(Lion("D"), Lion("E")) 46 | 47 | // Covariance 48 | feed(kitties) 49 | feed(lions) 50 | 51 | val allElements = listOf(Kitty("D"), Kitty("A"), Lion("C")) 52 | 53 | val compareNames = Comparator { o1: Mammal, o2: Mammal -> 54 | o1.name.first().code - o2.name.first().code 55 | } 56 | 57 | // Contravariance 58 | println(allElements.sortedWith(compareNames)) 59 | } -------------------------------------------------------------------------------- /src/main/kotlin/13-Generics.kt: -------------------------------------------------------------------------------- 1 | package org.example 2 | 3 | interface Device 4 | 5 | class Computer : Device 6 | class Telephone : Device 7 | 8 | fun addComputer(list: MutableList) { 9 | list.add(Computer()) 10 | } 11 | 12 | fun main() { 13 | /** 14 | * Class = Telephone 15 | * Types = Telephone, Telephone? 16 | * Subtypes = Telephone inherit eden herhangi bir şey ya da Telephone un kendisi 17 | */ 18 | 19 | /** 20 | * A -> A? 21 | * Telephone -> Telephone? 22 | * Telephone? -> Telephone // burası error verir. 23 | * 24 | * Nullable değer kabul eden bir değişken içerisinde null olmayan bir değer 25 | * tutulabilir ama tam tersi olamaz. 26 | */ 27 | val telephones = mutableListOf(Telephone(), Telephone(), Telephone()) 28 | 29 | /** 30 | * Bu eklemenin yapılamamasının sebebi MutableList in invariant olmasıdır. 31 | * Invariance sadece aynı tipi kabul eder. Burada MutableList invariant 32 | * olmasaydı bir Exception fırlatılması söz konusu olurdu. 33 | */ 34 | // addComputer(telephones) 35 | 36 | println(telephones) 37 | 38 | val computers = mutableListOf(Computer(), Computer(), Computer()) 39 | 40 | val devices = mutableListOf(Telephone(), Telephone(), Computer()) 41 | 42 | copyData(computers, devices) 43 | copyData(telephones, devices) 44 | 45 | /** 46 | * Compiler hatası verir. Çünkü Computer ve Telephone arasında bir typing yoktur 47 | */ 48 | // copyData(computers, telephones) 49 | } 50 | 51 | fun copyData(source: MutableList, destination: MutableList) { 52 | for (element in source) { 53 | destination.add(element) 54 | } 55 | } -------------------------------------------------------------------------------- /src/main/kotlin/14-Reflection.kt: -------------------------------------------------------------------------------- 1 | package org.example 2 | 3 | import java.lang.reflect.Constructor 4 | import kotlin.reflect.full.memberProperties 5 | import kotlin.reflect.jvm.isAccessible 6 | 7 | /** 8 | * Reflection yazılan kodun yapısının çalışma zamanında incelenmesine olanak 9 | * sağlayan bir yapıdır. Örneğin bir property nin tipini öğrenme, private 10 | * ise public yapma gibi işlemler yapılabilir. 11 | */ 12 | 13 | class ReflectionClass 14 | 15 | /** 16 | * Fonksiyonlara da reflection ile ulaşılabilir. Fonksiyonlar, propertyler 17 | * ve constructorlar callable referance olarak geçerler ve ortak süper 18 | * tipleri KCallable olarak geçer. 19 | * 20 | * Fonksiyon referansları KFunction nin alt tiplerinden biridir. 21 | * Bu durum parametre sayısına göre değişir. 22 | * Örneğin; KFunction3 23 | */ 24 | 25 | fun isOdd(x: Int) = x % 2 == 0 26 | 27 | class ClassWithPrivateInstructor private constructor() 28 | 29 | class ClassWithPrivateProperty { 30 | private val name: String = "Hello From Private Property" 31 | } 32 | 33 | fun createPrivateClassWithReflection(): ClassWithPrivateInstructor { 34 | return (ClassWithPrivateInstructor::class.java.declaredConstructors[0].apply { 35 | isAccessible = true 36 | } as Constructor).newInstance() 37 | } 38 | 39 | fun main() { 40 | /** 41 | * Sınıf referansını alma 42 | * Burada dönen tip KClass şeklindedir. Kotlin Class Java class 43 | * referansı ile aynı ile değil. 44 | */ 45 | val reflectionKotlin = ReflectionClass::class 46 | println(reflectionKotlin.constructors.size) 47 | println(reflectionKotlin.isOpen) 48 | 49 | /** 50 | * Kotlin Class Java class referansı ile aynı ile değildir. JVM 51 | * tarafındaki sınıfı almak için .java kullanılmalıdır. 52 | */ 53 | val reflectionJava = ReflectionClass::class.java 54 | println(reflectionJava.constructors.size) 55 | 56 | /** 57 | * Gelecek parametreler fonksiyona uyuyorsa bu şekilde reflection yaparak kullanılabilir. 58 | */ 59 | val numbers = listOf(1, 2, 3) 60 | println(numbers.filter(::isOdd)) 61 | 62 | val privateClass = createPrivateClassWithReflection() 63 | 64 | val classWithPrivateProperty = ClassWithPrivateProperty() 65 | 66 | val field = ClassWithPrivateProperty::class.memberProperties.find { 67 | it.name == "name" 68 | } 69 | 70 | field?.let { 71 | it.isAccessible = true 72 | val w = it.get(classWithPrivateProperty) 73 | println(w) 74 | } 75 | } -------------------------------------------------------------------------------- /src/main/kotlin/15-Delegation.kt: -------------------------------------------------------------------------------- 1 | package org.example 2 | 3 | /** 4 | * Delegation bir nesnenin işini başka bir nesneye aktarmaktır. Örneğin sınıf B nin 5 | * A ya verilerek A sınıfında kendisine ait bir şey çağırmasının yetkisinin verilmesine 6 | * delegation denir. 7 | */ 8 | 9 | /** 10 | * Delegation explicit ve implicit olmak üzere ikiye ayrılır. 11 | */ 12 | 13 | /** 14 | * Explicit Delegation 15 | */ 16 | 17 | interface Destroyer { 18 | fun destroy() 19 | } 20 | 21 | class SpecialRemover : Destroyer { 22 | override fun destroy() { 23 | println("SpecialRemover.destroy()") 24 | } 25 | 26 | } 27 | 28 | open class UserView { 29 | open fun show() { 30 | println("View.Show()") 31 | } 32 | } 33 | 34 | class Screen(private val view: UserView, private val destroyer: Destroyer) { 35 | fun show() { 36 | view.show() 37 | } 38 | 39 | fun destroy() { 40 | destroyer.destroy() 41 | } 42 | } 43 | 44 | class CustomView : UserView() { 45 | override fun show() { 46 | println("CustomView.show()") 47 | } 48 | } 49 | 50 | /** 51 | * Kotlin delegation ı işleminin implicit olarak yapılmasını sağlar. Class Delegation 52 | * ve Delegated Properties feature larını sunar. 53 | */ 54 | 55 | interface Nameable { 56 | var name: String 57 | } 58 | 59 | class Halil : Nameable { 60 | override var name: String = "Halil" 61 | } 62 | 63 | interface Runner { 64 | fun run() 65 | } 66 | 67 | class LongDistanceRunner : Runner { 68 | override fun run() { 69 | println("run()") 70 | } 71 | } 72 | 73 | /** 74 | * Burada by ile delegation yapılmıştır. Yani verilen nameable a direkt olarak 75 | * erişilebilir. Runnable ın içerisindeki fonksiyonu yazmadan direkt olarak 76 | * erişilebilir. 77 | */ 78 | class PersonDelegation(name: Nameable, runner: Runner) : Nameable by name, Runner by runner 79 | 80 | fun main() { 81 | /** 82 | * Screen in show işleminin View nesnesine atanması işlemi delegationdır. 83 | * Delegation işlemi aynı zamanda interfaceler aracılığıyla da yapılabilir. 84 | */ 85 | val view = UserView() 86 | val customView = CustomView() 87 | val specialRemover = SpecialRemover() 88 | val screen = Screen(customView, specialRemover) 89 | screen.show() 90 | screen.destroy() 91 | 92 | val person = PersonDelegation(Halil(), LongDistanceRunner()) 93 | println(person.name) 94 | person.run() 95 | } -------------------------------------------------------------------------------- /src/main/kotlin/16-DelegatedProperties.kt: -------------------------------------------------------------------------------- 1 | package org.example 2 | 3 | import kotlin.properties.Delegates 4 | import kotlin.properties.ReadOnlyProperty 5 | import kotlin.properties.ReadWriteProperty 6 | import kotlin.reflect.KProperty 7 | 8 | /** 9 | * Propertylerin her zaman manuel olarak implementasyonunun yapılmasının 10 | * istenmediği durumlarda delegate edilirler ve böylece sadece bir kere 11 | * tanımlanmış olurlar. Daha sonra delegation ile beraber tekrar 12 | * kullanılabilirler. 13 | */ 14 | 15 | /** 16 | * Delegation by anahtar kelimesi ile yapılır. Property den değer 17 | * alınması ve değer atanması getValue() ve setValue() fonksiyonlarına 18 | * verilir. Property delegation işleminde interface implemente etmeye 19 | * gerek yoktur ancak getValue() veya setValue() fonksiyonları tanımlanmak 20 | * zorundadır. 21 | */ 22 | 23 | /** 24 | * Eğer delegation da val kullanılırsa sadece getValue fonksiyonunu 25 | * yazmak yeterlidir ancak var ile kullanılacaksa o zaman setValue 26 | * fonksiyonu da yazılmalıdır. 27 | */ 28 | 29 | class UserDelegate 30 | 31 | fun userDelegation(userDelegate: UserDelegate = UserDelegate()): ReadWriteProperty = 32 | object : ReadWriteProperty { 33 | var currentValue = userDelegate 34 | override fun getValue(thisRef: Any?, property: KProperty<*>): UserDelegate { 35 | return currentValue 36 | } 37 | 38 | override fun setValue(thisRef: Any?, property: KProperty<*>, value: UserDelegate) { 39 | currentValue = value 40 | } 41 | } 42 | 43 | val userDelegate: UserDelegate by userDelegation() 44 | 45 | /** 46 | * Json parsing vb. işlemleri kolaylaştırmak için map delegation 47 | * kullanılabilir. 48 | * Sadece val değil var propertylerde de kullanılabilir. 49 | */ 50 | 51 | class UserMapDelegate(val map: Map) { 52 | val name: String by map 53 | val age: Int by map 54 | } 55 | 56 | /** 57 | * Bir property başka bir proterty e delegate edilebilir. 58 | * Aşağıdaki örnekte deprecated property i silmeden eski sürümleri de 59 | * destekleyerek geliştirme ve notify etme amacıyla kullanım vardır. 60 | */ 61 | 62 | class DelegateAnotherProperty { 63 | var privacyPermission: String = "" 64 | 65 | @Deprecated("Use new name instead", ReplaceWith("privacyPermission")) 66 | var permission: String by this::privacyPermission 67 | } 68 | 69 | /** 70 | * Delegation sınıf oluşturarak fonksiyonlarla tanımlanabildiği gibi 71 | * anonymous object ile de tanımlama yapılabilir. Bu fonksiyonlar 72 | * extension ve operator fonksiyon olarak tanımlanabilir 73 | */ 74 | 75 | /** 76 | * Primitive bir tipin tanımlaması yapılırken ilk değer atanması 77 | * yapılmak istenmediği zaman lateinit kullanılamaz. Bundan dolayı 78 | * bu tip genellikle nullable hale getirilir. Daha sonra her yerde 79 | * null safety ile kontrol yapılmaya çalışılır. Bunu yapmak yerine 80 | * notNull() delegation ı kullanılabilir 81 | */ 82 | 83 | var notNull: Int by Delegates.notNull() 84 | 85 | class BaseView 86 | 87 | interface ViewBinding 88 | 89 | abstract class Lifecycle { 90 | abstract fun addObserver(lifecycleObserver: LifecycleObserver) 91 | } 92 | 93 | interface LifecycleOwner { 94 | 95 | val lifecycle: Lifecycle 96 | 97 | fun isViewCreated(): Boolean = true 98 | } 99 | 100 | interface LifecycleObserver { 101 | fun onDestroy(owner: LifecycleOwner) {} 102 | } 103 | 104 | class LifecycleRegister : Lifecycle() { 105 | override fun addObserver(lifecycleObserver: LifecycleObserver) { 106 | // add lifecycle observer 107 | } 108 | } 109 | 110 | open class BaseSampleFragment : LifecycleOwner { 111 | 112 | private var lifecycleOwner: LifecycleOwner? = null 113 | fun onViewCreated() { 114 | lifecycleOwner = this 115 | } 116 | 117 | fun getLifecycleOwner(): LifecycleOwner = lifecycleOwner!! 118 | 119 | fun requireView(): BaseView = BaseView() 120 | override val lifecycle: Lifecycle 121 | get() = LifecycleRegister() 122 | } 123 | 124 | class SampleFragment : BaseSampleFragment() { 125 | val binding: HomeScreenBinding by viewBinding(HomeScreenBinding::bind) 126 | } 127 | 128 | class HomeScreenBinding : ViewBinding { 129 | 130 | companion object { 131 | fun bind(view: BaseView): HomeScreenBinding { 132 | return HomeScreenBinding() 133 | } 134 | } 135 | } 136 | 137 | fun BaseSampleFragment.viewBinding(factory: (BaseView) -> T): ReadOnlyProperty = 138 | object : ReadOnlyProperty, LifecycleObserver { 139 | 140 | private var binding: T? = null 141 | 142 | override operator fun getValue(thisRef: BaseSampleFragment, property: KProperty<*>): T { 143 | binding ?: factory(requireView()).also { 144 | if (getLifecycleOwner().isViewCreated()) { 145 | getLifecycleOwner().lifecycle.addObserver(this) 146 | binding = it 147 | } 148 | } 149 | return binding!! 150 | } 151 | 152 | override fun onDestroy(owner: LifecycleOwner) { 153 | binding = null 154 | } 155 | } 156 | 157 | fun main() { 158 | val userMapDelegate = UserMapDelegate(mapOf("name" to "Halil", "age" to 25)) 159 | 160 | println(userMapDelegate.name) 161 | println(userMapDelegate.age) 162 | 163 | val delegateAnotherProperty = DelegateAnotherProperty() 164 | 165 | delegateAnotherProperty.permission = "Camera" 166 | println(delegateAnotherProperty.privacyPermission) 167 | 168 | // notNull initialize edilmediği için hata fırlatılır 169 | // println(notNull) 170 | notNull = 14 171 | println(notNull) 172 | } 173 | -------------------------------------------------------------------------------- /src/main/kotlin/17-FunctionalProgramming.kt: -------------------------------------------------------------------------------- 1 | package org.example 2 | 3 | data class Salary(val value: Double, val currency: String = "$") 4 | 5 | data class Worker(val id: String, val name: String, val salary: Salary, val weight: Double) 6 | 7 | val workers = listOf( 8 | Worker("1", "Halil", Salary(4000.00, "£"), 105.1), 9 | Worker("2", "Metehan", Salary(3000.00, "£"), 60.8) 10 | ) 11 | 12 | fun workerWeight(worker: Worker) = worker.weight 13 | 14 | fun workerSalary(worker: Worker) = worker.salary.value 15 | 16 | val workerWeightFun = fun(worker: Worker) = worker.weight 17 | val workerSalaryFun = fun(worker: Worker) = worker.salary.value 18 | 19 | fun main() { 20 | var workerFun = workerWeightFun 21 | println("Worker weight: ${workerFun(workers[0])} Kg") 22 | 23 | workerFun = workerSalaryFun 24 | println("Worker salary: ${workerFun(workers[0])} £") 25 | } -------------------------------------------------------------------------------- /src/main/kotlin/18-FunctionalProgramming.kt: -------------------------------------------------------------------------------- 1 | package org.example 2 | 3 | typealias WorkerMapper = (Worker) -> T 4 | 5 | fun List.total(fn: WorkerMapper): Double = 6 | fold(0.0) { total, worker -> total + fn(worker) } 7 | 8 | fun main() { 9 | var mapper: WorkerMapper = ::workerWeight 10 | 11 | println("Weight of ${workers[0].name} is ${mapper(workers[0])} Kg") 12 | 13 | mapper = ::workerSalary 14 | 15 | val currency: WorkerMapper = { worker -> worker.salary.currency } 16 | println("Price of ${workers[0].name} is ${mapper(workers[0])}${currency(workers[0])}") 17 | 18 | 19 | val totalPrice = workers.total { it.salary.value } 20 | println("Total Price: $totalPrice £") 21 | 22 | val totalWeight = workers.total { it.weight } 23 | println("Total Weight: $totalWeight Kg") 24 | } -------------------------------------------------------------------------------- /src/main/kotlin/19-FunctionalProgramming.kt: -------------------------------------------------------------------------------- 1 | package org.example 2 | 3 | typealias Func = (A) -> B 4 | 5 | val getSalary: Func = { worker -> worker.salary } 6 | 7 | val formatSalary: Func = 8 | fun(salaryData: Salary) = "value: ${salaryData.value}${salaryData.currency}" 9 | 10 | infix fun Func.after(f: Func): Func = { x: A -> this(f(x)) } 11 | 12 | fun main() { 13 | // Composition olmadan 14 | val result: String = formatSalary(getSalary(workers[0])) 15 | println(result) 16 | 17 | // Composite edilmiş sonuç 18 | val compositeResult: String = (formatSalary after getSalary)(workers[0]) 19 | println(compositeResult) 20 | } -------------------------------------------------------------------------------- /src/main/kotlin/2-Loops.kt: -------------------------------------------------------------------------------- 1 | package org.example 2 | 3 | fun main() { 4 | /** 5 | * Dışarıdaki döngüyü bitirir. 6 | */ 7 | outerLoop@ for (i in 1..10) { 8 | innerLoop@ for (j in 1..10) { 9 | if (i == 5) { 10 | break@outerLoop 11 | } 12 | println("i:$i j:$j") 13 | } 14 | } 15 | 16 | /** 17 | * Lambda fonksiyonunun o adımı atlaması için kullanılır. 18 | */ 19 | intArrayOf(1, 2, 3, 4, 5).forEach lambda@{ 20 | if (it == 3) return@lambda 21 | println(it) 22 | } 23 | 24 | /** 25 | * Direkt run a dönüş için kullanılır 26 | */ 27 | run loop@{ 28 | intArrayOf(1, 2, 3, 4, 5).forEach { 29 | if (it == 3) return@loop 30 | println(it) 31 | } 32 | } 33 | 34 | println("Hello I'm working..") 35 | } -------------------------------------------------------------------------------- /src/main/kotlin/20-FunctionalProgramming.kt: -------------------------------------------------------------------------------- 1 | package org.example 2 | 3 | class Logger { 4 | var log = StringBuilder() 5 | fun log(str: String) { 6 | log = log.append(str).append("\n") 7 | } 8 | } 9 | 10 | val logger = Logger() 11 | 12 | val getSalaryWithLog: Func = { 13 | logger.log("Salary calculated for ${it.id}") 14 | it.salary 15 | } 16 | 17 | val formatSalaryWithLog: Func = { 18 | logger.log("Bill line created") 19 | "value: ${it.value} ${it.currency}" 20 | } 21 | 22 | fun main() { 23 | // Condition race ile 24 | formatSalaryWithLog(getSalaryWithLog(workers[0])) 25 | println(logger.log) 26 | } -------------------------------------------------------------------------------- /src/main/kotlin/21-FunctionalProgramming.kt: -------------------------------------------------------------------------------- 1 | package org.example 2 | 3 | typealias Writer = (T) -> Pair 4 | 5 | val fpGetSalary: Writer = 6 | fun(worker: Worker) = getSalary(worker) to "Price calculated for ${worker.id}" 7 | 8 | val fpFormatSalary: Writer = 9 | fun(salary: Salary) = formatSalary(salary) to "Bill line created for ${formatSalary(salary)}" 10 | 11 | infix fun Writer.compose(f: Writer): Writer = { x: A -> 12 | val p1 = this(x) 13 | val p2 = f(p1.first) 14 | p2.first to p1.second + "\n" + p2.second 15 | } 16 | 17 | fun main() { 18 | // Condition race olmadan 19 | val getPriceWithLog = fpGetSalary compose fpFormatSalary 20 | workers.forEach { worker -> 21 | println(getPriceWithLog(worker).second) 22 | } 23 | } -------------------------------------------------------------------------------- /src/main/kotlin/3-Functions.kt: -------------------------------------------------------------------------------- 1 | package org.example 2 | 3 | /** 4 | * Bazen sınıf içerisindeki bazı methodlar birbiriyle alakasız olabilirler. Bundan dolayı birbiriyle alakalı 5 | * işlemleri bir arada tanımlayabilmek için fonksiyon içerisinde fonksiyon tanımlanması yapılabilir. Local 6 | * fonksiyonlar kendileri çağırılmadan önce tanımlanmalıdır. Ayrıca local fonksiyonlar bir üst methodun 7 | * değişkenlerine erişebilir. Bu değişkenler referans tipli değişkenlere dönüşür ve alt method 8 | * içerisinden erişilebilir. 9 | */ 10 | fun login(userName: String, password: String): Boolean { 11 | fun validateInput(input: String) { 12 | if (input.isEmpty()) { 13 | throw Exception("Input can not be empty") 14 | } 15 | } 16 | 17 | validateInput(userName) 18 | validateInput(password) 19 | return true 20 | } 21 | 22 | /** 23 | * infix fonksiyonlar her zaman receiver a ve parametrenin belirtilmesine ihtiyacı vardır. güncel receiver içerisinde 24 | * çağırılırken this kullanılmalı veya parantezli fonksiyon çağırımı yapılmalıdır. 25 | */ 26 | class Operation { 27 | infix fun add(a: Int) {} 28 | 29 | fun buildAddOperation() { 30 | this add 5 31 | add(5) 32 | // add 5 bu yanlıştır 33 | } 34 | } 35 | 36 | /** 37 | * 38 | * (A,B)-> C 39 | * A -> Parametre Tipi 40 | * B -> Parametre Tipi 41 | * C -> Return Tipi 42 | * 43 | * () -> A - parametresi yok A tipinde dönüşü var 44 | * 45 | * A.(B) -> C -> A tipi üzerinden B parametreli fonksiyon çağrımı var ve return tipi 46 | * C demektir. 47 | * 48 | * nullable fonksiyon tanımlamak için ((Int,Int)->Int)? 49 | */ 50 | 51 | /** 52 | * Lambda expressionlar değer olarak döndürebilir. 53 | */ 54 | fun returnLambda(): () -> String { 55 | val lambda = { "Hi" } 56 | return lambda 57 | } 58 | 59 | fun main() { 60 | login("Hello", "1234") 61 | 62 | /** 63 | * Lambda expressionlar fonksiyonun return type ını belirtemezler. return type açık 64 | * olarak belirtmek için anonymous fonksiyonlar kullanılır. anonymous fonksiyonlar 65 | * isimsiz olarak yazılan fonksiyonlardır. bir body olarak veya single expression 66 | * olarak yazılabilir. return type aynı zamanda infer edilebilir. yani belirtmeye de 67 | * gerek yoktur 68 | */ 69 | 70 | val names = arrayOf("Halil", "Metehan", "İbrahim", "Hilal") 71 | 72 | val filterFunction = fun(a: String): Boolean = a.length > 5 73 | 74 | names.filter(filterFunction) 75 | } -------------------------------------------------------------------------------- /src/main/kotlin/4-InlineFunctions.kt: -------------------------------------------------------------------------------- 1 | package org.example 2 | 3 | val publicMember = "Public" 4 | 5 | @PublishedApi 6 | internal val internalMember = "I am internal" 7 | 8 | fun main() { 9 | callingFunction() 10 | } 11 | 12 | fun callingFunction() { 13 | println("started") 14 | /** 15 | * Kotlin byte code a çevrildiğinde nesne üretilir. Bunu döngüde kullandığımız zaman 16 | * her bir çağırımda nesne üretilir. inline eklenmesi bunu engeller. ve fonksiyonun 17 | * direkt olarak içeriğinin kendisini çağıran tarafa kopyalanmasını sağlar. 18 | */ 19 | higherOrderFunction { 20 | println("lambda") 21 | /** 22 | * inline fonksiyonlar lokal olarak return çağırarak calling site dan return 23 | * yapabilir. 24 | */ 25 | // Sadece bu fonksiyondan dönülmesini istiyorsak return@higherOrderFunction 26 | return 27 | } 28 | 29 | higherOrderFunctionNoInlined(lambda = { 30 | return 31 | }, noInlinedLambda = { 32 | // no inlined return e izin vermez 33 | // return 34 | }) 35 | 36 | higherOrderFunctionCrossInline { 37 | // non-local return e izin vermez. 38 | //return 39 | } 40 | 41 | println("finished") 42 | } 43 | 44 | inline fun higherOrderFunction(lambda: () -> Unit) { 45 | /** 46 | * inline fonksiyonlar kendisini çevreleyen sınıf veya scope daki 47 | * private değişkenlere ve methodlara etişim sağlayamaz. Erişmek için bunların public 48 | * veya internal olması, internal olanların @PublishedApi ile işaretlenmesi gerekir 49 | */ 50 | //privateMemberVariable.length 51 | publicMember.length 52 | internalMember.length 53 | doSomething() 54 | lambda() 55 | doAnotherThing() 56 | } 57 | 58 | /** 59 | * Bazen bazı lambda expressionları inlined olmasını istemeyebilirsiniz. Eğer bunun 60 | * inlined olmasını istemiyorsanız noinline ile işaretleyebilirsiniz. noinline 61 | * fonksiyonlar local return lere izin vermez 62 | */ 63 | inline fun higherOrderFunctionNoInlined(lambda: () -> Unit, noinline noInlinedLambda: () -> Unit) { 64 | doSomething() 65 | noInlinedLambda() 66 | doAnotherThing() 67 | } 68 | 69 | /** 70 | * Local returne izin verilmesini istemediğimiz durumlar için crossinline ile 71 | * fonksiyonları işaretleriz. 72 | */ 73 | 74 | inline fun higherOrderFunctionCrossInline(crossinline lambda: () -> Unit) { 75 | /** 76 | * Inline bir fonksiyon içerisinde inline olmayan bir fonksiyona 77 | * higher order çağırılırsa return e izin vermemek için lambda() fonksiyonu 78 | * crossinline olarak işaretlenir. 79 | */ 80 | normalFunction { 81 | lambda() 82 | // return 83 | } 84 | } 85 | 86 | fun doSomething() { 87 | println("do something()") 88 | } 89 | 90 | fun doAnotherThing() { 91 | println("do another thing()") 92 | } 93 | 94 | fun normalFunction(lambda: () -> Unit) { 95 | println("normal function started") 96 | lambda() 97 | println("normal function ended") 98 | return 99 | } -------------------------------------------------------------------------------- /src/main/kotlin/5-Properties.kt: -------------------------------------------------------------------------------- 1 | package org.example 2 | 3 | /** 4 | * val ile tanımlama yapıldığı zaman sadece getter ı oluşturulur 5 | * var ile tanımlama yapıldğı zaman getter ve setter ı oluşturur. kendi içerisinde 6 | * encapsulation yapılır. 7 | */ 8 | 9 | class Person(val name: String, var lastName: String, val born: Int) { 10 | 11 | /** 12 | * Burada böyle bir tanımlama compile olmadan hata vermez. Getter ve setter 13 | * fonksiyonlar val ve var durumuna göre oluştuğu için get ve set isimli 14 | * fonksiyonlar tanımlanamaz 15 | */ 16 | // fun getName() = name 17 | 18 | /** 19 | * Custom bir şekilde getter oluşturabilirsiniz. Property e her eriştiniz 20 | * durumda getter fonksiyonu çağırılır. Bu durumda bir field üretilmez ve 21 | * memory de yer almaz. 22 | */ 23 | val fullName: String get() = "$name $lastName" 24 | 25 | var info 26 | get() = "$name $lastName $born" 27 | set(value) { 28 | 29 | } 30 | 31 | /** 32 | * Eğer bir property nin değerinin dışarıdan okunup ama dışarıdan 33 | * değiştirilmesini istemiyorsanız private setter kullanabilirsiniz. 34 | */ 35 | var gender: String = "" 36 | private set 37 | 38 | fun setGenderInternally(gender: String) { 39 | this.gender = gender 40 | } 41 | 42 | /** 43 | * Fieldlar bir sınıfın private memberlarıdır. Memory i kullanırlar 44 | * Propertyler private fieldlara erişmeye izin veren getter ve setter 45 | * fonksiyonlarıdır. Aslında her şey bir propertydir. 46 | */ 47 | 48 | var height = 0 49 | set(value) { 50 | if (value >= 0) { 51 | // arkaplandaki fieldı şartlı olarak değiştiriyoruz. 52 | field = value 53 | // counter = value ifadesine izin verilmez. recursive atama olur. 54 | } 55 | } 56 | 57 | /** 58 | * Backing property kullanımında arkaplanda grades değil sadece _grades 59 | * üretilir. grades e ulaşım sağlandığı zaman bir getter fonksiyonu oluşturulur. 60 | * ve _grades döndürülür 61 | */ 62 | private var _grades: IntArray? = null 63 | val grades: IntArray 64 | get() { 65 | if (_grades == null) { 66 | _grades = intArrayOf() 67 | } 68 | return _grades ?: throw Exception("failed") 69 | } 70 | } 71 | 72 | /** 73 | * Equals hashcode gibi methodlar sadece primary constructora bakarlar 74 | * Bu yüzden aynı isimle üretilen iki nesne farklı yaşlara sahip olsa da 75 | * equals kontrolü true olarak döner. 76 | */ 77 | data class Equality(val name: String) { 78 | var age: Int = 0 79 | } -------------------------------------------------------------------------------- /src/main/kotlin/6-Scope Functions.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/halilozcan/KotlinLastButNotLeast/7b9e81a62d108840b6612d4c733c66cd36b3a628/src/main/kotlin/6-Scope Functions.webp -------------------------------------------------------------------------------- /src/main/kotlin/6-ScopeFunctions.kt: -------------------------------------------------------------------------------- 1 | package org.example 2 | 3 | /** 4 | * Scope fonksiyonlarda objelerin isimleri lambda expression ın receiver veya argument 5 | * olmasına göre değişir. eğer receiver ise (this) argument ise it olarak 6 | * adlandırılırlar 7 | */ 8 | 9 | private var globalName: String? = "Hello" 10 | 11 | var height = 180 12 | 13 | fun main() { 14 | 15 | val person: Person? = Person("", "", 1990) 16 | /** 17 | * let 18 | * nesne it olarak adlandırılır. dönüş değeri lambdanın sonucudur. 19 | */ 20 | 21 | /** 22 | * Chaining call yapılan ve sonucun bir değere atanmadığı durumlarda 23 | * let kullanılabilir. 24 | */ 25 | 26 | val numbers = mutableListOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) 27 | 28 | numbers.map { it / 2 }.filter { it > 3 }.let { 29 | println(it) 30 | } 31 | 32 | /** 33 | * Eğer let den sonra it yi kullanan tek bir fonksiyon kullanılacaksa 34 | * method referansı (::) kullanarak çağırım yapılabilir. 35 | */ 36 | 37 | numbers.map { it / 2 }.filter { it > 3 }.let(::println) 38 | 39 | doSomethingWithPersonLet(person) 40 | 41 | parseNameLet("Halil") 42 | 43 | parseNameGloballyLet() 44 | 45 | /** 46 | * with 47 | * nesneye this olarak erişilir. return değeri lambdanın sonucudur 48 | * with extension fonksiyon olmadığı için nesne parametre olarak verilir. 49 | */ 50 | 51 | /** 52 | * ilk kullanımı dönen sonuca ihtiyaç olmayan durumlar içindir. 53 | * with this object, do the following." 54 | */ 55 | 56 | with(numbers) { 57 | println("Size is ${this.size}") 58 | } 59 | 60 | /** 61 | * bir nesnenin değerleri bir sonuç hesaplamak için gerektiğinde kullanılır 62 | */ 63 | 64 | val firstAndLastSum = with(numbers) { 65 | first() + last() 66 | } 67 | 68 | /** 69 | * run 70 | * nesneye this kullanılarak erişilir. dönüş değeri lambdanın sonucudur 71 | */ 72 | 73 | /** 74 | * run with ile aynı işlemi yapar ancak extension fonksiyon olarak implemente 75 | * edilmiştir. 76 | */ 77 | 78 | val fullName: String? = run { 79 | person?.name?.plus(person.lastName)?.capitalize() 80 | } 81 | 82 | /** 83 | * run aynı zamanda extension fonksiyon olmadan da kullanılır. Bu durumda 84 | * nesne olmaz. dönüş değeri lambda nın sonucudur. 85 | */ 86 | 87 | val result = fullName ?: run { 88 | println("Name is null") 89 | throw Exception("Hello Mother Fucker") 90 | } 91 | 92 | /** 93 | * run aynı anda hem nesneyi initialize etmek hem de bu işlemle bir dönüş 94 | * değeri hesaplamak için kullanılır. 95 | */ 96 | 97 | getPersonInfoRun(person, 180) 98 | 99 | /** 100 | * apply 101 | * nesneye this kullanılarak ulaşılır. dönüş değeri nesnenin kendisidir. 102 | */ 103 | 104 | /** 105 | * Sonuç döndürmeyen ve genellikle nesnenin memberları üzerinde işlem yapılan 106 | * durumlar için kullanılır. "apply the following assignments to the object." 107 | */ 108 | val newPerson = Person("", "", 1990).apply { 109 | height = 183 110 | } 111 | 112 | /** 113 | * also 114 | * nesneye it kullanılarak ulaşılır. dönüş değeri nesnenin kendisidir. 115 | */ 116 | 117 | /** 118 | * also nesnenin property lerine veya fonksiyonlara erişmekten çok nesnenin 119 | * kendisi üzerinde yapılan aksiyonlar ve diğer context deki this shadowunu 120 | * engellemek için kullanılabilir. 121 | * "and also do the following with the object." 122 | */ 123 | 124 | numbers.also { 125 | println("before filtering the size of numbers:${it.size}") 126 | }.filter { 127 | it > 3 128 | } 129 | } 130 | 131 | // it ve this ile karışıklığı engellemek için kullanılabilir. 132 | fun doSomethingWithPersonLet(person: Person?) { 133 | person?.let { 134 | height = it.height 135 | } 136 | } 137 | 138 | fun parseNameLet(name: String?) { 139 | name?.let { 140 | // Do something with str 141 | } 142 | } 143 | 144 | fun parseNameGloballyLet() { 145 | if (globalName != null) { 146 | // Smart case yapılmaz - globalName.length 147 | } 148 | 149 | globalName?.let { 150 | 151 | } 152 | } 153 | 154 | fun getPersonInfoRun(person: Person?, height: Int) { 155 | val result = person?.run { 156 | this.height = height 157 | "$name $gender $height" 158 | } 159 | } 160 | 161 | -------------------------------------------------------------------------------- /src/main/kotlin/7-Exceptions.kt: -------------------------------------------------------------------------------- 1 | package org.example 2 | 3 | /** 4 | * Kotlin de Java da bulunan checked exceptions yoktur 5 | * Appendable append(CharSequence csq) throws IOException; 6 | * yani bir method tanımlaması yaparken bunun aynı zamanda exception 7 | * fırlatacağını belirtemezsiniz. 8 | */ 9 | 10 | /** 11 | * Nothing değer döndürülmeyen ve değerin asla olmadığını belirtmek için 12 | * kullanılan bir sınıftır. Bir exception fırlatılması ifadesinin sonucu 13 | * Nothing dir. Bu tip hiç bir zaman erişilmeyecek code konumlarını işaretlemek 14 | * için kullanılır. Nothing final bir classtır. Constructor ı private dır. 15 | * Genellikle sadece exception fırlatan methodlar için kullanılır. 16 | * Üst sınıf Any dir. 17 | */ 18 | 19 | fun main() { 20 | val name: String? = null 21 | 22 | val length = name?.length ?: error("name can not be null") 23 | println(length) 24 | } 25 | 26 | fun error(message: String): Nothing { 27 | throw Exception(message) 28 | } 29 | 30 | class MathOperation(private var number1: Int, private var number2: Int, private var number3: Int) { 31 | private fun minusTwoInteger(number1: Int, number2: Int): Int { 32 | return number1 - number2 33 | } 34 | 35 | /** 36 | * Java tarafından kotlin kodu çağırılırken hangi exception ın handle edilmesi 37 | * gerektiğini belirtmek için böyle bir annotation kullanılması gereklidir. 38 | * Yoksa compiler hata verir. 39 | */ 40 | @Throws(ArithmeticException::class) 41 | fun doOperation() { 42 | number1 / minusTwoInteger(number2, number3) 43 | } 44 | } -------------------------------------------------------------------------------- /src/main/kotlin/8-AbstractClasses.kt: -------------------------------------------------------------------------------- 1 | package org.example 2 | 3 | abstract class Employee(val name: String, val experience: Int, open val dateOfBirth: Int) { 4 | 5 | abstract var salary: Double 6 | 7 | abstract fun dateOfBirth(): String 8 | 9 | fun printDetails() { 10 | println("Name:$name") 11 | println("Experience:$experience") 12 | println("Date of birth:${dateOfBirth()}") 13 | } 14 | } 15 | 16 | class SoftwareEngineer(name: String, experience: Int, override val dateOfBirth: Int) : 17 | Employee(name, experience, dateOfBirth) { 18 | override var salary: Double = 50000.00 19 | 20 | 21 | override fun dateOfBirth(): String { 22 | return "Birth date is:$dateOfBirth" 23 | } 24 | } 25 | 26 | /** 27 | * Abstract classlar interfacelerin bütün implementasyonlarının override edilmesini 28 | * işlemini kendilerine alarak kod fazlalığını engeller 29 | */ 30 | interface AnimationListener { 31 | fun onStart() 32 | fun onResume() 33 | fun onDestroy() 34 | } 35 | 36 | abstract class AnimationContract : AnimationListener { 37 | override fun onStart() {} 38 | override fun onResume() {} 39 | override fun onDestroy() {} 40 | } 41 | 42 | fun main() { 43 | val softwareEngineer = SoftwareEngineer("Halil", 6, 1994) 44 | softwareEngineer.printDetails() 45 | 46 | val animationContract = object : AnimationContract() { 47 | override fun onStart() { 48 | super.onStart() 49 | } 50 | } 51 | } 52 | 53 | abstract class Fragment { 54 | abstract fun onCreateView(): View 55 | abstract fun onViewCreated() 56 | abstract fun onCreate() 57 | } 58 | 59 | abstract class BaseFragment : Fragment() { 60 | 61 | abstract fun initArguments() 62 | abstract fun layoutResId(): Int 63 | abstract fun observeUi() 64 | 65 | override fun onCreate() { 66 | initArguments() 67 | } 68 | 69 | override fun onCreateView(): View { 70 | return View(layoutResId()) 71 | } 72 | 73 | override fun onViewCreated() { 74 | observeUi() 75 | } 76 | } 77 | 78 | class View(layoutResId: Int) 79 | 80 | class HomeFragment : BaseFragment() { 81 | override fun initArguments() {} 82 | override fun layoutResId() = 15 83 | override fun observeUi() {} 84 | } -------------------------------------------------------------------------------- /src/main/kotlin/9-InlineValueClasses.kt: -------------------------------------------------------------------------------- 1 | package org.example 2 | 3 | /** 4 | * Bazı durumlarda primitive typeları wrap edip bir sınıfın içerisine gömmek gerekir. 5 | * Bu durumlarda runtime performance fazlasıyla azalır. Bunun nedeni primitive 6 | * tiplerin ağır bir şekilde runtime tarafından optimize edilmesidir. 7 | * 8 | * Bu durumdan kurtulmamıza sağlayan içerisine nesne konulsa bile primitive tip olarak 9 | * davranmasını compiler a söyleyen yapı value (inline) classlardır. Inline class lar 10 | * value anahtar kelimesi ile tanımlanır. 11 | */ 12 | 13 | /** 14 | * JVM de desteklenmesi için başına @JvmInline annotation ı konur. 15 | */ 16 | @JvmInline 17 | value class UserRequest(private val loginId: String) : Logging { 18 | init { 19 | require(loginId.isNotEmpty()) { 20 | throw Exception("login id can not be empty") 21 | } 22 | } 23 | 24 | /** 25 | * Kotlin 1.9.0 ile birlikte inline value sınıflar body e sahip olabilirler. 26 | */ 27 | constructor(firstName: String, lastName: String) : this("$firstName$lastName") { 28 | require(firstName.isNotEmpty()) { 29 | throw Exception("first name can not be empty") 30 | } 31 | 32 | require(lastName.isNotEmpty()) { 33 | throw Exception("last name can not be empty") 34 | } 35 | } 36 | 37 | override fun logId(): String { 38 | return loginId 39 | } 40 | } 41 | 42 | interface Logging { 43 | fun logId(): String 44 | } 45 | 46 | /** 47 | * Inline classların sadece bir property si bulunabilir. 48 | */ 49 | 50 | fun asInline(f: UserRequest) {} 51 | fun asGeneric(x: T) {} 52 | fun asInterface(i: Logging) {} 53 | fun asNullable(i: UserRequest?) {} 54 | 55 | fun id(x: T): T = x 56 | 57 | /** 58 | * Aşağıdaki fonksiyonların ikisi de JVM tarafında string olarak alacağı gözüktüğü 59 | * için JVM tarafında fonksiyon public final void logUserId-(String id) 60 | * olarak gözükür 61 | */ 62 | 63 | fun logUserId(id: String) { 64 | 65 | } 66 | 67 | /** 68 | * Java tarafından çağırılacağı zaman ismini değiştirmek için JVM name annotation ı 69 | * kullanılır 70 | */ 71 | @JvmName("logUserRequest") 72 | fun logUserId(id: UserRequest) { 73 | 74 | } 75 | 76 | fun main() { 77 | /** 78 | * Bu ifade runtime da sadece String olarak gösterilir. 79 | */ 80 | val userRequest = UserRequest("1234#asda") 81 | 82 | asInline(userRequest) // String 83 | asGeneric(userRequest) // userRequest 84 | asInterface(userRequest) // userRequest 85 | asNullable(userRequest) // String? 86 | 87 | /** 88 | * User Request ilk başta UserRequest olarak gitse de kendisini 89 | * döndüğü için geriye String olarak döner. 90 | */ 91 | val c = id(userRequest) 92 | } 93 | 94 | --------------------------------------------------------------------------------