├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── strings.xml
│ │ │ │ ├── colors.xml
│ │ │ │ └── themes.xml
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── ic_launcher.xml
│ │ │ │ └── ic_launcher_round.xml
│ │ │ ├── values-night
│ │ │ │ └── themes.xml
│ │ │ ├── drawable-v24
│ │ │ │ └── ic_launcher_foreground.xml
│ │ │ └── drawable
│ │ │ │ └── ic_launcher_background.xml
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── smarttoolfactory
│ │ │ └── kotlintutorials
│ │ │ └── ExampleUnitTest.kt
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── smarttoolfactory
│ │ └── kotlintutorials
│ │ └── ExampleInstrumentedTest.kt
├── proguard-rules.pro
└── build.gradle
├── tutorial
├── .gitignore
├── src
│ └── main
│ │ └── java
│ │ └── com
│ │ └── smarttoolfactory
│ │ └── tutorial
│ │ ├── chapter3Other
│ │ ├── Tutorial3_6Annotation.kt
│ │ ├── Tutorial3_7Reflection.kt
│ │ ├── Tutorial3_2TypeChecks.kt
│ │ ├── Tutorial3_1Destructuring.kt
│ │ ├── Tutorial3_5Exceptions.kt
│ │ ├── Tutorial3_3Equality.kt
│ │ ├── Tutorial3_4NullSafety.kt
│ │ └── Tutorial3_8FunctionLiteralsWithReceiver.kt
│ │ ├── chapter7Threading
│ │ ├── Tutorial7_4CountdownLatch.kt
│ │ ├── Tutorial7_1Thread.kt
│ │ ├── Tutorial7_2Synchronized.kt
│ │ ├── ReentrantLock.kt
│ │ └── Tutorial7_3SynchronizedBlock.kt
│ │ ├── chapter2OOP
│ │ ├── Tutorial2_10Generics.kt
│ │ ├── mvp
│ │ │ ├── BaseContract.kt
│ │ │ ├── UserFragmentMain.kt
│ │ │ ├── UserContract.kt
│ │ │ ├── BaseComponents.kt
│ │ │ └── user
│ │ │ │ └── UserFragment.kt
│ │ ├── Tutorial2_7VisibilityModifiers.kt
│ │ ├── Tutorial2_14DelegationComposeRememberMutableState.kt
│ │ ├── Tutorial2_1Constructors.kt
│ │ ├── Tutorial2_11Enums.kt
│ │ ├── Tutorial2_4Inheritance2.kt
│ │ ├── Tutorial2_14Delegation3StandartDelegation.kt
│ │ ├── Tutorial2_14Delegation.kt
│ │ ├── Tutorial2_6Interfaces.kt
│ │ ├── Tutorial2_4Inheritance.kt
│ │ ├── Tutorial2_8Extensions.kt
│ │ ├── Tutorial2_15Singleton.kt
│ │ ├── model
│ │ │ ├── InheritanceModels2.kt
│ │ │ ├── InheritanceModels.kt
│ │ │ └── ConstructorModels.kt
│ │ ├── Tutorial2_14Delegation2.kt
│ │ ├── Tutorial2_2NestedClasses.kt
│ │ ├── Tutorial2_5Properties.kt
│ │ ├── Tutorial2_3OtherClasses.kt
│ │ ├── Tutorial2_9DataClasses2Inheritance.kt
│ │ └── Tutorial2_9DataClasses.kt
│ │ ├── chapter6Advanced
│ │ ├── Generics3Methods.kt
│ │ ├── OperatorOverloading.kt
│ │ ├── ReferencesAndObjects.kt
│ │ ├── HashCodeEqualsHashMap.kt
│ │ ├── LambdaWithReceiver.kt
│ │ ├── Reified.kt
│ │ ├── RegularExpressions.kt
│ │ ├── DSLWithLambda2.kt
│ │ ├── DSLWithLambda.kt
│ │ ├── Generics2PECS.kt
│ │ ├── Generics.kt
│ │ └── DelegatedProperty.kt
│ │ ├── MySingleton.kt
│ │ ├── chapter1Basics
│ │ ├── Tutorial1_4Ranges.kt
│ │ ├── Tutorial1_1Basics.kt
│ │ ├── Tutorial1_3Collections2Set.kt
│ │ ├── Tutorial1_3Collections3Map.kt
│ │ ├── Tutorial1_6Function1.kt
│ │ ├── Tutorial1_5ControlFlow.kt
│ │ ├── Tutorial1_2Arrays.kt
│ │ └── Tutorial1_6Function2.kt
│ │ ├── chapter8fileIO
│ │ └── Test.java
│ │ ├── Animal.java
│ │ ├── RegularExpressionTest.java
│ │ ├── chapter4Functions
│ │ ├── Tutorial4_4InlineFunctions.kt
│ │ ├── Tutorial4_1HigOrderFunctions.kt
│ │ ├── Tutorial4_3LambdaExpressions.kt
│ │ └── Tutorial4_2FunctionTypes.kt
│ │ ├── EqualityAndHashCode.java
│ │ ├── TestStringConcatenation.java
│ │ └── chapter5Coroutines
│ │ └── Tutorial5_5Flow3.kt
└── build.gradle
├── .gitignore
├── settings.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .idea
├── misc.xml
├── vcs.xml
├── gradle.xml
└── modules.xml
├── README.md
├── local.properties
├── gradle.properties
└── gradlew.bat
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/tutorial/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | *.len
3 | .idea/*
4 | */.idea/*
5 | /build/
6 | /.gradle/vcs-1/
7 | /.gradle/
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = "Kotlin Tutorials"
2 | include ':app'
3 | include ':tutorial'
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Kotlin Tutorials
3 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartToolFactory/Kotlin-Tutorials/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter3Other/Tutorial3_6Annotation.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter3Other
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartToolFactory/Kotlin-Tutorials/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartToolFactory/Kotlin-Tutorials/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartToolFactory/Kotlin-Tutorials/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartToolFactory/Kotlin-Tutorials/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartToolFactory/Kotlin-Tutorials/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartToolFactory/Kotlin-Tutorials/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartToolFactory/Kotlin-Tutorials/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartToolFactory/Kotlin-Tutorials/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartToolFactory/Kotlin-Tutorials/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartToolFactory/Kotlin-Tutorials/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter3Other/Tutorial3_7Reflection.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter3Other
2 |
3 | fun main() {
4 |
5 | }
6 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter7Threading/Tutorial7_4CountdownLatch.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter7Threading
2 |
3 | import java.util.concurrent.CountDownLatch
4 |
5 | fun main() {
6 |
7 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Tutorials/Playground for learning Kotlin and Coroutines
2 |
3 | This is a series tutorials or playground for learning Kotlin and Coroutines based on official
4 | Kotlin documents which contains more samples and examples than original documentation has
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/local.properties:
--------------------------------------------------------------------------------
1 | ## This file must *NOT* be checked into Version Control Systems,
2 | # as it contains information specific to your local configuration.
3 | #
4 | # Location of the SDK. This is only used by Gradle.
5 | # For customization when using a Version Control System, please read the
6 | # header note.
7 | #Sat Mar 25 15:51:30 TRT 2023
8 | sdk.dir=/Users/sunflowar/Library/Android/sdk
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFBB86FC
4 | #FF6200EE
5 | #FF3700B3
6 | #FF03DAC5
7 | #FF018786
8 | #FF000000
9 | #FFFFFFFF
10 |
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter2OOP/Tutorial2_10Generics.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter2OOP
2 |
3 | fun main() {
4 | val box = Box(1) // 1 has type Int, so the compiler figures out that we are talking about Box
5 |
6 |
7 | test(12)
8 | test(12.4f)
9 | }
10 |
11 |
12 | class Box(t: T) {
13 | var value = t
14 | }
15 |
16 | fun test(num: T) {
17 |
18 | }
19 |
20 |
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter6Advanced/Generics3Methods.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter6Advanced
2 |
3 |
4 | fun main() {
5 |
6 | val ints: Array = arrayOf(1, 2, 3)
7 | val any = Array(3) { "" }
8 | copy(ints, any)
9 |
10 | }
11 |
12 |
13 | fun copy(from: Array, to: Array) {
14 | from.forEachIndexed { index, any ->
15 | to[index] = any
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter2OOP/mvp/BaseContract.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter2OOP.mvp
2 |
3 | interface BaseContract {
4 |
5 | interface IView
6 | interface IPresenter {
7 |
8 | fun attachOutput()
9 | fun attachView(view: V)
10 | fun detachView()
11 | fun onDestroy()
12 | }
13 |
14 | interface IInteractor {
15 | fun onDestroy()
16 | }
17 |
18 | interface IOutput
19 | }
--------------------------------------------------------------------------------
/app/src/test/java/com/smarttoolfactory/kotlintutorials/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.kotlintutorials
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/MySingleton.kt:
--------------------------------------------------------------------------------
1 | class MySingleton {
2 |
3 | var type = "Singleton"
4 |
5 | companion object {
6 |
7 | private var INSTANCE: MySingleton? = null
8 | val instance: MySingleton?
9 | get() {
10 | if (INSTANCE == null) {
11 | INSTANCE = MySingleton()
12 | }
13 | return INSTANCE
14 | }
15 | }
16 | }
17 |
18 | fun main() {
19 | MySingleton.instance
20 | }
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter2OOP/mvp/UserFragmentMain.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter2OOP.mvp
2 |
3 | import com.smarttoolfactory.tutorial.chapter2OOP.mvp.user.UserFragment
4 |
5 |
6 | fun main() {
7 | val userFragment = UserFragment()
8 | userFragment.onCreate()
9 | Thread.sleep(400)
10 |
11 | userFragment.onCreateView()
12 | Thread.sleep(400)
13 |
14 | userFragment.onDestroyView()
15 | Thread.sleep(400)
16 | userFragment.onDestroy()
17 |
18 | println("PROGRAM FINISHED")
19 | }
20 |
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter6Advanced/OperatorOverloading.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter6Advanced
2 |
3 | fun main() {
4 |
5 | val firstText = StringFirstLetter("Hello")
6 | val secondText = StringFirstLetter("World")
7 |
8 | val text = firstText plus secondText
9 | val text2 = firstText + secondText
10 |
11 | println(text) // Prints HW
12 | }
13 |
14 |
15 | class StringFirstLetter(val value: String) {
16 | // operator fun plus(other: StringFirstLetter): String {
17 | // return "${this.value.first()}${other.value.first()}"
18 | // }
19 | }
20 |
21 | // With infix
22 | infix operator fun StringFirstLetter.plus(other: StringFirstLetter): String {
23 | return "${this.value.first()}${other.value.first()}"
24 | }
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter2OOP/mvp/UserContract.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter2OOP.mvp
2 |
3 | import com.smarttoolfactory.tutorial.chapter2OOP.User
4 |
5 |
6 | interface UserContract {
7 |
8 | interface UserView : BaseContract.IView {
9 | fun displayUser(users: List)
10 | fun displayError(message: String?)
11 | }
12 |
13 | interface UserPresenter : BaseContract.IPresenter {
14 | fun fetchUsers()
15 | }
16 |
17 | interface UserInteractor : BaseContract.IInteractor {
18 | fun fetchUsersFromNetwork()
19 | }
20 |
21 | interface UserOutput : BaseContract.IOutput {
22 | fun onUsersFetched(users: List)
23 | fun onErrorOccurred(message: String)
24 | }
25 | }
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
19 |
20 |
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter6Advanced/ReferencesAndObjects.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter6Advanced
2 |
3 | fun main() {
4 | // var list: ArrayList? = ArrayList()
5 | // val map: HashMap?> = HashMap()
6 | // list?.add("hello")
7 | // list?.add("world")
8 | // // Map holds a reference to list
9 | // map["foo"] = list
10 | //
11 | // // 🔥 We set reference of list variable, actual objects are still referenced by map
12 | // list = null
13 |
14 | // var list1: List? = listOf(1, 2, 3)
15 | // var list2 = list1
16 | // println("list1==list2 ${list1 == list2}, ${list1.hashCode()}, ${list2.hashCode()}")
17 | // list1 = null
18 | //
19 | // println("${list2?.size}")
20 | // println("map: ${map.size}")
21 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/smarttoolfactory/kotlintutorials/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.kotlintutorials
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.smarttoolfactory.kotlintutorials", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter6Advanced/HashCodeEqualsHashMap.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter6Advanced
2 |
3 | fun main() {
4 |
5 | val myMap:HashMap = hashMapOf()
6 | for (i in 0..1000) {
7 | myMap[Person("jon", id = i)] = 1
8 | }
9 |
10 | val person1 = Person("jon", 0)
11 | val person2 = Person("jon", 10)
12 |
13 | println("person1==person2 ${person1==person2}")
14 | println("myMap size: ${myMap.size}")
15 |
16 | }
17 |
18 | /**
19 | * Need to override equals and hash code to use objects from this class to be same keys
20 | * of HashMap
21 | */
22 | class Person(private val name: String, private val id: Int) {
23 | override fun equals(other: Any?): Boolean {
24 | if(other !is Person) return false
25 |
26 | if (other.name == this.name) return true
27 |
28 | return false
29 | }
30 |
31 | override fun hashCode(): Int {
32 | return name.hashCode()
33 | }
34 | }
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter1Basics/Tutorial1_4Ranges.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter1Basics
2 |
3 | fun main() {
4 |
5 | // ----- RANGES -----
6 | // You define ranges by providing a starting and ending
7 | // value
8 |
9 | val oneTo10 = 1..10
10 | val alpha = "BaseClassA".."Z"
11 |
12 | // Use in to search a Range
13 | println("R in alpha : ${"R" in alpha}")
14 |
15 | // Create ranges that decrement
16 | val tenTo1 = 10.downTo(1)
17 |
18 | // Create array up to a value
19 | val twoTo20 = 2.rangeTo(20)
20 |
21 | // Step through an array while adding 3
22 | val rng3 = oneTo10.step(3)
23 |
24 | // Cycle through a range and print
25 | for (x in rng3) println("rng3 : $x")
26 |
27 | // Closed range
28 | for (i in 1 until 10) {
29 | // i in [1, 10), 10 is excluded
30 | println(i)
31 | }
32 |
33 | // Reverse a range
34 | for (x in tenTo1.reversed()) println("Reverse : $x")
35 | }
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter1Basics/Tutorial1_1Basics.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter1Basics
2 |
3 | fun main() {
4 |
5 | var a: Int = 1000;
6 |
7 | a += 10
8 | println("a: $a")
9 |
10 | if (true is Boolean) {
11 | print("true is boolean\n")
12 | }
13 |
14 | /*
15 | *** Characters ***
16 | */
17 | var letterGrade: Char = 'A'
18 |
19 | // instance of -> is
20 | println("BaseClassA is a Char : ${letterGrade is Char} ")
21 |
22 | // Get ASCII code of character
23 | println("BaseClassA ascii: ${letterGrade.toInt()}")
24 |
25 | println("3.14 to int ${3.14.toInt()}")
26 |
27 | /*
28 | *** Strings ***
29 | */
30 |
31 | println("********** Strings **********")
32 |
33 |
34 | var rawString: String = "I am Raw String!"
35 | val escapedString: String = "I am escaped String!\n"
36 |
37 | // Escaped String has end of line character
38 | println("Hello!$escapedString")
39 | println("Hey!!$rawString")
40 |
41 |
42 | }
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter3Other/Tutorial3_2TypeChecks.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter3Other
2 |
3 |
4 | fun main() {
5 |
6 | // Info Cast
7 | var obj: String = "";
8 | if (obj is String) {
9 | print(obj.length)
10 | }
11 | if (obj !is String) { // same as !(obj is String) print("Not a String")
12 | } else {
13 | println(obj.length)
14 | }
15 |
16 | // INFO "Unsafe" cast operator
17 | // val y: Any? = null
18 | // val x: String = y as String
19 | // println(x) // INFO Throw TypeCastException
20 |
21 | // INFO "Safe" (nullable) cast operator
22 | val a:Any? = null
23 | val b:String? = a as? String
24 | println("a: $a") // prints a: null
25 |
26 | }
27 |
28 | // INFO Smart Casts
29 | fun demo(x: Any) {
30 | if (x is String) {
31 | print(x.length) // x is automatically cast to String }
32 | }
33 | }
34 |
35 | fun testCast(x: Any) {
36 | when (x) {
37 | is Int -> print(x + 1)
38 | is String -> print(x.length + 1)
39 | is IntArray -> print(x.sum())
40 | }
41 | }
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter8fileIO/Test.java:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter8fileIO;
2 |
3 | import java.io.*;
4 |
5 | public class Test {
6 |
7 | public static void writeFile4() throws IOException {
8 | File fout = new File("out.txt");
9 | FileOutputStream fos = new FileOutputStream(fout);
10 |
11 | OutputStreamWriter osw = new OutputStreamWriter(fos);
12 |
13 | for (int i = 0; i < 10; i++) {
14 | osw.write("something");
15 | }
16 |
17 | osw.close();
18 | }
19 |
20 | public static void writeFile3() throws IOException {
21 | PrintWriter pw = new PrintWriter(new FileWriter("out.txt"));
22 |
23 | for (int i = 0; i < 10; i++) {
24 | pw.write("something");
25 | }
26 |
27 | pw.close();
28 | }
29 |
30 | public static void writeFile2() throws IOException {
31 | FileWriter fw = new FileWriter("out.txt");
32 |
33 | for (int i = 0; i < 10; i++) {
34 | fw.write("something");
35 | }
36 |
37 | fw.close();
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter3Other/Tutorial3_1Destructuring.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter3Other
2 |
3 |
4 | fun main() {
5 |
6 | // INFO Destructuring Declarations
7 | val account = Account("Standard", 100)
8 | val (name: String, amount: Int) = account
9 | println("Account type: $name, amount: $amount")
10 |
11 |
12 | // Info Returning Two Values from a Function
13 | val (result, status) = function()
14 |
15 |
16 | val map = mapOf("key1" to 1, "key2" to 2)
17 |
18 | for ((key, value) in map) {
19 | // do something with the key and the value
20 | }
21 |
22 | // Info Underscore for unused variables (since 1.1)
23 | val (_:String, _:Int, interest:Float) = account
24 |
25 |
26 | }
27 |
28 |
29 | data class Account(var type: String, var amount: Int, var interest: Float = 5.7f)
30 |
31 |
32 | // Info Returning Two Values from a Function
33 | data class Result(val result: Int, val status: String)
34 |
35 | fun function(): Result {
36 |
37 | val result = 10
38 | val status = "COMPLETED"
39 |
40 | return Result(result, status)
41 | }
42 |
43 |
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter2OOP/Tutorial2_7VisibilityModifiers.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter2OOP
2 |
3 | fun main() {
4 | val subclass = Subclass()
5 | // INFO ⚠️ only c, and d properties are visible to instance of derived class
6 | println("Subclass c ${subclass.c}, d ${subclass.d}")
7 |
8 | }
9 |
10 | open class ParentClass {
11 |
12 | private val a = 1
13 | protected open val b = 2
14 | internal val c = 3
15 | val d = 4 // public by default
16 |
17 | protected class Nested {
18 | public val e: Int = 5
19 | }
20 |
21 | }
22 |
23 | class Subclass : ParentClass() {
24 |
25 | // a is not visible
26 | // b, c and d are visible // Nested and e are visible
27 | override val b = 5 // 'b' is protected }
28 |
29 | fun test() {
30 | println("b $b, c $c, d $d")
31 | val nested = Nested()
32 |
33 | }
34 | }
35 |
36 | class Unrelated(o: ParentClass) {
37 | // o.a, o.b are not visible
38 | // o.c and o.d are visible (same module)
39 | // Outer.Nested is not visible, and Nested::e is not visible either
40 |
41 | init {
42 | // INFO ⚠️ not Visible
43 | // val nestedClass = Nested()
44 | }
45 | }
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter7Threading/Tutorial7_1Thread.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter7Threading
2 |
3 | fun main() {
4 | // Threads run concurrently
5 | val myThread1 = MyThread()
6 | val myThread2 = MyThread()
7 | myThread1.start()
8 | myThread2.start()
9 |
10 | // Runnable can be passed to thread constructor
11 | val thread = Thread(MyRunnable())
12 | thread.start()
13 |
14 | val thread2 = Thread {
15 | // This is run method of this thread
16 | for (i in 0..10) {
17 | println("ANONYMOUS THREAD Count: $i, in thread: ${Thread.currentThread().name}")
18 | Thread.sleep(100)
19 | }
20 | }
21 | thread2.start()
22 |
23 | Thread.sleep(1000)
24 | }
25 |
26 | class MyThread : Thread() {
27 | override fun run() {
28 | for (i in 0..10) {
29 | println("THREAD Count: $i, in thread: ${Thread.currentThread().name}")
30 | sleep(100)
31 | }
32 | }
33 | }
34 |
35 | class MyRunnable : Runnable {
36 | override fun run() {
37 | for (i in 0..10) {
38 | println("RUNNABLE Count: $i, in thread: ${Thread.currentThread().name}")
39 | Thread.sleep(100)
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Kotlin code style for this project: "official" or "obsolete":
19 | kotlin.code.style=official
20 | android.defaults.buildfeatures.buildconfig=true
21 | android.nonTransitiveRClass=false
22 | android.nonFinalResIds=false
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter2OOP/Tutorial2_14DelegationComposeRememberMutableState.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter2OOP
2 |
3 | import java.util.LinkedHashMap
4 | import kotlin.reflect.KProperty
5 |
6 | fun main() {
7 |
8 | val isSelected: MutableState = remember { mutableStateOf(true) }
9 | isSelected.value = false
10 |
11 | var selected by remember { mutableStateOf(false) }
12 | selected = false
13 | }
14 |
15 |
16 | /*
17 | * MutableState
18 | */
19 | interface MutableState : State {
20 | override var value: T
21 | }
22 |
23 | // Delegation Functions for setting and getting value
24 | operator fun State.getValue(thisObj: Any?, property: KProperty<*>): T = value
25 |
26 | operator fun MutableState.setValue(thisObj: Any?, property: KProperty<*>, value: T) {
27 | this.value = value
28 | }
29 |
30 | interface State {
31 | val value: T
32 | }
33 |
34 | class MutableStateImpl(value: T) : MutableState {
35 | override var value: T = value
36 | }
37 |
38 | fun mutableStateOf(value: T): MutableState = MutableStateImpl(value)
39 |
40 | /*
41 | * Remember
42 | */
43 |
44 | inline fun remember(calculation: () -> T): T {
45 | return calculation()
46 | }
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter2OOP/Tutorial2_1Constructors.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter2OOP
2 |
3 | import com.smarttoolfactory.tutorial.chapter2OOP.model.*
4 |
5 | fun main() {
6 |
7 | val a: String? = null
8 | val b: String = ""
9 | println(a == b)
10 |
11 | // create obj object of myClass class
12 | // val obj = MyClass()
13 | // obj.printMe()
14 | //
15 | val person1 = Person("Alex", "Smith", 29)
16 | val person2 = Person("Jane", "Smith", null)
17 | //
18 | println("${person1.firstName},${person1.lastName} is ${person1.age} years old")
19 | // println("${person2.firstName},${person2.lastName} is ${person2.age?.toString() ?: "?"} years old")
20 | //
21 | val personType2 = Person2(
22 | "June",
23 | "Smith",
24 | 23
25 | )
26 |
27 | // println("Name: ${personType2.getType()}, age: ${personType2.getAge()}")
28 |
29 |
30 |
31 | // INFO Init Blocks
32 | val initOrder = InitOrderDemo("Demo")
33 |
34 | // // INFO Secondary Constructors
35 | val person3 = Person4("Jane", "White")
36 | val person4 = Person4("Jake", "White")
37 |
38 | val constructors = Constructors(5)
39 |
40 | val auto1 = Auto(5, "Honda")
41 | val auto2 =
42 | Auto(name = "Ferrari")
43 | val auto3 = Auto(2, "BMW")
44 |
45 |
46 | }
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter6Advanced/LambdaWithReceiver.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter6Advanced
2 |
3 | fun main() {
4 |
5 | testScopedFunctions()
6 |
7 | }
8 |
9 |
10 | /*
11 | Scoped Functions
12 | */
13 |
14 | private fun testScopedFunctions() {
15 |
16 | val testString = "Hello"
17 |
18 | val resLet = testString.letMe {
19 | it.toIntOrNull() ?: -1
20 | }
21 |
22 | val resRun = testString.runMe {
23 | toIntOrNull() ?: -1
24 | }
25 |
26 |
27 | val resAlso = testString.alsoMe {
28 | }
29 |
30 | val resApply = testString.applyMe {
31 |
32 | }
33 |
34 | withMe(testString) {
35 | uppercase()
36 | capitalize()
37 | }
38 |
39 | }
40 |
41 | fun T.letMe(predicate: (T) -> R): R {
42 | return predicate(this)
43 | }
44 |
45 | fun T.runMe(predicate: T.() -> R): R {
46 | return this.predicate()
47 | }
48 |
49 |
50 | fun T.alsoMe(predicate: (T) -> Unit): T {
51 | predicate(this)
52 | return this
53 | }
54 |
55 | fun T.applyMe(predicate: T.() -> Unit): T {
56 | this.predicate()
57 | return this
58 | }
59 |
60 | fun withMe(receiver: T, predicate: (T).() -> R): R {
61 | return receiver.predicate()
62 | }
63 |
64 |
65 | class Task(val date: Long, val description: String)
66 |
--------------------------------------------------------------------------------
/tutorial/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java-library'
3 | id 'kotlin'
4 | }
5 |
6 | java {
7 | sourceCompatibility JavaVersion.VERSION_21
8 | targetCompatibility JavaVersion.VERSION_21
9 | }
10 |
11 | dependencies {
12 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
13 |
14 | implementation 'io.reactivex.rxjava2:rxjava:2.2.19'
15 | implementation("io.reactivex.rxjava2:rxkotlin:2.2.0")
16 |
17 | implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2")
18 |
19 | // Reflection
20 | implementation("org.jetbrains.kotlin:kotlin-reflect:2.1.0")
21 |
22 | // (Required) Writing and executing Unit Tests on the JUnit Platform
23 | testImplementation "org.junit.jupiter:junit-jupiter-api:5.10.1"
24 | testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.10.1"
25 |
26 | testImplementation 'junit:junit:4.13.2'
27 |
28 | // (Optional) If you need "Parameterized Tests"
29 | testImplementation "org.junit.jupiter:junit-jupiter-params:5.10.1"
30 |
31 | // (Optional) If you also have JUnit 4-based tests
32 | testImplementation "junit:junit:4.13.2"
33 | testRuntimeOnly "org.junit.vintage:junit-vintage-engine:5.10.1"
34 |
35 | // Test Coroutines
36 | testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.10.2'
37 |
38 | // Truth
39 | testImplementation "com.google.truth:truth:1.4.2"
40 | }
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'kotlin-android'
4 | }
5 |
6 | android {
7 | compileSdkVersion 35
8 |
9 | defaultConfig {
10 | applicationId "com.smarttoolfactory.kotlintutorials"
11 | minSdkVersion 21
12 | targetSdkVersion 35
13 | versionCode 1
14 | versionName "1.0"
15 |
16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
17 | }
18 |
19 | buildTypes {
20 | release {
21 | minifyEnabled false
22 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
23 | }
24 | }
25 | compileOptions {
26 | sourceCompatibility = JavaVersion.VERSION_17
27 | targetCompatibility = JavaVersion.VERSION_17
28 | }
29 | kotlinOptions {
30 | jvmTarget = '17'
31 | }
32 | namespace 'com.smarttoolfactory.kotlintutorials'
33 | }
34 |
35 | dependencies {
36 |
37 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
38 | implementation 'androidx.core:core-ktx:1.16.0'
39 | implementation 'androidx.appcompat:appcompat:1.7.0'
40 | implementation 'com.google.android.material:material:1.12.0'
41 | testImplementation 'junit:junit:4.13.2'
42 | androidTestImplementation 'androidx.test.ext:junit:1.2.1'
43 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1'
44 | }
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter6Advanced/Reified.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter6Advanced
2 |
3 |
4 | fun main() {
5 |
6 | val reified = Reified()
7 |
8 | val result = reified.getClassOf()
9 |
10 | val str = result.newInstance()
11 |
12 | println(str)
13 |
14 | val publicAccount = reified.getAccountClass().newInstance()
15 | val publicAccountBalance = publicAccount.getBalance()
16 | println("Public Balance $publicAccountBalance")
17 |
18 | val privateAccount = reified.getAccountInstance()
19 | val privateAccountBalance = privateAccount.getBalance()
20 | println("Private Balance: $privateAccountBalance")
21 |
22 |
23 | }
24 |
25 | class Reified {
26 |
27 | internal inline fun getClassOf(): Class {
28 | return T::class.java
29 | }
30 |
31 | internal inline fun getAccountClass(): Class {
32 | return T::class.java
33 | }
34 |
35 | internal inline fun getAccountInstance(): T {
36 | return T::class.java.newInstance()
37 | }
38 | }
39 |
40 | interface Account {
41 | fun getBalance(): Int
42 | }
43 |
44 | class PrivateAccount() : Account {
45 |
46 | override fun getBalance(): Int {
47 | return 3
48 | }
49 | }
50 |
51 | class PublicAccount() : Account {
52 | override fun getBalance(): Int {
53 | return 5
54 | }
55 | }
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter6Advanced/RegularExpressions.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter6Advanced
2 |
3 | /*
4 | Here is the complete list of various character classes constructs:
5 | [abc]: It would match with text if the text is having either one of them(a,b or c) and only once.
6 | [^abc]: Any single character except a, b, or c (^ denote negation)
7 | [a-zA-Z]: a through z, or A through Z, inclusive (range)
8 | [a-d[m-p]]: a through d, or m through p: [a-dm-p] (union)
9 | [a-z&&[def]]: Any one of them (d, e, or f)
10 | [a-z&&[^bc]]: a through z, except for b and c: [ad-z] (subtraction)
11 | [a-z&&[^m-p]]: a through z, and not m through p: [a-lq-z] (subtraction)
12 |
13 | Predefined Character Classes – Metacharacters
14 | These are like short codes which you can use while writing regex.
15 |
16 | Construct Description
17 | . -> Any character (may or may not match line terminators)
18 | \d -> A digit: [0-9]
19 | \D -> A non-digit: [^0-9]
20 | \s -> A whitespace character: [ \t\n\x0B\f\r]
21 | \S -> A non-whitespace character: [^\s]
22 | \w -> A word character: [a-zA-Z_0-9]
23 | \W -> A non-word character: [^\w]
24 |
25 | Boundary Matchers
26 | ^ Matches the beginning of a line.
27 | $ Matches then end of a line.
28 | \b Matches a word boundary.
29 | \B Matches a non-word boundary.
30 | \A Matches the beginning of the input text.
31 | \G Matches the end of the previous match
32 | \Z Matches the end of the input text except the final terminator if any.
33 | \z Matches the end of the input text.
34 | */
35 |
36 | fun main() {
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter6Advanced/DSLWithLambda2.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter6Advanced
2 |
3 | /**
4 | * This is a sample to display how functions with literals used with Jetpack Compose.
5 | *
6 | * This is a series of mock functions to display simplified version of drawing with Compose.
7 | *
8 | * * Column uses [Layout] do draw on a [Canvas] function using [DrawScope]
9 | */
10 | fun main() {
11 |
12 | val modifier = Modifier
13 | Column(modifier = modifier) {
14 | println("🔥 Draw this COLUMN")
15 | }
16 | }
17 |
18 | fun Column(modifier: Modifier, content: ColumnScope.() -> Unit) {
19 |
20 | Layout(modifier) {
21 | ColumnScope.content()
22 | }
23 | }
24 |
25 | interface ColumnScope {
26 | fun Modifier.alignColumn()
27 |
28 | companion object : ColumnScope {
29 |
30 | override fun Modifier.alignColumn() {
31 | println("🤔 Modifier for Column alignColumn() ")
32 | }
33 |
34 | }
35 | }
36 |
37 |
38 | interface Modifier {
39 | companion object : Modifier
40 | }
41 | fun Layout(modifier: Modifier = Modifier, content: () -> Unit) {
42 | println("Layout()")
43 | modifier.drawBehind {
44 | content()
45 | }
46 | }
47 |
48 | interface DrawScope {
49 | fun draw()
50 | }
51 |
52 | class DrawModifier(val onDraw: DrawScope.() -> Unit) : DrawScope {
53 |
54 | override fun draw() {
55 | println("⚠️ DrawModifier drawContent()")
56 | onDraw()
57 | }
58 | }
59 |
60 | fun Modifier.drawBehind(
61 | onDraw: DrawScope.() -> Unit
62 | ) {
63 | DrawModifier(
64 | onDraw = onDraw
65 | ).draw()
66 | }
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter2OOP/Tutorial2_11Enums.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter2OOP
2 |
3 | fun main() {
4 | val direction = Direction.NORTH
5 |
6 | val waiting = ProtocolState.WAITING
7 | println("WAITING signal(): ${ waiting.signal()}")
8 |
9 | var state = ProtocolState.WAITING
10 | repeat(4) {
11 | state = state.signal()
12 |
13 | println("state: $state")
14 | }
15 |
16 | val redColor = Color.RED
17 |
18 | println("Color: $redColor, rgb: ${redColor.rgb}")
19 |
20 | val printerType = EnumPrinterType.DOTMATRIX
21 |
22 | println("printerType: $printerType, pageAmount: ${printerType.pageAmount}, price: ${printerType.price}")
23 |
24 |
25 | }
26 |
27 | // 🔥 INFO Enum Classes
28 | enum class Direction {
29 | NORTH, SOUTH, WEST, EAST
30 | }
31 |
32 | // 🔥 INFO Initialization
33 | enum class Color(val rgb: Int) {
34 |
35 | RED(0xFF0000),
36 | GREEN(0x00FF00),
37 | BLUE(0x0000FF)
38 |
39 | }
40 |
41 | // 🔥 INFO Anonymous Classes
42 | enum class ProtocolState {
43 |
44 | WAITING {
45 | override fun signal() = TALKING
46 | },
47 |
48 | TALKING {
49 | override fun signal() = WALKING
50 | },
51 |
52 | WALKING {
53 | override fun signal() = WAITING
54 | };
55 |
56 | abstract fun signal(): ProtocolState
57 | }
58 |
59 | // 🔥 INFO Working with Enum Constants
60 |
61 |
62 | // 🔥 Enum constructors are private, enums can not be instantiated
63 | enum class EnumPrinterType(var pageAmount: Int, internal var price: String) {
64 |
65 | DOTMATRIX(3, "cheap"), INKJET(5, "expensive"), LASER(7, "very expensive")
66 |
67 | }
68 |
69 |
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/Animal.java:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial; /**
2 | * Class for displaying inheritance when a field exists in both super and derived type
3 | *
4 | * If static type of object is super(Animal cat) then field from super type is used to
5 | * fetch and modify.
6 | *
7 | * * When a method is overridden by a derived class then derived class' method is called
8 | */
9 | public class Animal {
10 |
11 | String name;
12 |
13 | public Animal(String name) {
14 | this.name = name;
15 | }
16 |
17 | public void printName() {
18 | System.out.println("Animal.printName() -> Animal name: " + name);
19 | }
20 |
21 | public String getCatName() {
22 | return name;
23 | }
24 |
25 | public static void main(String[] args) {
26 |
27 | Animal cat = new Cat("Cat");
28 |
29 | cat.name = "Felix";
30 | cat.printName();
31 |
32 | // Cat name is from Animal but overridden method is from Cat dynamic type
33 | System.out.println("CAT NAME: " + cat.name +", CAT.getName(): " + cat.getCatName());
34 |
35 | /*
36 | Prints:
37 |
38 | Cat name: Cat, Animal name: Felix
39 | CAT NAME: Felix, CAT.getName(): Cat
40 | */
41 |
42 | }
43 | }
44 |
45 |
46 | class Cat extends Animal {
47 |
48 | // 🔥If type is Animal this is shadowed, name from Animal is set and get when called
49 | String name;
50 |
51 | public Cat(String name) {
52 | super("Felis Domesticus");
53 | this.name = name;
54 | }
55 |
56 | public String getCatName() {
57 | return name;
58 | }
59 |
60 | public void printName() {
61 | System.out.println("Cat.printName() -> Cat name: " + name + ", Animal(super.name) name: " + super.name);
62 | }
63 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter3Other/Tutorial3_5Exceptions.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter3Other
2 |
3 | import java.io.*
4 | import java.lang.Integer.parseInt
5 |
6 | fun main() {
7 |
8 | try {
9 | // some code
10 | } catch (e: Exception) {
11 | // handler(if finally is available catch is optional)
12 | } finally {
13 | // optional finally block
14 | }
15 |
16 |
17 | // INFO Try is an expression
18 | val a: Int? = try {
19 | parseInt("5")
20 | } catch (e: NumberFormatException) {
21 | null
22 | }
23 |
24 | // INFO Checked Exceptions
25 |
26 | val stringBuilder = StringBuilder()
27 | stringBuilder.append(charArrayOf('a', 'b', 'c'), 1, 2)
28 |
29 | // INFO Checked Exception with File IO
30 | try {
31 |
32 | val homePath = System.getProperty("user.home")
33 |
34 | // Throws FileNotFoundException
35 | File("$homePath/desktop/test.txt")
36 | .writer().use {
37 | it.write("Hello World")
38 | }
39 |
40 | } catch (e: FileNotFoundException) {
41 | println("Exception occurred: ${e.message}")
42 | }
43 |
44 | // INFO Nothing Type
45 | val person = Person(null)
46 | // Throws IllegalArgumentException: Name required since name is NULL
47 | // val s = person.name ?: throw IllegalArgumentException("Name required")
48 |
49 | val test = person.name ?: fail("Name required")
50 | println(test) // 'test' is known to be initialized at this point
51 |
52 |
53 | val x = null // 'x' has type `Nothing?`
54 | val l = listOf(null) // 'l' has type `List
55 |
56 | }
57 |
58 |
59 | data class Person(val name: String?)
60 |
61 | fun fail(message: String): Nothing {
62 | throw IllegalArgumentException(message)
63 | }
64 |
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter7Threading/Tutorial7_2Synchronized.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter7Threading
2 |
3 | fun main() {
4 | val nonSyncCounter = NonSyncCounter()
5 | val syncCounter = SyncedCounter()
6 |
7 | nonSyncCounter.count()
8 | syncCounter.count()
9 | }
10 |
11 | class NonSyncCounter {
12 | /**
13 | * Any thread can access and update this value while other thread might be reading
14 | * value that is not updated yet
15 | */
16 | private var counter: Int = 0
17 |
18 | fun count() {
19 | val thread1 = Thread {
20 | repeat(10000) {
21 | counter++
22 | }
23 | }
24 |
25 | val thread2 = Thread {
26 | repeat(10000) {
27 | counter++
28 | }
29 | }
30 |
31 | thread1.start()
32 | thread2.start()
33 |
34 | thread1.join()
35 | thread2.join()
36 |
37 | println("NonSyncCounter counter: $counter")
38 | }
39 | }
40 |
41 | class SyncedCounter {
42 | private var counter: Int = 0
43 |
44 | /**
45 | * We acquire lock with SyncedCounter object this.
46 | * Only one thread at a time can access to counter
47 | */
48 | @Synchronized
49 | private fun increment() {
50 | counter++
51 | }
52 |
53 |
54 | fun count() {
55 | val thread1 = Thread {
56 | repeat(10000) {
57 | increment()
58 | }
59 | }
60 |
61 | val thread2 = Thread {
62 | repeat(10000) {
63 | increment()
64 | }
65 | }
66 |
67 | thread1.start()
68 | thread2.start()
69 |
70 | thread1.join()
71 | thread2.join()
72 |
73 | println("SyncedCounter counter: $counter")
74 | }
75 |
76 | }
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter6Advanced/DSLWithLambda.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter6Advanced
2 |
3 | import java.util.*
4 |
5 |
6 | fun main() {
7 | testRouteHandler()
8 |
9 | var delegatedNum2 by delegateCalculationFunction()
10 |
11 | }
12 |
13 | private fun testRouteHandler() {
14 |
15 | routeHandler("/index.html") {
16 |
17 | if (request.query != "") {
18 | // process
19 | }
20 |
21 | response {
22 | code = 404
23 | description = "Not found"
24 | }
25 | }
26 | }
27 |
28 | class RouteHandler(val request: Request, val response: Response) {
29 | var executeNext = false
30 | fun next() {
31 | executeNext = true
32 | }
33 | }
34 |
35 | fun routeHandler(path: String, f: RouteHandler.() -> Unit) {
36 |
37 | val request = Request("GET", "/v1/getProducts", "json")
38 | val response = Response("body", Status(200, ""))
39 | val routeHandler = RouteHandler(request, response)
40 |
41 | routeHandler.f()
42 | }
43 |
44 | class Status(var code: Int, var description: String)
45 |
46 | class Request(val method: String, val query: String, val contentType: String)
47 |
48 | class Response(var contents: String, var status: Status) {
49 | operator fun invoke(status: Status.() -> Unit) {
50 | }
51 | }
52 |
53 |
54 | // HTML
55 |
56 | class HTML {
57 |
58 | fun init() {
59 |
60 | }
61 | }
62 |
63 | interface Element
64 |
65 | class Head : Element
66 | class Body : Element
67 |
68 | val children = ArrayList()
69 |
70 | fun head(init: Head.() -> Unit): Head {
71 | val head = Head()
72 | head.init()
73 | children.add(head)
74 | return head
75 | }
76 |
77 | fun body(init: Body.() -> Unit): Body {
78 | val body = Body()
79 | body.init()
80 | children.add(body)
81 | return body
82 | }
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter2OOP/Tutorial2_4Inheritance2.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter2OOP
2 |
3 | import com.smarttoolfactory.tutorial.chapter2OOP.model.BusinessAccount
4 | import com.smarttoolfactory.tutorial.chapter2OOP.model.PrivateAccount
5 | import com.smarttoolfactory.tutorial.chapter2OOP.model.Snake
6 | import com.smarttoolfactory.tutorial.chapter2OOP.model.UnionAccount
7 |
8 | fun main() {
9 |
10 | // val privateAccount = PrivateAccount(22.5)
11 | // println("Private baseAmount: ${privateAccount.baseAmount} ")
12 | // privateAccount.baseAmount = 130.0
13 | // println("Private AFTER baseAmount: ${privateAccount.baseAmount} ")
14 | // privateAccount.displayValue()
15 | //
16 | // val businessAccount = BusinessAccount(50.0)
17 | // println("Business baseAmount: ${businessAccount.baseAmount} ")
18 | // businessAccount.baseAmount = 130.0
19 | // println("Business AFTER baseAmount: ${businessAccount.baseAmount} ")
20 | // businessAccount.displayValue()
21 |
22 | val unionAccount = UnionAccount(61.8)
23 | unionAccount.setBase(12.54)
24 | unionAccount.displayValue()
25 |
26 | unionAccount.unionProperty = "Test"
27 |
28 | println("Union property: ${unionAccount.unionProperty}")
29 |
30 | /*
31 | Private baseAmount: 22.5
32 | Private AFTER baseAmount: 130.0
33 | PrivateAccount Parent super.baseAmount: 130.0, derived: 130.0
34 |
35 | Business baseAmount: 0.0
36 | Business AFTER baseAmount: 390.0
37 | BusinessAccount Parent super.baseAmount: 50.0, derived: 390.0
38 |
39 | UnionAccount Parent super.baseAmount: 61.8, derived: 12.54
40 | Union property: Test 12.54
41 | */
42 |
43 |
44 | // val snake = Snake()
45 | // println("Snake Sound: ${snake.makeSound()}")
46 | // println("Snake Move: ${snake.doMove()}")
47 | // println("Snake Max Age: ${snake.MAX_AGE}")
48 | }
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter1Basics/Tutorial1_3Collections2Set.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter1Basics
2 |
3 | fun main() {
4 |
5 | /*
6 | ***** SETs *****
7 | */
8 |
9 | /*
10 | * INFO Instantiation
11 | */
12 | // Immutable(Read-Only)
13 | val setImmutable1 = setOf(3, 5, 1) // [3, 5, 1]
14 |
15 | // Mutable
16 | val setHash = hashSetOf(3, 5, 1) // [5, 1, 3]
17 | val setLinkedHash = linkedSetOf(3, 5, 1) // [3, 5, 1]
18 | val setTree = sortedSetOf(3, 5, 1) // [1, 3, 5]
19 | val setMutable = mutableSetOf(3, 5, 1) // [3, 5, 1]
20 |
21 | setImmutable1.forEach { it -> println("setImmutable1 Item $it") }
22 | setHash.forEach { it -> println("setHash Item $it") }
23 | setLinkedHash.forEach { it -> println("setLinkedHash Item $it") }
24 | setTree.forEach { it -> println("setTree Item $it") }
25 |
26 | // When we put same object with hash code and equals it's replaced with previous one
27 | // If objects are not treated as same object from hashmap perspective new object is added
28 | // Hashset adds items as keys of inner hashMap as
29 | /*
30 | Object PRESENT = Object()
31 | mySet(person1) -> map.put(person1, PRESENT)
32 | */
33 | val person1 = Person("jon", 0)
34 | val person2 = Person("jon", 2)
35 | val mySet: HashSet = hashSetOf()
36 | val result1 = mySet.add(person1)
37 | val result2 = mySet.add(person2)
38 | println("Result1: $result1, result2: $result2")
39 |
40 |
41 |
42 | }
43 |
44 | class Person(
45 | val name: String, val id: Int
46 | ) {
47 | // override fun equals(other: Any?): Boolean {
48 | // if (other !is Person) return false
49 | // if (other.name == this.name) return true
50 | // return false
51 | // }
52 | //
53 | // override fun hashCode(): Int {
54 | // return name.hashCode()
55 | // }
56 | }
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter3Other/Tutorial3_3Equality.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter3Other
2 |
3 | fun main() {
4 |
5 | println("Primitive Equality")
6 | val int1 = 10
7 | val int2 = 10
8 |
9 | println(int1 == int2) // true
10 | println(int1.equals(int2)) // true
11 | println(int1 === int2) // true
12 |
13 | println("Class Equality")
14 |
15 | class Employee(val name: String)
16 |
17 | val emp1 = Employee("John")
18 | val emp2 = Employee("John")
19 |
20 | println(emp1 == emp2) //false
21 | println(emp1.equals(emp2)) //false
22 | println(emp1 === emp2) //false
23 |
24 | println(emp1.name == emp2.name) //true
25 | println(emp1.name.equals(emp2.name)) //true
26 | println(emp1.name === emp2.name) //true
27 |
28 | println("Data Class Equality")
29 |
30 | data class EmployeeData(val name: String)
31 |
32 | val empData1 = EmployeeData("John")
33 | val empData2 = EmployeeData("John")
34 |
35 | println(empData1 == empData2) //true
36 | println(empData1.equals(empData2)) //true
37 | println(empData1 === empData2) //false
38 |
39 | println(empData1.name == empData2.name) //true
40 | println(empData1.name.equals(empData2.name)) //true
41 | println(empData1.name === empData2.name) //true
42 |
43 | println("Numbers")
44 | val number1 = Integer(10) // create new instance
45 | val number2 = Integer(10) // create new instance
46 | val number3 = number1
47 |
48 | // check if number1 and number2 are Structural equality
49 | println(number1 == number2) // prints true
50 |
51 | // check if number1 and number2 points to the same object
52 | // in other words, checks for Referential equality
53 | println(number1 === number2) // prints false
54 |
55 | // check if number1 and number3 points to the same object
56 | println(number1 === number3) // prints true
57 |
58 | }
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter2OOP/Tutorial2_14Delegation3StandartDelegation.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter2OOP
2 |
3 | import kotlin.properties.Delegates
4 |
5 | fun main() {
6 |
7 | // INFO 🔥 Standard Delegates
8 | // INFO 🔥 Lazy
9 | println(lazyValue)
10 | println(lazyValue)
11 |
12 | // INFO 🔥 Observable
13 | val user = UserObservable()
14 | user.name = "first"
15 | user.name = "second"
16 |
17 | // INFO 🔥 Vetoable
18 | println(max) // 0
19 | max = 10
20 | println(max) // 10
21 |
22 | max = 5 // will fail with IllegalArgumentException
23 |
24 | // INFO 🔥 Storing Properties in a Map
25 | val userMapDelegate = ImmutableUser(
26 | mapOf(
27 | "type" to "John Doe",
28 | "age" to 25
29 | )
30 | )
31 |
32 | println(userMapDelegate.name) // Prints "John Doe"
33 | println(userMapDelegate.age) // Prints 25
34 | }
35 |
36 | // INFO 🔥 Standard Delegates
37 |
38 | // INFO 🔥 Lazy
39 | // WARNING The lazy {...} delegate can only be used for val properties
40 | val lazyValue: String by lazy {
41 | println("Invoked only the first time lazy initialized!")
42 | "Hello"
43 | }
44 |
45 |
46 | // INFO 🔥 Observable
47 |
48 | class UserObservable {
49 | var name: String by Delegates.observable("") { prop, old, new ->
50 | println("$old -> $new")
51 | }
52 | }
53 |
54 | // INFO 🔥 Vetoable
55 | var max: Int by Delegates.vetoable(0) { property, oldValue, newValue ->
56 |
57 | println("vetoable property: $property, oldValue: $oldValue, newValue: $newValue")
58 | if (newValue > oldValue) true
59 | else throw IllegalArgumentException("New value must be larger than old value.")
60 | }
61 |
62 |
63 | // INFO 🔥 Storing Properties in a Map
64 |
65 | class ImmutableUser(val map: Map) {
66 | val name: String by map
67 | val age: Int by map
68 | }
69 |
70 |
71 | class MutableUser(val map: MutableMap) {
72 | var name: String by map
73 | var age: Int by map
74 | }
75 |
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter6Advanced/Generics2PECS.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter6Advanced
2 |
3 | fun main() {
4 |
5 | val tomatoBasket = VegetableBasket()
6 | val vegetableBasket = VegetableBasket()
7 | val plantBasket = VegetableBasket()
8 |
9 | val plants = ArrayList()
10 | val vegtables = ArrayList()
11 | val tomatoes = ArrayList()
12 |
13 | // Can use any class that super of T which is Tomato
14 | tomatoBasket.doSomethingWithList(plants)
15 | tomatoBasket.doSomethingWithList(vegtables)
16 | tomatoBasket.doSomethingWithList(tomatoes)
17 |
18 | vegetableBasket.doSomethingWithList(plants)
19 | vegetableBasket.doSomethingWithList(vegtables)
20 |
21 | vegetableBasket.doSomethingOut(tomatoBasket)
22 | vegetableBasket.doSomethingIn(plantBasket)
23 |
24 | // ❌ COMPILE ERROR Tomato is sub-type of Vegetable, it can accept Vegetable or super types
25 | // vegetableBasket.doSomething(tomatoes)
26 |
27 |
28 | }
29 |
30 | open class Plant
31 | open class Vegetable : Plant()
32 | class Tomato : Vegetable()
33 | class Cucumber : Vegetable()
34 |
35 | class VegetableBasket {
36 |
37 | fun doSomethingOut(basket: VegetableBasket) {
38 |
39 | }
40 |
41 | fun doSomethingIn(basket: VegetableBasket) {
42 |
43 | }
44 |
45 | fun doSomethingWithList(list: ArrayList) {
46 | list.forEach {
47 | println("VegetableBasket element: $it")
48 | }
49 | }
50 | }
51 |
52 | interface Producer {
53 | fun produce(): T
54 | }
55 |
56 | interface Consumer {
57 | fun consume(t: T)
58 | }
59 |
60 | class InOutTestClass {
61 |
62 | fun foo1(i: I) {
63 |
64 | }
65 |
66 | // ❌ COMPILE ERROR Type parameter I is declared as 'in' but occurs in 'out' position in type I
67 | // fun foo2():I{}
68 |
69 | // ❌ COMPILE ERROR Type parameter O is declared as 'out' but occurs in 'in' position in type O
70 | // fun foo3(o:O) = {}
71 |
72 | inline fun foo4(): O {
73 | return O::class.java.newInstance()
74 | }
75 |
76 |
77 | }
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter3Other/Tutorial3_4NullSafety.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter3Other
2 |
3 | fun main() {
4 |
5 | val a: String = "abc"
6 | // a = null // compilation error
7 |
8 | var b: String? = "abc"
9 | b = null // ok print(b)
10 | // val l = b.length // WARNING error: variable 'b' can be null
11 |
12 | // INFO Checking for null in conditions
13 | val l = if (b != null) b.length else -1
14 |
15 |
16 | val c: String? = "Kotlin"
17 | if (c != null && c.length > 0) {
18 | print("String of length ${c.length}")
19 | } else {
20 | print("Empty string")
21 | }
22 |
23 |
24 | val notNullString = "Kotlin"
25 | val nullableString: String? = null
26 | println(nullableString?.length)
27 | println(notNullString?.length) // Unnecessary safe call
28 |
29 | // INFO Safe Calls with Let
30 | val listWithNulls: List = listOf("Kotlin", null)
31 | for (item in listWithNulls) {
32 | item?.let { println(it) } // prints Kotlin and ignores null
33 | }
34 |
35 | // BaseClassA safe call can also be placed on the left side of an assignment.
36 | // Then, if one of the receivers in the safe calls chain is null,
37 | // the assignment is skipped, and the expression on the right is not evaluated at all:
38 |
39 | // If either `person` or `person.department` is null, the function is not called:
40 | // person?.department?.head = managersPool.getManager()
41 |
42 | // INFO Elvis Operator
43 | val myInt: Int = if (b != null) b.length else -1
44 | val myInt2 = b?.length ?: -1
45 |
46 | // INFO The !! Operator
47 | // val nullableInt = b!!.length // Throws NPE since b is NULL
48 |
49 | // INFO Safe Casts
50 | // Regular casts may result into a ClassCastException if the object is not of the target type.
51 | // Another option is to use safe casts that return null if the attempt was not successful:
52 | val randomVal: Any = 3
53 | val aInt: Int? = randomVal as? Int
54 |
55 | // INFO Collections of Nullable Type
56 | val nullableList: List = listOf(1, 2, null, 4)
57 | // Filters out the null elements
58 | val intList: List = nullableList.filterNotNull()
59 |
60 |
61 | }
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter1Basics/Tutorial1_3Collections3Map.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter1Basics
2 |
3 | fun main() {
4 |
5 | /*
6 | ***** MAPs *****
7 | */
8 |
9 | /*
10 | * INFO Instantiation
11 | */
12 | val map1 = mapOf("b" to 2, "a" to 1) // {b=2, a=1}
13 | val mapHash = hashMapOf("b" to 2, "a" to 1) // {a=1, b=2}
14 | val mapLinked = linkedMapOf("b" to 2, "a" to 1) // {b=2, a=1}
15 | val mapSorted = sortedMapOf("b" to 2, "a" to 1) // {a=1, b=2}
16 | val mapMutable = mutableMapOf("b" to 2, "a" to 1) // {b=2, a=1}
17 |
18 |
19 | val keys: MutableSet = mapMutable.keys
20 | val values: MutableCollection = mapMutable.values
21 | val entries: MutableSet> = mapMutable.entries
22 | val iterator = mapMutable.iterator()
23 |
24 | mapMutable.put("c",3)
25 |
26 | // Iterator contains Entry, and gets iterator.hasNext() and iterates to next item if available
27 |
28 | /*
29 | * INFO Looping
30 | */
31 |
32 | // INFO Method1: Key & Values
33 |
34 | for (k in keys) {
35 | println("Map Method1a: K: $k")
36 | }
37 |
38 | for (v in values) {
39 | println("Map Method1b: V: $v")
40 | }
41 |
42 | for ((key, value) in mapMutable) {
43 | println("Map Method1c: K: $key, V: $value")
44 | }
45 | println("****************************")
46 |
47 | // INFO Method2: EntrySet
48 | entries.forEach { (k, v) -> println("Map Method2: $k, V: $v") }
49 | println("****************************")
50 |
51 | // INFO Method3: Iterator & Entry
52 | while (iterator.hasNext()) {
53 | val entry = iterator.next()
54 | println("Map Method3: K: ${entry.key}, V: ${entry.value}")
55 | }
56 | println("****************************")
57 |
58 | // INFO Method4: Loop iterator with foreach method
59 | iterator.forEach { println("Map Method4 K: ${it.key}, V: ${it.value}") }
60 | println("****************************")
61 |
62 | // INFO Method5: Looping Keys and Values directly
63 | mapMutable.forEach { (key, value) -> println("Map Method5 K: $key , V: $value") }
64 | println("****************************")
65 |
66 | /*
67 | * INFO Immutable(Read-Only) Maps
68 | */
69 |
70 |
71 | // 🔥 WARNING
72 |
73 |
74 | }
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter2OOP/Tutorial2_14Delegation.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter2OOP
2 |
3 |
4 | fun main() {
5 |
6 | // INFO 🔥 Implementation by Delegation
7 | val b = BaseImpl(10)
8 | Derived(b).print()
9 |
10 | // INFO 🔥 Overriding a member of an interface implemented by delegation
11 | val b2 = BaseImpl2(10)
12 | Derived2(b2).printMessage() // prints abc
13 | Derived2(b2).printMessageLine() // prints 10
14 |
15 | // INFO 🔥 Members overridden in derived class
16 | val b3 = BaseImpl3(10)
17 | val derived = Derived3(b3)
18 | derived.print() // prints BaseImpl: x = 10
19 | println("Derived message: ${derived.message}") // prints Message of Derived
20 |
21 | }
22 |
23 | // INFO 🔥 Implementation by Delegation
24 | interface Base {
25 | fun print()
26 | }
27 |
28 |
29 | class BaseImpl(val x: Int) : Base {
30 | override fun print() {
31 | println(x)
32 | }
33 | }
34 |
35 | /**
36 | * The by-clause in the supertype list for Derived indicates that b will be stored internally in objects
37 | * of Derived and the compiler will generate all the methods of Base that forward to b .
38 | */
39 | class Derived(b: Base) : Base by b
40 |
41 | // INFO 🔥 Overriding a member of an interface implemented by delegation
42 |
43 | interface Base2 {
44 | fun printMessage()
45 | fun printMessageLine()
46 | }
47 |
48 | class BaseImpl2(val x: Int) : Base2 {
49 | override fun printMessage() {
50 | println(x)
51 | }
52 |
53 | override fun printMessageLine() {
54 | println(x)
55 | }
56 | }
57 |
58 | //Overrides work as you might expect: the compiler will use your override implementations
59 | // instead of those in the delegate object.
60 | class Derived2(b: Base2) : Base2 by b {
61 | override fun printMessage() {
62 | println("abc")
63 | }
64 | }
65 |
66 | // INFO 🔥 Members overridden in derived class
67 | interface Base3 {
68 | val message: String
69 | fun print()
70 | }
71 |
72 | class BaseImpl3(val x: Int) : Base3 {
73 | override val message = "BaseImpl: x = $x"
74 | override fun print() {
75 | println(message)
76 | }
77 | }
78 |
79 | class Derived3(b: Base3) : Base3 by b {
80 | // 🔥 ⚠️ This property is not accessed from b's implementation of `print`
81 | override val message = "Message of Derived"
82 | }
83 |
84 |
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/RegularExpressionTest.java:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial;
2 |
3 | import java.util.regex.Matcher;
4 | import java.util.regex.Pattern;
5 |
6 | public class RegularExpressionTest {
7 |
8 | /*
9 | Here is the complete list of various character classes constructs:
10 | [abc]: It would match with text if the text is having either one of them(a,b or c) and only once.
11 | [^abc]: Any single character except a, b, or c (^ denote negation)
12 | [a-zA-Z]: a through z, or A through Z, inclusive (range)
13 | [a-d[m-p]]: a through d, or m through p: [a-dm-p] (union)
14 | [a-z&&[def]]: Any one of them (d, e, or f)
15 | [a-z&&[^bc]]: a through z, except for b and c: [ad-z] (subtraction)
16 | [a-z&&[^m-p]]: a through z, and not m through p: [a-lq-z] (subtraction)
17 |
18 | Predefined Character Classes – Metacharacters
19 | These are like short codes which you can use while writing regex.
20 |
21 | Construct Description
22 | . -> Any character (may or may not match line terminators)
23 | \d -> A digit: [0-9]
24 | \D -> A non-digit: [^0-9]
25 | \s -> A whitespace character: [ \t\n\x0B\f\r]
26 | \S -> A non-whitespace character: [^\s]
27 | \w -> A word character: [a-zA-Z_0-9]
28 | \W -> A non-word character: [^\w]
29 |
30 | Boundary Matchers
31 | ^ Matches the beginning of a line.
32 | $ Matches then end of a line.
33 | \b Matches a word boundary.
34 | \B Matches a non-word boundary.
35 | \A Matches the beginning of the input text.
36 | \G Matches the end of the previous match
37 | \Z Matches the end of the input text except the final terminator if any.
38 | \z Matches the end of the input text.
39 | */
40 |
41 | public void testRegex1() {
42 |
43 | // String str = "123Hello World";
44 | //
45 | // Pattern pattern = Pattern.compile("[^\\d]");
46 | // Matcher matcher = pattern.matcher(str);
47 | //
48 | // if (matcher.find()) {
49 | // System.out.println("");
50 | // }
51 |
52 | String text = "This island is beautiful";
53 |
54 | Pattern p = Pattern.compile("\\bis\\b");
55 |
56 | Matcher matcher = p.matcher(text);
57 |
58 | while (matcher.find()) {
59 | System.out.printf("%s at %d", matcher.group(), matcher.start());
60 | }
61 |
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter2OOP/Tutorial2_6Interfaces.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter2OOP
2 |
3 | fun main() {
4 |
5 | val child = Child()
6 | println("Child propertyWithImplementation ${child.propertyWithImplementation}")
7 | child.foo()
8 | child.prop = 2
9 | child.foo()
10 |
11 | /*
12 | Prints:
13 | Child propertyWithImplementation fooBar
14 | 29
15 | 2
16 | */
17 | }
18 |
19 | interface MyInterface {
20 | fun bar()
21 | fun foo() {
22 | // optional body
23 | println("MyInterface foo()")
24 | }
25 | }
26 |
27 | /*
28 | public interface MyInterface {
29 | void bar();
30 |
31 | void foo();
32 |
33 | public static final class DefaultImpls {
34 | public static void foo(@NotNull MyInterface $this) {
35 | String var1 = "MyInterface foo()";
36 | boolean var2 = false;
37 | System.out.println(var1);
38 | }
39 | }
40 | }
41 | */
42 |
43 | interface MyInterface2 {
44 |
45 | var prop: Int // abstract
46 |
47 |
48 | // INFO 🔥⚠️ This is NOT allowed: Property initializers are not allowed in interfaces
49 | // val propertyWithImplementation: String = "fooBar"
50 |
51 | // INFO 🔥⚠️ This CANNOT be var -> Property in interface cannot have a backing field
52 | // Creates a static nested class with static methodDefaultImpls.getPropertyWithImplementation
53 | val propertyWithImplementation: String
54 | get() = "fooBar"
55 |
56 | fun foo() {
57 | println(prop)
58 | }
59 |
60 | }
61 |
62 | /*
63 | public interface MyInterface2 {
64 | int getProp();
65 |
66 | void setProp(int var1);
67 |
68 | @NotNull
69 | String getPropertyWithImplementation();
70 |
71 | void foo();
72 |
73 |
74 | public static final class DefaultImpls {
75 |
76 | @NotNull
77 | public static String getPropertyWithImplementation(@NotNull MyInterface2 $this) {
78 | return "fooBar";
79 | }
80 |
81 | public static void foo(@NotNull MyInterface2 $this) {
82 | int var1 = $this.getProp();
83 | boolean var2 = false;
84 | System.out.println(var1);
85 | }
86 | }
87 | }
88 | */
89 |
90 | class Child : MyInterface2 {
91 | override var prop: Int = 29
92 | }
93 |
94 | interface Named {
95 | val name:String
96 | }
97 |
98 | interface PersonNamed:Named {
99 |
100 | val firstName:String
101 | val secondName: String
102 |
103 | override val name: String
104 | get() = "$firstName, lastName: $secondName"
105 |
106 | }
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter2OOP/mvp/BaseComponents.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter2OOP.mvp
2 |
3 | open class BaseFragment> : Fragment() {
4 |
5 | var presenter: P? = null
6 |
7 | override fun onCreate() {
8 | super.onCreate()
9 | presenter?.attachOutput()
10 | }
11 |
12 | override fun onCreateView() {
13 | super.onCreateView()
14 | println("😍 BaseFragment onCreateView()")
15 | presenter?.attachView(this as V)
16 | }
17 |
18 | override fun onDestroyView() {
19 | super.onDestroyView()
20 | println("😍 BaseFragment onDestroyView()")
21 | presenter?.detachView()
22 | }
23 |
24 | override fun onDestroy() {
25 | super.onDestroy()
26 | println("😍 BaseFragment onDestroy()")
27 | presenter?.onDestroy()
28 | }
29 | }
30 |
31 | abstract class BasePresenter(interactor: I) : BaseContract.IPresenter,
32 | BaseContract.IOutput {
33 |
34 | protected var view: V? = null
35 |
36 | protected var interactor: I?
37 |
38 | init {
39 | this.interactor = interactor
40 | }
41 |
42 | override fun attachOutput() {
43 | if (interactor is BaseInteractor<*>) {
44 | (interactor as? BaseInteractor)?.output = this
45 | }
46 | }
47 |
48 | override fun attachView(view: V) {
49 | this.view = view
50 | println("😅 BasePresenter attachView() view: $view")
51 | }
52 |
53 | override fun detachView() {
54 | println("😅 BasePresenter detachView()")
55 | view = null
56 | }
57 |
58 | override fun onDestroy() {
59 | println("😅 BasePresenter onDestroy()")
60 | interactor?.onDestroy()
61 | interactor = null
62 | }
63 |
64 |
65 | }
66 |
67 | abstract class BaseInteractor : BaseContract.IInteractor {
68 | var output: O? = null
69 |
70 | override fun onDestroy() {
71 | println("🍒 BaseInteractor onDestroy()")
72 | output = null
73 | }
74 | }
75 |
76 | /**
77 | * Mock fragment class to mock Android's Fragment with MVP
78 | */
79 | open class Fragment {
80 | open fun onCreate() {
81 | println("🔥 Fragment() onCreate()")
82 | }
83 |
84 | open fun onCreateView() {
85 | println("🌽 Fragment() onCreateView()")
86 | }
87 |
88 | open fun onDestroyView() {
89 | println("🎃 Fragment() onDestroyView()")
90 | }
91 |
92 | open fun onDestroy() {
93 | println("🍺 Fragment() onDestroy()")
94 | }
95 | }
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter4Functions/Tutorial4_4InlineFunctions.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter4Functions
2 |
3 | fun main() {
4 |
5 | // INFO 🔥 Inline Function
6 | /**********************************************/
7 | // Creates instance of lambda function instance every time invoked
8 | nonInlined {
9 | println("Hello from NON-inlined")
10 | }
11 |
12 | // only gets block inside lambda, does not create instance
13 | inlined {
14 | println("Hello from inlined")
15 | }
16 | /**********************************************/
17 |
18 | val list = arrayListOf()
19 | for (number in 1..10) {
20 | list.add(number)
21 | }
22 |
23 | // 🔥 'it' in lambda is every element that this list contains iterated one by one
24 | val resultList = list.filterOnCondition { isMultipleOf(it, 5) }
25 | println("filterOnCondition resultList : $resultList")
26 |
27 |
28 | // 🔥 'this' in lambda is every element that this list contains iterated one by one
29 | val resultListWithReceiver = list.filterWithCondition {
30 | isMultipleOf(this, 5)
31 | }
32 | println("filterWithCondition resultListWithReceiver : $resultListWithReceiver")
33 |
34 | /**********************************************/
35 | }
36 |
37 |
38 | fun nonInlined(block: () -> Unit) {
39 | println("before")
40 | block()
41 | println("after")
42 | }
43 |
44 |
45 | inline fun inlined(block: () -> Unit) {
46 | println("before")
47 | block()
48 | println("after")
49 | }
50 |
51 | /*
52 | * Gives the following warning because the inline function does not take any Function object
53 | * Expected performance impact from inlining is insignificant. Inlining works best for functions with parameters of functional types
54 | * */
55 | inline fun isMultipleOf(number: Int, multipleOf: Int): Boolean {
56 | return number % multipleOf == 0
57 | }
58 |
59 | fun ArrayList.filterOnCondition(condition: (T) -> Boolean): ArrayList {
60 | val result = arrayListOf()
61 | for (item in this) {
62 | if (condition(item)) {
63 | result.add(item)
64 | }
65 | }
66 | return result
67 | }
68 |
69 | fun ArrayList.filterWithCondition(condition: T.() -> Boolean): ArrayList {
70 | val result = arrayListOf()
71 |
72 | for (item in this) {
73 |
74 | /*
75 | 🔥 our parameter is literal with Receiver here, T.() -> Boolean
76 | so we can call condition() function on T
77 | */
78 |
79 | if (item.condition()) {
80 | result.add(item)
81 | }
82 | }
83 |
84 | return result
85 | }
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/EqualityAndHashCode.java:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial;
2 |
3 | import java.util.HashMap;
4 | import java.util.Iterator;
5 | import java.util.LinkedHashMap;
6 | import java.util.List;
7 | import java.util.Map;
8 |
9 | public class EqualityAndHashCode {
10 |
11 | static class Currency {
12 |
13 | String currencyCode;
14 |
15 | Currency(String currencyCode) {
16 | this.currencyCode = currencyCode;
17 | }
18 |
19 | @Override
20 | public boolean equals(Object obj) {
21 |
22 | if (obj == null) return false;
23 |
24 | // if (obj.getClass().equals(getClass())) {
25 | // Currency currency = (Currency) obj;
26 | // return currency.currencyCode.equals(this.currencyCode);
27 | // }
28 |
29 | if (obj instanceof Currency) {
30 | Currency currency = (Currency) obj;
31 | return currency.currencyCode.equals(this.currencyCode);
32 | }
33 | return false;
34 | }
35 |
36 | @Override
37 | public int hashCode() {
38 | return currencyCode.hashCode();
39 | }
40 | }
41 |
42 |
43 | public static void main(String[] args) {
44 |
45 | Currency currency1 = new Currency("USD");
46 |
47 | Currency currency2 = new Currency("USD");
48 |
49 | System.out.println("Currency1: " + currency1 + ", hashCode: " + currency1.hashCode());
50 | System.out.println("Currency2: " + currency2 + ", hashCode: " + currency2.hashCode());
51 |
52 | System.out.println("Currency1 equals Currency2: " + currency1.equals(currency2));
53 | // 🔥 This never returns TRUE even when both equals method and hashcode is overridden to be same
54 | // Only when both objects are same
55 | System.out.println("Currency1 == Currency2: " + (currency1 == currency2));
56 |
57 |
58 | Map rates = new HashMap<>();
59 |
60 | rates.put(currency1, 1.1);
61 |
62 | // 🔥🔥🔥Hash Map KEYS should both meet the conditions of EQUALS and same HASH CODE
63 | /*
64 | HashMap uses hashCode(), == and equals() for entry lookup.
65 | The lookup sequence for a given key k is as follows:
66 |
67 | Use k.hashCode() to determine which bucket the entry is stored, if any
68 | If found, for each entry's key k1 in that bucket, if k == k1 || k.equals(k1), then return k1's entry
69 | Any other outcomes, no corresponding entry
70 | */
71 | Double result = rates.get(currency2);
72 |
73 | System.out.println("Result: " + result);
74 |
75 |
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/TestStringConcatenation.java:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial;
2 |
3 | public class TestStringConcatenation {
4 |
5 | public static void main(String[] args) {
6 |
7 | long startTime = System.nanoTime();
8 | testStringConcat();
9 | long totalTime = System.nanoTime() - startTime;
10 |
11 | System.out.println("Total time for String concat: " + totalTime);
12 |
13 | startTime = System.nanoTime();
14 | testStringBuilder();
15 | totalTime = System.nanoTime() - startTime;
16 | System.out.println("Total time for StringBuilder: " + totalTime);
17 |
18 | }
19 |
20 | private static String testStringConcat() {
21 | return "ByteCode:ldc pushes a one-word constant onto the operand stack. ldc takes a single parameter, , which is the value to push."
22 | + "ByteCode:ldc pushes a one-word constant onto the operand stack. ldc takes a single parameter, , which is the value to push."
23 | + "ByteCode:ldc pushes a one-word constant onto the operand stack. ldc takes a single parameter, , which is the value to push."
24 | + "ByteCode:ldc pushes a one-word constant onto the operand stack. ldc takes a single parameter, , which is the value to push."
25 | + "ByteCode:ldc pushes a one-word constant onto the operand stack. ldc takes a single parameter, , which is the value to push."
26 | + "Lorem Ipsum ";
27 |
28 | }
29 |
30 |
31 | private static String testStringBuilder() {
32 |
33 | StringBuilder stringBuilder = new StringBuilder();
34 |
35 | stringBuilder.append("ByteCode:ldc pushes a one-word constant onto the operand stack. ldc takes a single parameter, , which is the value to push.");
36 | stringBuilder.append("ByteCode:ldc pushes a one-word constant onto the operand stack. ldc takes a single parameter, , which is the value to push.");
37 | stringBuilder.append("ByteCode:ldc pushes a one-word constant onto the operand stack. ldc takes a single parameter, , which is the value to push.");
38 | stringBuilder.append("ByteCode:ldc pushes a one-word constant onto the operand stack. ldc takes a single parameter, , which is the value to push.");
39 | stringBuilder.append("ByteCode:ldc pushes a one-word constant onto the operand stack. ldc takes a single parameter, , which is the value to push.");
40 |
41 | stringBuilder.append("Lorem Ipsum");
42 |
43 | return stringBuilder.toString();
44 |
45 | }
46 |
47 |
48 | interface Account {
49 |
50 | }
51 |
52 | static class BankAccount implements Account {
53 |
54 | }
55 |
56 | static class InterestAccount implements Account {
57 |
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter2OOP/mvp/user/UserFragment.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter2OOP.mvp.user
2 |
3 |
4 |
5 | import com.smarttoolfactory.tutorial.chapter2OOP.User
6 | import com.smarttoolfactory.tutorial.chapter2OOP.mvp.BaseFragment
7 | import com.smarttoolfactory.tutorial.chapter2OOP.mvp.BaseInteractor
8 | import com.smarttoolfactory.tutorial.chapter2OOP.mvp.BasePresenter
9 | import com.smarttoolfactory.tutorial.chapter2OOP.mvp.UserContract
10 | import java.util.*
11 |
12 | class UserFragment : BaseFragment(),
13 | UserContract.UserView {
14 |
15 | init {
16 | presenter = InitUserFragment.initUserModule()
17 | }
18 |
19 | override fun onCreate() {
20 | super.onCreate()
21 | println("😍 UserFragment onCreate()")
22 | }
23 |
24 | override fun onCreateView() {
25 | super.onCreateView()
26 | presenter?.fetchUsers()
27 | }
28 |
29 | override fun displayUser(users: List) {
30 | for (i in users.indices) {
31 | val user = users[i]
32 | println("🔥🔥 UserFragment displayUser() USER: " + user.fullName)
33 | }
34 | }
35 |
36 | override fun displayError(message: String?) {}
37 |
38 | internal object InitUserFragment {
39 | fun initUserModule(): UserContract.UserPresenter {
40 | val userInteractor: UserContract.UserInteractor = UserInteractor()
41 | return UserPresenter(userInteractor)
42 | }
43 | }
44 | }
45 |
46 |
47 | class UserPresenter(interactor: UserContract.UserInteractor) :
48 | BasePresenter(interactor), UserContract.UserPresenter,
49 | UserContract.UserOutput {
50 |
51 | override fun fetchUsers() {
52 | interactor?.fetchUsersFromNetwork()
53 | }
54 |
55 | override fun onUsersFetched(users: List) {
56 | view?.displayUser(users)
57 | }
58 |
59 | override fun onErrorOccurred(message: String) {
60 | view?.displayError(message)
61 | }
62 | }
63 |
64 | class UserInteractor : BaseInteractor(), UserContract.UserInteractor {
65 |
66 | override fun fetchUsersFromNetwork() {
67 | val userList = GetUsers.users
68 | output?.onUsersFetched(userList)
69 | println("🤩 UserInteractor fetchUsersFromNetwork() userList: $userList")
70 | }
71 |
72 | internal object GetUsers {
73 | val users: List
74 | get() {
75 | val userList: MutableList = ArrayList()
76 | val user = User("John", "Smith")
77 | userList.add(user)
78 | return userList
79 | }
80 | }
81 | }
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter2OOP/Tutorial2_4Inheritance.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter2OOP
2 |
3 |
4 | fun main() {
5 |
6 | // val derived = Derived("Foo", "Bar")
7 |
8 | // Class with interface and base class
9 | // val c = C()
10 | // // INFO 🔥 f() method calls super method of Class BaseClassA and Interface InterfaceB
11 | // c.f()
12 |
13 | val sportsCar = SportsCar()
14 |
15 | println("SportsCar type: ${sportsCar.type}, manufacturer: ${sportsCar.manufacturer}")
16 |
17 | val resultSuccess = Result.Success(3)
18 | val resultError = Result.Error(IllegalArgumentException("Exception"))
19 |
20 | val resultBoxed = getResult("Hello World", 2)
21 |
22 | when (resultBoxed) {
23 | is Result.Success -> println("Result: ${resultBoxed.data}")
24 | is Result.Error -> println("Error: ${resultBoxed.exception.message}")
25 | }
26 |
27 | val bus = Bus("Ford")
28 |
29 | bus.printMaker()
30 | /*
31 | Prints Ford
32 | */
33 |
34 | println("Manufacturer: ${(bus as Vehicle).manufacturer}")
35 | /*
36 | Prints Ford
37 | */
38 |
39 | }
40 |
41 | fun getResult(data: T, index: Int): Result {
42 | return if (index < 0) {
43 | Result.Error(IllegalAccessException("Number cannot be smaller than 0"))
44 | } else {
45 | Result.Success(data)
46 | }
47 | }
48 |
49 |
50 | sealed class VehicleType {
51 | data class CarType(val type: Int) : VehicleType()
52 | data class BusType(val type: Int) : VehicleType()
53 | }
54 |
55 | sealed class Result {
56 | data class Success(val data: T) : Result()
57 | data class Error(val exception: Exception) : Result()
58 | }
59 |
60 | open class Vehicle(var type: VehicleType, open var manufacturer: String)
61 |
62 | class SportsCar : Vehicle(VehicleType.CarType(1), "Tesla")
63 |
64 | /**
65 | *
66 | */
67 | class Bus(override var manufacturer: String) :
68 | Vehicle(VehicleType.BusType(2), "$manufacturer + Bus") {
69 |
70 | fun printMaker() {
71 | println("Maker: $manufacturer, super manufacturer: ${super.manufacturer}")
72 | }
73 | }
74 |
75 | /*
76 | @NotNull
77 | private String manufacturer;
78 |
79 | public final void printMaker() {
80 | String var1 = "Maker: " + this.getManufacturer();
81 | boolean var2 = false;
82 | System.out.println(var1);
83 | }
84 |
85 | @NotNull
86 | public String getManufacturer() {
87 | return this.manufacturer;
88 | }
89 |
90 | public void setManufacturer(@NotNull String var1) {
91 | this.manufacturer = var1;
92 | }
93 |
94 | public Bus(@NotNull String manufacturer) {
95 | super((VehicleType)(new VehicleType.BusType(2)), manufacturer + " + Bus");
96 | this.manufacturer = manufacturer;
97 | }
98 | */
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter1Basics/Tutorial1_6Function1.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter1Basics
2 |
3 | fun main() {
4 |
5 | // INFO Default Argument Functions
6 | println(myFunction("Earth"))
7 | println(myFunction2())
8 |
9 | foo(1) { println("hello") } // Uses the default value baz = 1
10 | foo(qux = { println("hello") }) // Uses both default values bar = 0 and baz = 1
11 | foo { println("hello") } // Uses both default values bar = 0 and baz = 1
12 |
13 | // INFO Named Function
14 | namedFunc(number = 4)
15 |
16 | // INFO Single Expression Function
17 |
18 | // INFO Vararg Function
19 | val myList = asList("1", "2", "3")
20 | myList.forEach { it -> println("List $it") }
21 |
22 | // INFO Infix Notation Function
23 | infix fun Int.shl(x: Int): Int {
24 | return x * 2;
25 | }
26 |
27 | // calling the function using the infix notation
28 | 1 shl 2
29 | // is the same as
30 | 1.shl(2)
31 |
32 | infix fun String.sameAs(x: String): Boolean {
33 | return this == x
34 | }
35 |
36 | val isThisTrue = "Obj" sameAs "Obj"
37 |
38 | println("🎃 Infix result $isThisTrue")
39 |
40 | // INFO Tail Recursive Function
41 |
42 | println("Factorial result: ${fact(5)}")
43 |
44 | }
45 |
46 | /**
47 | * myFunction has x as parameter and returns a String defined with : String as return type
48 | */
49 | fun myFunction(x: String): String {
50 | val c: String = "Hey!! Welcome To ---"
51 | return (c + x)
52 | }
53 |
54 | // INFO Default Arguments
55 | /**
56 | * Function parameters can have default values, which are used when a corresponding argument is omitted.
57 | * This allows for a reduced number of overloads compared to other languages:
58 | */
59 | fun myFunction2(x: String = "Universe"): String {
60 | val c: String = "Hey!! Welcome To ---"
61 | return (c + x)
62 | }
63 |
64 | fun read(b: Array, off: Int = 0, len: Int = b.size) {
65 | // Do some stuff...
66 | }
67 |
68 | // bar = 0, and baz = 1 are the default values.
69 | fun foo(bar: Int = 0, baz: Int = 1, qux: () -> Unit) {
70 | println("foo() bar: $bar, baz: $baz")
71 | }
72 |
73 | // INFO Named Arguments
74 | fun namedFunc(number: Int = 5, text: String = "Empty") {
75 | println("Number $number, text: $text")
76 | }
77 |
78 | // INFO Single Expression
79 | fun double(x: Int): Int = x * 2
80 |
81 | // Explicitly declaring the return type is optional when this can be inferred by the compiler:
82 | fun double2(x: Int) = x * 2
83 |
84 | // INFO Vargarg Arguments
85 | fun asList(vararg ts: T): List {
86 | val result = ArrayList()
87 | for (t in ts) // ts is an Array
88 | result.add(t)
89 | return result
90 | }
91 |
92 |
93 | // INFO Tail Recursive
94 |
95 | // Recursive function that is optimized with tailRec keyword
96 | fun fact(x: Int): Int {
97 |
98 | tailrec fun factTail(y: Int, z: Int): Int {
99 | println("FactTail x: $x, y: $y, z: $z")
100 | return if (y == 1) z else factTail(y - 1, y * z)
101 | }
102 |
103 | return factTail(x, 1)
104 |
105 | }
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 | @rem SPDX-License-Identifier: Apache-2.0
17 | @rem
18 |
19 | @if "%DEBUG%"=="" @echo off
20 | @rem ##########################################################################
21 | @rem
22 | @rem Gradle startup script for Windows
23 | @rem
24 | @rem ##########################################################################
25 |
26 | @rem Set local scope for the variables with windows NT shell
27 | if "%OS%"=="Windows_NT" setlocal
28 |
29 | set DIRNAME=%~dp0
30 | if "%DIRNAME%"=="" set DIRNAME=.
31 | @rem This is normally unused
32 | set APP_BASE_NAME=%~n0
33 | set APP_HOME=%DIRNAME%
34 |
35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
37 |
38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
40 |
41 | @rem Find java.exe
42 | if defined JAVA_HOME goto findJavaFromJavaHome
43 |
44 | set JAVA_EXE=java.exe
45 | %JAVA_EXE% -version >NUL 2>&1
46 | if %ERRORLEVEL% equ 0 goto execute
47 |
48 | echo. 1>&2
49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
50 | echo. 1>&2
51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
52 | echo location of your Java installation. 1>&2
53 |
54 | goto fail
55 |
56 | :findJavaFromJavaHome
57 | set JAVA_HOME=%JAVA_HOME:"=%
58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
59 |
60 | if exist "%JAVA_EXE%" goto execute
61 |
62 | echo. 1>&2
63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
64 | echo. 1>&2
65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2
66 | echo location of your Java installation. 1>&2
67 |
68 | goto fail
69 |
70 | :execute
71 | @rem Setup the command line
72 |
73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
74 |
75 |
76 | @rem Execute Gradle
77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
78 |
79 | :end
80 | @rem End local scope for the variables with windows NT shell
81 | if %ERRORLEVEL% equ 0 goto mainEnd
82 |
83 | :fail
84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
85 | rem the _cmd.exe /c_ return code!
86 | set EXIT_CODE=%ERRORLEVEL%
87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
89 | exit /b %EXIT_CODE%
90 |
91 | :mainEnd
92 | if "%OS%"=="Windows_NT" endlocal
93 |
94 | :omega
95 |
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter7Threading/ReentrantLock.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter7Threading
2 |
3 | import java.util.concurrent.locks.ReentrantLock
4 |
5 | /**
6 | * 1) If Thread1 accesses lock before Thread2, since [ReentrantLock.lock] locks it multiple times,
7 | * Thread2 is dead locked.
8 | *
9 | * 2) If Thread2 accesses lock before Thread1, Thread2 access program main thread that is waiting
10 | * threads because of join ends successfully.
11 | */
12 | fun main() {
13 |
14 | val lock = ReentrantLock()
15 |
16 | val thread1 = Thread {
17 |
18 | println(
19 | "1st START Lock in thread: ${Thread.currentThread().name}, " +
20 | "lock held by current thread: ${lock.isHeldByCurrentThread}"
21 | )
22 | lock.lock()
23 | lock.lock()
24 | println(
25 | "1st GOT Lock in thread: ${Thread.currentThread().name}, " +
26 | "lock held by this thread: ${lock.isHeldByCurrentThread}, " +
27 | "hold count: ${lock.holdCount}, " +
28 | "queue: ${lock.queueLength}"
29 | )
30 | Thread.sleep(4500)
31 | lock.unlock()
32 | println(
33 | "1st Unlock in thread: ${Thread.currentThread().name}, " +
34 | "lock held by current thread: ${lock.isHeldByCurrentThread}, " +
35 | "hold count: ${lock.holdCount}, " +
36 | "queue: ${lock.queueLength}"
37 | )
38 | }
39 |
40 | val thread2 = Thread {
41 | println(
42 | "2nd START Lock in thread: ${Thread.currentThread().name}, " +
43 | "lock held by current thread: ${lock.isHeldByCurrentThread}"
44 | )
45 | lock.lock()
46 | println(
47 | "2nd GOT Lock in thread: ${Thread.currentThread().name}, " +
48 | "lock held by this thread: ${lock.isHeldByCurrentThread}, " +
49 | "hold count: ${lock.holdCount}, " +
50 | "queue: ${lock.queueLength}"
51 | )
52 | Thread.sleep(900)
53 | lock.unlock()
54 | println(
55 | "2nd Unlock in thread: ${Thread.currentThread().name}, " +
56 | "lock held by current thread: ${lock.isHeldByCurrentThread}, " +
57 | "hold count: ${lock.holdCount}, " +
58 | "queue: ${lock.queueLength}"
59 | )
60 | }
61 |
62 | // logStates(thread1, thread2, lock)
63 |
64 | thread1.start()
65 | thread2.start()
66 |
67 | thread1.join()
68 | thread2.join()
69 |
70 | println("Program finishing")
71 | }
72 |
73 | private fun logStates(
74 | thread1: Thread,
75 | thread2: Thread,
76 | lock: ReentrantLock
77 | ) {
78 | val mainThread = Thread.currentThread()
79 |
80 | Thread {
81 | var counter = 0
82 |
83 | while (counter < 100) {
84 |
85 | println(
86 | "Thread1 state: ${thread1.state}, Thread2 state: ${thread2.state}, mainThread state: ${mainThread.state}, " +
87 | "lock count for this thread: ${lock.holdCount}, queue length: ${lock.queueLength}"
88 | )
89 | Thread.sleep(50)
90 | counter++
91 | }
92 | }.start()
93 | }
94 |
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter3Other/Tutorial3_8FunctionLiteralsWithReceiver.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter3Other
2 |
3 | fun main() {
4 |
5 | // INFO 🔥 High Order Function
6 |
7 | val test = createString(5, {
8 | println("createTest() $it")
9 | it * 2
10 | })
11 |
12 | println("test: $test")
13 |
14 | val test2 = createString(4, {
15 | it / 2
16 | })
17 |
18 | println("Test2 $test2")
19 |
20 |
21 | // {} = block: (StringBuilder) -> Unit
22 | val stringFromHighOrder = createStringFromStringBuilder({
23 | it.append(4)
24 | it.append("Hello")
25 | })
26 |
27 |
28 | val stringFromHighOrder2 = createStringFromStringBuilder(lambdaString("Hello", "World"))
29 | println("stringFromHighOrder2: $stringFromHighOrder2")
30 |
31 | println("stringFromHighOrder $stringFromHighOrder")
32 |
33 |
34 | // INFO 🔥 Function Literal with Receiver
35 |
36 | // Function Literal with Receiver
37 | val stringFromLiteralWithReceiver = createStringWithLiteral({
38 | append(4)
39 | append("hello")
40 | })
41 |
42 |
43 | // Function Literal with Receiver without Parenthesis
44 | val stringFromLiteralWithReceiver2 = createStringWithLiteral {
45 |
46 | //here we're in the context of a `StringBuilder`
47 | append(4)
48 | append("hello")
49 | // functions inside {} are basically call to sb.block() in function body
50 | }
51 | println("stringFromLiteralWithReceiver2: $stringFromLiteralWithReceiver2")
52 |
53 | // INFO 🔥 Extension Function Literal with Receiver
54 | val sb = StringBuilder()
55 | val sbNew = sb.extra({
56 |
57 | })
58 |
59 | sb.extra {
60 |
61 | }
62 |
63 | val ch = sbNew.extra2(3) {
64 | val num = it * 2
65 | num
66 | }
67 |
68 | }
69 |
70 | // INFO 🔥 High Order Functions
71 | fun createString(value: Int, block: (Int) -> Int): String {
72 | return block(value * value).toString()
73 | }
74 |
75 | fun createStringFromStringBuilder(block: (StringBuilder) -> Unit): String {
76 | val sb = StringBuilder()
77 | block(sb) // 🔥 This CAN NOT be sb.block()
78 | return sb.toString()
79 | }
80 |
81 | // Lambda function to pass as parameter to high-order function
82 | fun lambdaString(vararg texts: String): (StringBuilder) -> Unit = {
83 | texts.forEach { text ->
84 | it.append(text)
85 | }
86 |
87 |
88 | }
89 |
90 | // INFO 🔥 Function Literal with Receiver
91 | // StringBuilder.() sets this function as extension function of StringBuilder class
92 | // receiver is defined as StringBuilder
93 | fun createStringWithLiteral(block: StringBuilder.() -> Unit): String {
94 |
95 | val sb = StringBuilder() // create the receiver object
96 | sb.block() // 🔥 This can also be block(sb)
97 |
98 | // pass the receiver object to the lambda
99 |
100 | return sb.toString()
101 | }
102 |
103 |
104 |
105 | // INFO 🔥 Extension Function Literal with Receiver
106 | /**
107 | * This function is extension function of [StringBuilder] class by [StringBuilder]. before function name.
108 | *
109 | * It takes a block parameter which is a function literal receiver which returns StringBuilder instance
110 | * in function implementation
111 | */
112 | fun StringBuilder.extra(block: StringBuilder.() -> Unit): StringBuilder {
113 | block()
114 | return this
115 | }
116 |
117 | fun StringBuilder.extra2(value: Int, block: (Int) -> Int): StringBuilder {
118 | block(value)
119 | return this
120 | }
121 |
122 |
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter2OOP/Tutorial2_8Extensions.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter2OOP
2 |
3 | fun main() {
4 |
5 | // INFO 🔥 Extension function
6 | val testString: String = "Hello World "
7 | println("Test ${testString.upperCaseAndTrim()}")
8 |
9 | val list = mutableListOf();
10 | list.add(1)
11 | list.add(2)
12 | list.add(3)
13 |
14 | list.swap(0, 1)
15 | list.forEach { it -> println("it $it") }
16 |
17 | // INFO 🔥 Extensions are resolved statically
18 | printFoo(D())
19 | // calls member function
20 | Cex().foo()
21 |
22 | // INFO 🔥 Overloaded extension function will call suitable overloaded function
23 | CExtension().foo(1) // prints extension
24 |
25 | // INFO 🔥 Companion Object Extensions
26 | MyClass.foo()
27 |
28 | // INFO 🔥 Declaring Extensions as Members
29 | val f = F()
30 | f.caller(G())
31 |
32 |
33 | }
34 |
35 | // INFO 🔥 Extension function
36 |
37 | fun String.upperCaseAndTrim(): String {
38 | // INFO The this keyword inside an extension function corresponds to the receiver object
39 | return this.uppercase().trim()
40 | }
41 |
42 | fun MutableList.swap(index1: Int, index2: Int) {
43 | val tmp = this[index1] // 'this' corresponds to the list this[index1] = this[index2]
44 | this[index2] = tmp
45 | }
46 |
47 |
48 | // INFO 🔥 Extensions are resolved statically
49 | open class C
50 |
51 | class D : C()
52 |
53 | fun C.foo() = "c"
54 | fun D.foo() = "d"
55 |
56 | fun printFoo(c: C) {
57 | println(c.foo())
58 | }
59 |
60 | // INFO 🔥 calls member function instead of extension
61 | class Cex {
62 | fun foo() {
63 | println("member")
64 | }
65 | }
66 |
67 | /*
68 | If a class has a member function, and an extension function is defined
69 | which has the same receiver type, the same name is applicable to given arguments,
70 | the member always wins. For example:
71 | 🔥 invoking foo() calls MEMBER not EXTENSION function
72 | */
73 | fun Cex.foo() {
74 | println("extension")
75 | }
76 |
77 | // INFO 🔥 Overloaded extension function
78 | class CExtension {
79 | fun foo() {
80 | println("member")
81 | }
82 | }
83 |
84 | fun CExtension.foo(i: Int) {
85 | println("extension")
86 | }
87 |
88 | /*
89 | Note that extensions can be defined with a nullable receiver type.
90 | Such extensions can be called on an object variable even if its value is null,
91 | and can check for this == null inside the body.
92 | This is what allows you to call toString() in Kotlin without checking for null:
93 | the check happens inside the extension function.
94 | */
95 | fun Any?.toString(): String {
96 | if (this == null) return "null"
97 | // after the null check, 'this' is autocast to a non-null type, so the toString()
98 | // below resolves to the member function of the Any class
99 | return toString()
100 | }
101 |
102 | // INFO 🔥 Extension Properties
103 | val List.lastIndex: Int
104 | get() = size - 1
105 |
106 | // INFO 🔥 Companion Object Extensions
107 | class MyClass {
108 | companion object {} // will be called "Companion"
109 | }
110 |
111 | fun MyClass.Companion.foo() {
112 | println("MyClass.Companion.foo()")
113 | }
114 |
115 |
116 | // INFO 🔥 Declaring Extensions as Members
117 | class G {
118 | fun bar() {
119 | println("G bar()")
120 | }
121 | }
122 |
123 | class F {
124 | fun baz() {
125 | println("F baz()")
126 | }
127 |
128 | fun G.foo() {
129 | bar() // calls G.bar
130 | baz() // calls F.baz
131 | }
132 |
133 | fun caller(g: G) {
134 | g.foo()
135 | }
136 | }
137 |
138 |
139 |
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter2OOP/Tutorial2_15Singleton.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter2OOP
2 |
3 | import java.lang.Thread.sleep
4 |
5 |
6 | fun main() {
7 |
8 | val firstSingleton = Singleton
9 | sleep(1200)
10 | firstSingleton.printName()
11 | val secondSingleton = Singleton
12 | secondSingleton.name = "Hello World"
13 | firstSingleton.printName()
14 |
15 | println(
16 | "firstSingleton: $firstSingleton, secondSingleton: $secondSingleton," +
17 | " firstSingleton == secondSingleton ${firstSingleton == secondSingleton}"
18 | )
19 |
20 | /*
21 | Prints:
22 |
23 | Singleton class invoked.
24 | Kotlin Objects
25 | Hello World
26 | firstSingleton: chapter2OOP.Singleton@1d44bcfa, secondSingleton: chapter2OOP.Singleton@1d44bcfa, firstSingleton == secondSingleton true
27 | */
28 |
29 | val mySingleton1 = SingletonWithCompanion.createRandomClazz()
30 | val mySingleton2 = SingletonWithCompanion.createRandomClazz()
31 |
32 | println(
33 | "firstSingleton: $mySingleton1, secondSingleton: $mySingleton2," +
34 | " firstSingleton == secondSingleton ${mySingleton1 == mySingleton2}"
35 | )
36 | /*
37 | Prints:
38 |
39 | firstSingleton: chapter2OOP.RandomClass@7852e922, secondSingleton: chapter2OOP.RandomClass@4e25154f, firstSingleton == secondSingleton false
40 | */
41 |
42 | }
43 |
44 | fun otherMethod() {
45 | Singleton.name = "Test"
46 | }
47 | fun someMethod() {
48 | val s = Singleton
49 | }
50 |
51 | object Singleton {
52 |
53 | init {
54 | println("Singleton class invoked.")
55 | }
56 |
57 | var name = "Kotlin Objects"
58 |
59 | @JvmStatic
60 | fun printName() {
61 | println(name)
62 | }
63 | }
64 |
65 | /*
66 | JAVA counterpart from decompiling
67 |
68 | public final class Singleton {
69 |
70 | static {
71 | Singleton var0 = new Singleton();
72 | INSTANCE = var0;
73 | String var1 = "Singleton class invoked.";
74 | boolean var2 = false;
75 | System.out.println(var1);
76 | name = "Kotlin Objects";
77 | }
78 |
79 | @NotNull
80 | private static String name;
81 | public static final Singleton INSTANCE;
82 |
83 | @NotNull
84 | public final String getName() {
85 | return name;
86 | }
87 |
88 | public final void setName(@NotNull String var1) {
89 | Intrinsics.checkParameterIsNotNull(var1, "");
90 | name = var1;
91 | }
92 |
93 | @JvmStatic
94 | public static final void printName() {
95 | String var1 = name;
96 | boolean var2 = false;
97 | System.out.println(var1);
98 | }
99 |
100 | private Singleton() {
101 | }
102 | }
103 | */
104 |
105 | class SingletonWithCompanion {
106 |
107 | companion object Factory {
108 |
109 | /**
110 | * This method does not create Singleton objects
111 | */
112 | fun createRandomClazz(): RandomClass = RandomClass()
113 | }
114 | }
115 |
116 |
117 | /*
118 | public final class SingletonWithCompanion {
119 | @NotNull
120 | public static final SingletonWithCompanion.Factory Factory = new SingletonWithCompanion.Factory((DefaultConstructorMarker)null);
121 |
122 |
123 | public static final class Factory {
124 | @NotNull
125 | public final RandomClass createRandomClazz() {
126 | return new RandomClass();
127 | }
128 |
129 | private Factory() {
130 | }
131 |
132 | // $FF: synthetic method
133 | public Factory(DefaultConstructorMarker $constructor_marker) {
134 | this();
135 | }
136 | }
137 | }
138 |
139 | */
140 |
141 | class RandomClass
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter2OOP/model/InheritanceModels2.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter2OOP.model
2 |
3 | fun main() {
4 | val employee = Employee()
5 | println(employee.baseSalary) // 30000.0
6 |
7 | val programmer = Programmer()
8 | println(programmer.baseSalary) // 50000.0
9 | }
10 |
11 | // 🔥 INFO Overriding Properties
12 |
13 | abstract class Account(initialAmount: Double) {
14 | open var baseAmount = initialAmount
15 | }
16 |
17 | class PrivateAccount(initial: Double) : Account(initial) {
18 | fun displayValue() {
19 | println("PrivateAccount Parent super.baseAmount: ${super.baseAmount}, derived: $baseAmount")
20 | }
21 | }
22 |
23 | class BusinessAccount(base: Double) : Account(base) {
24 |
25 | //🔥 INFO When you override a property or a member function of a super class,
26 | // the super class implementation
27 | // is shadowed by the child class implementation.
28 | // You can access the properties and functions of the super class using super() keyword.
29 |
30 | override var baseAmount: Double = 0.0
31 | set(value) {
32 | field = value * 3
33 | }
34 |
35 |
36 | fun displayValue() {
37 | println("BusinessAccount Parent super.baseAmount: ${super.baseAmount}, derived: $baseAmount")
38 | }
39 | }
40 |
41 | // Overriding a value returns a different value than parent has
42 | class UnionAccount(override var baseAmount: Double) : Account(baseAmount) {
43 |
44 | fun setBase(amount: Double) {
45 | baseAmount = amount
46 | }
47 |
48 | var unionProperty: String = ""
49 | set(value) {
50 | field = "$value $baseAmount"
51 | }
52 |
53 | fun displayValue() {
54 | println("UnionAccount Parent super.baseAmount: ${super.baseAmount}, derived: $baseAmount")
55 | }
56 | }
57 |
58 | /*
59 |
60 | public final class UnionAccount extends Account {
61 | @NotNull
62 | private String unionProperty;
63 | private double baseAmount;
64 |
65 | public final void setBase(double amount) {
66 | this.setBaseAmount(amount);
67 | }
68 |
69 | @NotNull
70 | public final String getUnionProperty() {
71 | return this.unionProperty;
72 | }
73 |
74 | public final void setUnionProperty(@NotNull String value) {
75 | this.unionProperty = value + ' ' + this.getBaseAmount();
76 | }
77 |
78 | public final void displayValue() {
79 | String var1 = "UnionAccount Parent super.baseAmount: " + super.getBaseAmount() + ", derived: " + this.getBaseAmount();
80 | System.out.println(var1);
81 | }
82 |
83 | public double getBaseAmount() {
84 | return this.baseAmount;
85 | }
86 |
87 | public void setBaseAmount(double var1) {
88 | this.baseAmount = var1;
89 | }
90 |
91 | public UnionAccount(double baseAmount) {
92 | super(baseAmount);
93 | this.baseAmount = baseAmount;
94 | this.unionProperty = "";
95 | }
96 | }
97 |
98 | */
99 |
100 | open class Employee {
101 | // Use "open" modifier to allow child classes to override this property
102 | open val baseSalary: Double = 30000.0
103 | }
104 |
105 | class Programmer : Employee() {
106 | // Use "override" modifier to override the property of base class
107 | override val baseSalary: Double = 50000.0
108 | }
109 |
110 | interface AnimalBase {
111 | // 🔥 Implementing class MUST override this
112 | var MAX_AGE: Int
113 |
114 | fun makeSound(): String
115 |
116 | fun doMove(): String
117 | }
118 |
119 | class Snake : AnimalBase {
120 |
121 | // Has to be overriden
122 | override var MAX_AGE = 7
123 |
124 | override fun doMove() = "Slithers"
125 |
126 | override fun makeSound() = "Hisses"
127 | }
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter7Threading/Tutorial7_3SynchronizedBlock.kt:
--------------------------------------------------------------------------------
1 | @file:OptIn(ExperimentalTime::class, ExperimentalTime::class)
2 |
3 | package com.smarttoolfactory.tutorial.chapter7Threading
4 |
5 | import kotlin.random.Random
6 | import kotlin.time.ExperimentalTime
7 | import kotlin.time.measureTime
8 |
9 | fun main() {
10 | /**
11 | * This one takes more than 4 seconds because we lock addToFirstList and
12 | * addSecondList with same lock, SingleLockedObject, instance(this) because of that
13 | * while lock is acquired while addingFirstList second list is locked as well
14 | */
15 | // val singleLockedObject = SingleLockedObject()
16 | // singleLockedObject.start()
17 |
18 | /**
19 | * Takes about 2.5s
20 | */
21 | val multipleLockedObject = MultipleLockedObject()
22 | multipleLockedObject.start()
23 |
24 | }
25 |
26 |
27 | class SingleLockedObject {
28 | private val list1 = mutableListOf()
29 | private val list2 = mutableListOf()
30 |
31 | @Synchronized
32 | private fun addToFirstList() {
33 | Thread.sleep(1)
34 | list1.add(Random.nextInt(100))
35 | // println("🍏 addToFirstList-> Thread: ${Thread.currentThread().name}")
36 | }
37 |
38 | @Synchronized
39 | private fun addToSecondList() {
40 | Thread.sleep(1)
41 | list2.add(Random.nextInt(100))
42 | // println("🍎 addToSecondList-> Thread: ${Thread.currentThread().name}")
43 | }
44 |
45 | fun start() {
46 | val time = measureTime {
47 | val thread1 = Thread {
48 | process()
49 | }
50 | val thread2 = Thread {
51 | process()
52 | }
53 |
54 | thread1.start()
55 | thread2.start()
56 |
57 | thread1.join()
58 | thread2.join()
59 | }
60 |
61 | println("😆 Total time: $time, list1: ${list1.size}, list2: ${list2.size}")
62 |
63 | }
64 |
65 | private fun process() {
66 | for (i in 0..999) {
67 | addToFirstList()
68 | addToSecondList()
69 | }
70 | }
71 | }
72 |
73 | class MultipleLockedObject {
74 | private val list1 = mutableListOf()
75 | private val list2 = mutableListOf()
76 |
77 | private val lock1 = Any()
78 | private val lock2 = Any()
79 |
80 |
81 | private fun addToFirstList() {
82 | /**
83 | * While this lock is acquired no other thread can run this but can run
84 | * other function with lock2
85 | */
86 | synchronized(lock1){
87 | Thread.sleep(1)
88 | list1.add(Random.nextInt(100))
89 | // println("🍏 addToFirstList-> Thread: ${Thread.currentThread().name}")
90 | }
91 | }
92 |
93 | private fun addToSecondList() {
94 | /**
95 | * While this lock is acquired no other thread can run this but can run
96 | * other function with lock1
97 | */
98 | synchronized(lock2){
99 | Thread.sleep(1)
100 | list2.add(Random.nextInt(100))
101 | // println("🍎 addToSecondList-> Thread: ${Thread.currentThread().name}")
102 | }
103 | }
104 |
105 | fun start() {
106 | val time = measureTime {
107 | val thread1 = Thread {
108 | process()
109 | }
110 | val thread2 = Thread {
111 | process()
112 | }
113 |
114 | thread1.start()
115 | thread2.start()
116 |
117 | thread1.join()
118 | thread2.join()
119 | }
120 |
121 | println("😆 Total time: $time, list1: ${list1.size}, list2: ${list2.size}")
122 |
123 | }
124 |
125 | private fun process() {
126 | for (i in 0..999) {
127 | addToFirstList()
128 | addToSecondList()
129 | }
130 | }
131 | }
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter1Basics/Tutorial1_5ControlFlow.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter1Basics
2 |
3 | import java.util.*
4 |
5 | fun main() {
6 |
7 | // 🔥 INFO Prints from 0 to 5
8 | for (i in 0..5) {
9 | println("Index: $i")
10 | }
11 |
12 | // This list does not have remove and methods
13 | val daysOfWeek: List =
14 | listOf("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday")
15 |
16 | println("List item get 3rd: ${daysOfWeek.get(2)}")
17 |
18 |
19 | // For each like loop
20 | for (day in daysOfWeek) {
21 | println("Day: $day")
22 | }
23 |
24 | // 🔥 INFO For loop with INDEX and VALUES
25 | for ((index, value) in daysOfWeek.withIndex()) {
26 | println("Day withIndex: #$index: $value")
27 | }
28 |
29 | // ----- LOOPING -----
30 | // You can use for loops to cycle through arrays
31 | // ranges, or anything else that implements the
32 | // iterator function
33 |
34 | // ends at 10
35 | for (x in 1..10) {
36 | println("Loop in range 1..10 : $x")
37 | }
38 |
39 | // ends at 9
40 | for (x in 1 until 10) {
41 | println("Loop in range 1 until 10 : $x")
42 |
43 | }
44 |
45 | // Generate a random number from 1 to 50
46 | val rand = Random()
47 | val magicNum = rand.nextInt(50) + 1
48 |
49 | // While loops while a condition is true
50 | var guess = 0
51 |
52 | while (magicNum != guess) {
53 | guess += 1
54 | }
55 |
56 | println("Magic num is $magicNum and you guessed $guess")
57 |
58 | for (x in 1..20) {
59 |
60 | println("Loop before continue $x")
61 | if (x % 2 == 0) {
62 | // Continue jumps back to the top of the loop
63 | continue
64 | }
65 |
66 | println("Odd : $x")
67 |
68 | // Break jumps out of the loop and stops looping
69 | if (x == 15) break
70 |
71 | }
72 |
73 | /*
74 | Loop through Arrays
75 | */
76 | val array: Array = arrayOf(3, 6, 9)
77 |
78 | // Iterate for indexes
79 | for (i in array.indices) {
80 | println("Mult 3 : ${array[i]}")
81 | }
82 |
83 | // Output indexes
84 | for ((index, value) in array.withIndex()) {
85 | println("Index : $index & Value : $value")
86 | }
87 |
88 | val testArray = IntArray(4)
89 |
90 | testArray.forEachIndexed { index, value ->
91 | println("forEachIndexed: index: $index, value: $value")
92 | }
93 |
94 | /*
95 | Returns and jumps
96 | */
97 |
98 | // 🔥 Break and continue labels
99 |
100 | breakFunction()
101 |
102 |
103 | returnUnreachableFun()
104 |
105 | returnReachableFun()
106 |
107 | returnReachableFun2()
108 | }
109 |
110 | private fun breakFunction() {
111 | loop@ for (i in 1..100) {
112 | for (j in 1..100) {
113 | if (j == 10) break@loop
114 | println("Loop break i: $i, j: $j")
115 | }
116 | }
117 |
118 | println("END OF breakFunction()")
119 | }
120 | private fun returnUnreachableFun() {
121 | listOf(1, 2, 3, 4, 5).forEach {
122 | if (it == 3) return // non-local return directly to the caller of foo()
123 | println("returnUnreachableFun() it: $it")
124 | }
125 | println("this point is unreachable")
126 | }
127 |
128 | private fun returnReachableFun() {
129 | listOf(1, 2, 3, 4, 5).forEach {
130 | // This is equivalent of continue for
131 | if (it == 3) return@forEach // local return to the caller of the lambda - the forEach loop
132 | println("returnReachableFun() it: $it")
133 | }
134 | println(" done with implicit label")
135 | }
136 |
137 | private fun returnReachableFun2() {
138 | run lit@{
139 | listOf(1, 2, 3, 4, 5).forEach {
140 | // This is equivalent of break for
141 | if (it == 3) return@lit // local return to the caller of the lambda - the forEach loop
142 | println("Inside run lit@{} it: $it")
143 | }
144 | }
145 | println("🔥 done with implicit label")
146 | }
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter5Coroutines/Tutorial5_5Flow3.kt:
--------------------------------------------------------------------------------
1 | @file:OptIn(ExperimentalCoroutinesApi::class)
2 |
3 | package com.smarttoolfactory.tutorial.chapter5Coroutines
4 |
5 | import kotlinx.coroutines.ExperimentalCoroutinesApi
6 | import kotlinx.coroutines.InternalCoroutinesApi
7 | import kotlinx.coroutines.delay
8 | import kotlinx.coroutines.flow.asFlow
9 | import kotlinx.coroutines.flow.flatMapConcat
10 | import kotlinx.coroutines.flow.flatMapLatest
11 | import kotlinx.coroutines.flow.flatMapMerge
12 | import kotlinx.coroutines.flow.merge
13 | import kotlinx.coroutines.flow.onEach
14 | import kotlinx.coroutines.runBlocking
15 |
16 |
17 | @InternalCoroutinesApi
18 | fun main() = runBlocking {
19 |
20 | // mergeSample()
21 | // flatMapConcatSample()
22 | flatMapMergeSample()
23 | // flatmapLatestSample()
24 |
25 | }
26 |
27 |
28 | // 🔥 RxJava merge
29 | private suspend fun mergeSample() {
30 | val flow1 = listOf("Alpha", "Beta", "Gamma", "Delta", "Epsilon").asFlow()
31 | val flow2 = listOf("Zeta", "Eta", "Theta").asFlow()
32 |
33 |
34 | merge(flow1, flow2)
35 | .collect {
36 | println(it)
37 | }
38 |
39 | /*
40 | RxJava Counterpart
41 |
42 | val source1 = Observable.just("Alpha", "Beta", "Gamma", "Delta", "Epsilon")
43 | val source2 = Observable.just("Zeta", "Eta", "Theta")
44 |
45 | source1
46 | .mergeWith(source2)
47 | .doFinally {
48 | println("doOnFinally()")
49 | }
50 | .subscribe { i -> println("RECEIVED: $i") }
51 | */
52 |
53 | /*
54 | Prints:
55 | Beta
56 | Gamma
57 | Delta
58 | Epsilon
59 | Zeta
60 | Eta
61 | Theta
62 | */
63 | }
64 |
65 | // 🔥 RxJava concatMap
66 | private suspend fun flatMapConcatSample() {
67 | (1..3).asFlow()
68 | .onEach { delay(100) } // a number every 100 ms
69 | .flatMapConcat { requestFlow(it) }
70 | .collect { value -> // collect and print
71 | println(value)
72 | }
73 |
74 | /*
75 | RxJava Counterpart
76 | observable1.concatMap{}
77 |
78 | */
79 |
80 | /*
81 | Prints
82 | 1: First in thread main
83 | 1: Second in thread main
84 | 2: First in thread main
85 | 2: Second in thread main
86 | 3: First in thread main
87 | 3: Second in thread main
88 | */
89 | }
90 |
91 | // 🔥 RxJava flatMap
92 | private suspend fun flatMapMergeSample() {
93 | (1..3).asFlow()
94 | .onEach { delay(100) } // a number every 100 ms
95 | .flatMapMerge { requestFlow(it) }
96 | .collect { value -> // collect and print
97 | println(value)
98 | }
99 |
100 | /*
101 | RxJava Counterpart
102 | observable1.flatMap{}
103 |
104 | */
105 |
106 | /*
107 | Prints
108 | 1: First in thread main
109 | 2: First in thread main
110 | 3: First in thread main
111 | 1: Second in thread main
112 | 2: Second in thread main
113 | 3: Second in thread main
114 | */
115 | }
116 |
117 | // 🔥 RxJava switchMap
118 | private suspend fun flatmapLatestSample() {
119 |
120 | val startTime = System.currentTimeMillis() // remember the start time
121 | (1..3).asFlow()
122 | // .onEach { delay(100) } // a number every 100 ms
123 | .flatMapLatest { requestFlow(it) }
124 | .collect { value -> // collect and print
125 | println("$value at ${System.currentTimeMillis() - startTime} ms from start")
126 | }
127 |
128 | /*
129 | Prints:
130 |
131 | 1: First in thread main at 79 ms from start
132 | 2: First in thread main at 84 ms from start
133 | 3: First in thread main at 85 ms from start
134 | 3: Second in thread main at 588 ms from start
135 |
136 | */
137 |
138 | /*
139 | 🔥🔥 Note that flatMapLatest cancels all the code in
140 | its block ({ requestFlow(it) } in this example) on a new value.
141 |
142 | It makes no difference in this particular example,
143 | because the call to requestFlow itself is fast, not-suspending, and cannot be cancelled.
144 | However, it would show up if we were to use suspending functions like delay in there.
145 | */
146 | }
147 |
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter6Advanced/Generics.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter6Advanced
2 |
3 | fun main() {
4 |
5 | var listBaseShape = listOf(BaseShapeK())
6 | var listOfShape = listOf(ShapeK())
7 |
8 | // ❌ COMPILE ERROR
9 | // listOfShape = listBaseShape
10 |
11 | // THIS DOES NOT WORK IN JAVA, it should have ? super BaseShapeK to work
12 | // WORKS in KOTLIN
13 | // listBaseShape = listOfShape
14 |
15 | // ❌ COMPILE ERROR
16 | // listOfShape = listBaseShape
17 |
18 | /*
19 | Producer Consumer Behaviour
20 | */
21 | val shapeBuilder = ShapeBuilder(ShapeK())
22 | var shapeBuilderWithIN: ShapeBuilder = ShapeBuilder(CircleK())
23 |
24 | println("ShapeBuilder shape: ${shapeBuilderWithIN.shape}")
25 | shapeBuilderWithIN.shape = RectangleK()
26 | println("ShapeBuilder After shape: ${shapeBuilderWithIN.shape}")
27 |
28 |
29 | var shapeBuilderWithOUT: ShapeBuilder = ShapeBuilder(CircleK())
30 |
31 | /*
32 | ❌ COMPILE ERROR
33 | Type mismatch.
34 | Required:
35 | Nothing?
36 | Found:
37 | RectangleK
38 | */
39 | // shapeBuilderWithOUT.shape = RectangleK()
40 |
41 | val shapeBuilderIn: ShapeBuilderIn = ShapeBuilderIn(CircleK())
42 | println("ShapeBuilderIn shape: ${shapeBuilderIn.fetchShape()}")
43 | shapeBuilderIn.updateShape(RectangleK())
44 | println("ShapeBuilderIn After shape: ${shapeBuilderIn.fetchShape()}")
45 |
46 | /*
47 | Assigning to Covariant or Contravariant
48 | */
49 |
50 | // 🔥 Assigning concrete types to variants works
51 | // shapeBuilderWithIN = shapeBuilder
52 | // shapeBuilderWithOUT = shapeBuilder
53 |
54 | // ❌ Compile Error
55 | // shapeBuilder = shapeBuilderWithIN
56 | // shapeBuilder = shapeBuilderWithOUT
57 |
58 | val rectangleBuilder = ShapeBuilder(RectangleK())
59 | val baseShaBuilder = ShapeBuilder(BaseShapeK())
60 |
61 | // ❌ Compile Error IN type can only be assigned with higher(super) types
62 | // shapeBuilderWithIN = rectangleBuilder
63 | shapeBuilderWithIN = baseShaBuilder
64 |
65 | shapeBuilderWithOUT = rectangleBuilder
66 | // ❌ Compile Error OUT type can only be assigned with lower(sub) types
67 | // shapeBuilderWithOUT = baseShaBuilder
68 | }
69 |
70 | internal open class BaseShapeK
71 |
72 | internal open class ShapeK : BaseShapeK()
73 |
74 | internal class CircleK : ShapeK()
75 |
76 | internal open class RectangleK : ShapeK()
77 |
78 | internal class SquareK : RectangleK()
79 |
80 | /**
81 | * Invariant class
82 | */
83 | private class ShapeBuilder(var shape: T? = null)
84 |
85 | /**
86 | * Covariant class
87 | *
88 | * **shape** in constructor cannot have ***var*** parameters
89 | */
90 | private class ShapeBuilderOut(private val shape: T?) {
91 | private var newShape = shape
92 |
93 | // 🔥🔥 ❌ Compile ErrorType parameter T is declared as 'out' but occurs in 'in' position in type T?
94 | // fun updateShape(shape: T?) {
95 | // newShape = shape
96 | //
97 | // }
98 | }
99 |
100 | /**
101 | * Contravariant class
102 | * **shape** in constructor must be private. If it's not private it returns error
103 | *
104 | * ```Type parameter T is declared as 'in' but occurs in 'invariant' position in type T```
105 | */
106 | private class ShapeBuilderIn(private var shape: T?) {
107 |
108 | fun updateShape(shape: T?) {
109 | this.shape = shape
110 | }
111 |
112 | fun fetchShape(): ShapeK? = shape
113 | }
114 |
115 |
116 | interface Source
117 |
118 | /*
119 |
120 | IN JAVA
121 |
122 | // Java
123 | interface Source {}
124 | Copied!
125 | Then, it would be perfectly safe to store a reference to an instance of Source
126 | in a variable of type Source