├── .gitignore
├── .idea
├── gradle.xml
├── misc.xml
├── modules.xml
└── vcs.xml
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── smarttoolfactory
│ │ └── kotlintutorials
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ └── res
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ └── ic_launcher_background.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.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
│ │ ├── values-night
│ │ └── themes.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── themes.xml
│ └── test
│ └── java
│ └── com
│ └── smarttoolfactory
│ └── kotlintutorials
│ └── ExampleUnitTest.kt
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── local.properties
├── settings.gradle
└── tutorial
├── .gitignore
├── build.gradle
└── src
└── main
└── java
└── com
└── smarttoolfactory
└── tutorial
├── Animal.java
├── EqualityAndHashCode.java
├── MySingleton.kt
├── RegularExpressionTest.java
├── TestStringConcatenation.java
├── chapter1Basics
├── Tutorial1_1Basics.kt
├── Tutorial1_2Arrays.kt
├── Tutorial1_3Collections1List.kt
├── Tutorial1_3Collections2Set.kt
├── Tutorial1_3Collections3Map.kt
├── Tutorial1_4Ranges.kt
├── Tutorial1_5ControlFlow.kt
├── Tutorial1_6Function1.kt
└── Tutorial1_6Function2.kt
├── chapter2OOP
├── Tutorial2_10Generics.kt
├── Tutorial2_11Enums.kt
├── Tutorial2_13ObjectExpressions.kt
├── Tutorial2_14Delegation.kt
├── Tutorial2_14Delegation2.kt
├── Tutorial2_14Delegation3StandartDelegation.kt
├── Tutorial2_14DelegationComposeRememberMutableState.kt
├── Tutorial2_15Singleton.kt
├── Tutorial2_1Constructors.kt
├── Tutorial2_2NestedClasses.kt
├── Tutorial2_3OtherClasses.kt
├── Tutorial2_4Inheritance.kt
├── Tutorial2_4Inheritance2.kt
├── Tutorial2_5Properties.kt
├── Tutorial2_6Interfaces.kt
├── Tutorial2_7VisibilityModifiers.kt
├── Tutorial2_8Extensions.kt
├── Tutorial2_9DataClasses.kt
├── Tutorial2_9DataClasses2Inheritance.kt
├── model
│ ├── ConstructorModels.kt
│ ├── InheritanceModels.kt
│ └── InheritanceModels2.kt
└── mvp
│ ├── BaseComponents.kt
│ ├── BaseContract.kt
│ ├── UserContract.kt
│ ├── UserFragmentMain.kt
│ └── user
│ └── UserFragment.kt
├── chapter3Other
├── Tutorial3_1Destructuring.kt
├── Tutorial3_2TypeChecks.kt
├── Tutorial3_3Equality.kt
├── Tutorial3_4NullSafety.kt
├── Tutorial3_5Exceptions.kt
├── Tutorial3_6Annotation.kt
├── Tutorial3_7Reflection.kt
├── Tutorial3_8FunctionLiteralsWithReceiver.kt
└── Tutorial3_8ScopeFunctions.kt
├── chapter4Functions
├── Tutorial4_1HigOrderFunctions.kt
├── Tutorial4_2FunctionTypes.kt
├── Tutorial4_3LambdaExpressions.kt
└── Tutorial4_4InlineFunctions.kt
├── chapter5Coroutines
├── Tutorial5_1Basics.kt
├── Tutorial5_2CancellationAndTimeouts.kt
├── Tutorial5_3ComposingSuspendingFunctions.kt
├── Tutorial5_4CoroutineContextAndDispatchers.kt
├── Tutorial5_5Flow1.kt
├── Tutorial5_5Flow2.kt
├── Tutorial5_5Flow3.kt
└── Tutorial5_7ExceptionHandling.kt
├── chapter6Advanced
├── DSLWithLambda.kt
├── DSLWithLambda2.kt
├── DelegatedProperty.kt
├── GenericJava.java
├── Generics.kt
├── Generics2PECS.kt
├── Generics3Methods.kt
├── HashCodeEqualsHashMap.kt
├── LambdaWithReceiver.kt
├── OperatorOverloading.kt
├── ReferencesAndObjects.kt
├── RegularExpressions.kt
└── Reified.kt
├── chapter7Threading
├── ReentrantLock.kt
├── Tutorial7_1Thread.kt
├── Tutorial7_2Synchronized.kt
├── Tutorial7_3SynchronizedBlock.kt
└── Tutorial7_4CountdownLatch.kt
└── chapter8fileIO
└── Test.java
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | *.len
3 | .idea/*
4 | */.idea/*
5 | /build/
6 | /.gradle/vcs-1/
7 | /.gradle/
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
19 |
20 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/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
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/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/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartToolFactory/Kotlin-Tutorials/e6d413609d7903a7e51f66edc48d19f084685823/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartToolFactory/Kotlin-Tutorials/e6d413609d7903a7e51f66edc48d19f084685823/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartToolFactory/Kotlin-Tutorials/e6d413609d7903a7e51f66edc48d19f084685823/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartToolFactory/Kotlin-Tutorials/e6d413609d7903a7e51f66edc48d19f084685823/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartToolFactory/Kotlin-Tutorials/e6d413609d7903a7e51f66edc48d19f084685823/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartToolFactory/Kotlin-Tutorials/e6d413609d7903a7e51f66edc48d19f084685823/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartToolFactory/Kotlin-Tutorials/e6d413609d7903a7e51f66edc48d19f084685823/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartToolFactory/Kotlin-Tutorials/e6d413609d7903a7e51f66edc48d19f084685823/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartToolFactory/Kotlin-Tutorials/e6d413609d7903a7e51f66edc48d19f084685823/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartToolFactory/Kotlin-Tutorials/e6d413609d7903a7e51f66edc48d19f084685823/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFBB86FC
4 | #FF6200EE
5 | #FF3700B3
6 | #FF03DAC5
7 | #FF018786
8 | #FF000000
9 | #FFFFFFFF
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Kotlin Tutorials
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 | ext.kotlin_version = "2.1.0"
4 | repositories {
5 | google()
6 | mavenCentral()
7 | }
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:8.9.1'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 |
12 | // NOTE: Do not place your application dependencies here; they belong
13 | // in the individual module build.gradle files
14 | }
15 | }
16 |
17 | allprojects {
18 | repositories {
19 | google()
20 | mavenCentral()
21 | // Warning: this repository is going to shut down soon
22 | }
23 | }
24 |
25 | task clean(type: Delete) {
26 | delete rootProject.buildDir
27 | }
--------------------------------------------------------------------------------
/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
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SmartToolFactory/Kotlin-Tutorials/e6d413609d7903a7e51f66edc48d19f084685823/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = "Kotlin Tutorials"
2 | include ':app'
3 | include ':tutorial'
4 |
--------------------------------------------------------------------------------
/tutorial/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/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/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/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/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/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/chapter1Basics/Tutorial1_2Arrays.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter1Basics
2 |
3 |
4 | fun main() {
5 |
6 | // INFO Initializing Arrays Method 1
7 | val numbers: IntArray = intArrayOf(1, 2, 3, 4, 5)
8 | println("Hey!! I am array Example numbers[2]: " + numbers[2])
9 |
10 | // Creates a new array of the specified size, with all elements initialized to zero.
11 | val myArray: IntArray = IntArray(3)
12 | myArray[0] = 1
13 | myArray[1] = 2
14 | myArray[2] = 3
15 |
16 | // For loop
17 | for (i in myArray) {
18 | println("myArray i: $i")
19 | }
20 |
21 | // Iterator
22 | val iterator = myArray.iterator()
23 |
24 | while (iterator.hasNext()) {
25 | println("Item: ${iterator.nextInt()}")
26 | }
27 |
28 | iterator.forEach {
29 | println("Item: $it")
30 | }
31 |
32 | // Array's foreach operator
33 | myArray.forEach { i: Int -> println("Foreach i: $i") }
34 |
35 | // Set value of item in index2 to 15
36 | myArray.set(2, 15) // myArray[2] = 15
37 | println("MyArray " + myArray.get(2))
38 |
39 | // Get average of values in array
40 | println("MyArray average: " + myArray.average())
41 |
42 | // INFO Initializing Arrays Method 2
43 | // 🔥 WARNING This is array with 3 null elements
44 | val stringArray: Array = arrayOfNulls(3)
45 |
46 | stringArray[0] = "Hello World"
47 | stringArray.forEach { s -> println("arrayOfNulls: $s") }
48 |
49 | // INFO Initializing Arrays Method 3
50 | // Creates an array where both items "Empty" with length of 4
51 | val anotherStringArray: Array = Array(4) { "Empty" }
52 | anotherStringArray.forEach { s -> println("Another array: $s") }
53 |
54 | // INFO Initializing Arrays Method 4
55 | val sqrArray: IntArray = IntArray(5) { x -> x * x }
56 | sqrArray.forEach { it -> println("Sqr : $it") }
57 |
58 |
59 | // INFO Other Initialization types
60 | val size = 10
61 |
62 | // Primitive arrays
63 | val arrayOfZeros = IntArray(6) //equivalent in Java: new int[size]
64 | val numbersFromOne = IntArray(6) { it + 1 }
65 | val myInts: IntArray = intArrayOf(1, 1, 2, 3, 5, 8, 13, 21)
66 |
67 | // Alternative 1 for loop
68 | for (i in 0 until myInts.size) {
69 | println("i: ${myInts[i]}")
70 | }
71 | // Alternative 2 for loop
72 | for (element in myInts) {
73 | println("i: $element")
74 | }
75 |
76 | // Non primitive-arrays
77 | val boxedInts: Array = arrayOfNulls(size) // 🔥 equivalent in Java: new Integer[size]
78 | val boxedZeros: Array = Array(size) { 0 }
79 |
80 | val nulls: Array = arrayOfNulls(size) // 🔥 equivalent in Java: new String[size]
81 | val strings: Array = Array(size) { "n = $it" }
82 | val myStrings: Array = arrayOf("foo", "bar", "baz")
83 |
84 | // 👍 This is valid
85 | boxedInts[0] = 12
86 | println("BoxedInt[0]: ${boxedInts[0]}")
87 |
88 | // 👍 This is valid
89 | nulls[0] = "Hey"
90 | println("nulls[0]: ${nulls[0]}")
91 |
92 | // WARNING 🔥 This is an EMPTY ARRAY with 0 length, no value can be assigned to this array.
93 | // Returns ArrayIndexOutOfBoundsException
94 | val emptyStringArray: Array = arrayOf()
95 | // emptyStringArray[0] = "TestStringConcatenation"
96 |
97 |
98 | // 🔥 2D Arrays
99 | val coordinates: Array> = arrayOf(
100 | arrayOf(1, 2),
101 | arrayOf(2, 3),
102 | arrayOf(3, 4),
103 | arrayOf(4, 5),
104 | arrayOf(5, 6),
105 | arrayOf(6, 7)
106 | )
107 |
108 | val arr = Array>(6) { arrayOf(it) }
109 | arr[0] = arrayOf(1, 2)
110 | arr[1] = arrayOf(2, 3)
111 | arr[2] = arrayOf(3, 4)
112 | arr[3] = arrayOf(4, 5)
113 | arr[4] = arrayOf(5, 6)
114 | arr[5] = arrayOf(6, 7)
115 |
116 | coordinates.forEach {
117 | println("Array in array: $it")
118 | }
119 |
120 | val solution = Solution()
121 |
122 | solution.checkStraightLine(coordinates)
123 | }
124 |
125 |
126 | class Solution {
127 |
128 | fun checkStraightLine(coordinates: Array>): Boolean {
129 |
130 | val y2 = coordinates[1][1].toDouble()
131 | val x2 = coordinates[1][0].toDouble()
132 | val y1 = coordinates[0][1].toDouble()
133 | val x1 = coordinates[0][0].toDouble()
134 |
135 | var m = 0.0
136 |
137 | if (y2 != y1) {
138 | m = ((y2 - y1) / (x2 - x1))
139 | }
140 |
141 | for (i in 2 until coordinates.size) {
142 | val y = coordinates[i][1] - coordinates[i - 1][1]
143 | val x = coordinates[i][0] - coordinates[i - 1][0]
144 |
145 | if (x == 0) {
146 | return false
147 | } else if (m != (y / x).toDouble()) {
148 | return false
149 | }
150 | }
151 |
152 | return true
153 | }
154 | }
--------------------------------------------------------------------------------
/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/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/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_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/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 | }
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter1Basics/Tutorial1_6Function2.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter1Basics
2 |
3 | /*
4 | Lambda expression takes parameters from when it's invoked
5 | definition uses that argument in codeBody
6 |
7 | val lambdaName : Type = { argumentList -> codeBody }
8 | or
9 | val lambdaName: Type = {argument: TypeOfArgument -> codeBody }
10 |
11 | *** Instantiating a function type ***
12 | There are several ways to obtain an instance of a function type:
13 |
14 | Using a code block within a function literal, in one of the forms:
15 | a lambda expression: { a, b -> a + b },
16 |
17 | an anonymous function: fun(s: String): Int { return s.toIntOrNull() ?: 0 }
18 | Function literals with receiver can be used as values of function types with receiver.
19 |
20 | Using a callable reference to an existing declaration:
21 | a top-level, local, member, or extension function: ::isOdd, String::toInt,
22 |
23 | a top-level, member, or extension property: List::size,
24 | a constructor: ::Regex
25 | These include bound callable references that point to a member of a particular
26 | instance: foo::toString.
27 | */
28 | fun main() {
29 |
30 | // INFO 🔥 Lambdas
31 |
32 | // Lambda
33 | val myLambda: (String) -> Unit = { s -> println(s) }
34 | val v: String = "Tutorials"
35 | // Invocation of lambda
36 | myLambda(v)
37 |
38 | // Lambda
39 | val compLambda: (Int, Int) -> Boolean = { a, b ->
40 | a == b
41 | }
42 | // Invocation of lambda
43 | val resLambda: Boolean = compLambda(2, 4)
44 | compLambda.invoke(2, 4)
45 |
46 | // Lambda
47 | val comp2Lambda = { a: Int, b: Int ->
48 | a == b
49 | }
50 | // Invocation of lambda
51 | val res2Lambda: Boolean = comp2Lambda(2, 4)
52 |
53 | // INFO 🔥 Lambda Functions
54 | // 🔥 myFun is a function that is (String) -> String = { str -> str.reversed() }
55 | val myFun: (String) -> String = bar() // or bar()("Hello world")
56 | println(myFun("Hello world"))
57 |
58 |
59 | val isEven: (Int) -> Boolean = modulo(2)
60 | // 🔥 k = 2, 'it' = 3, and isItEven = (Int) -> Boolean = { it % k == 0 }
61 | val isItEven = isEven(3)
62 | val myList = arrayListOf(1, 2, 3)
63 | val result = myList.filter(isEven)
64 |
65 |
66 | val myFunction: () -> Int = lambdaFunctionWithParam(13)
67 | val test = myFunction()
68 | println("Test String Concatenation $test")
69 |
70 |
71 | val totalSum: Int = highOrderSum(3, { 4 })
72 | println("totalSum: $totalSum")
73 |
74 | val totalSum2: Int = highOrderSum2(3) {
75 | it * 2
76 | }
77 | println("totalSum2: $totalSum2")
78 |
79 |
80 | // Lambda with String parameter that returns a String
81 | val anotherLambda: (String) -> String = { s -> s.uppercase() }
82 | val lambdaResult = anotherLambda("Hello World")
83 | println(lambdaResult)
84 |
85 | val swapLambda: (Int, Int, MutableList) -> List = { index1, index2, list ->
86 |
87 | require(!(index1 < 0 || index2 < 0)) { "Index cannot be smaller than zero" }
88 | require(!(index1 > list.size - 1 || index2 > list.size - 1)) { "Index cannot be bigger than size of the list" }
89 | val temp = list[index1]
90 | list[index1] = list[index2]
91 | list[index2] = temp
92 | list
93 | }
94 |
95 | val myL = listOf(1,2,3)
96 |
97 | val listNumber = mutableListOf(1, 2, 3)
98 |
99 | val resList = swapLambda(0, 1, listNumber)
100 |
101 | println("Result List: $resList")
102 |
103 | // Both implementation works
104 | // Alternative 1
105 | val lambdaFuncVar = concatLambdaFunction(13)
106 | val lambdaFuncResult = lambdaFuncVar("Try this")
107 | println(lambdaFuncResult)
108 |
109 | // Alternative 2
110 | val lambdaFuncResult2 = concatLambdaFunction(12)("Test")
111 | println(lambdaFuncResult2)
112 |
113 | // INFO 🔥 High-order functions
114 | // Alternative 1 to pass function to high order functions
115 | highOrderFunction(3) {
116 | parameterFunction(it)
117 | }
118 |
119 | // Alternative 2 to pass function to high order functions
120 | highOrderFunction(3, ::parameterFunction)
121 |
122 | "Hello World".highTes {
123 | it.reversed()
124 | }
125 | }
126 |
127 | fun String.highTes(action: (String) -> String) {
128 | action(this)
129 | }
130 |
131 | // INFO 🔥 Lambda Functions
132 |
133 | fun bar(): (String) -> String = { str -> str.reversed() }
134 |
135 | fun modulo(k: Int): (Int) -> Boolean = { it % k == 0 }
136 |
137 | /**
138 | * Lambda function that takes num Int as parameter and returns a function that takes
139 | * a String as parameter and returns a String
140 | */
141 | fun concatLambdaFunction(num: Int): (String) -> String = {
142 | "$num + $it"
143 | }
144 |
145 | /**
146 | * Lambda function that takes args and returns a lambda
147 | */
148 | fun lambdaFunctionWithParam(arg: Int): () -> Int = {
149 | val message = "I was created by CreateFunction()"
150 | println("createFunction() message: $message")
151 | arg * 2
152 | }
153 |
154 | // INFO 🔥 High-order functions
155 | private fun highOrderSum(a: Int, predicate: () -> Int): Int {
156 | return a + predicate()
157 | }
158 |
159 | private fun highOrderSum2(a: Int, predicate: (Int) -> Int): Int {
160 | return a + predicate(a)
161 | }
162 |
163 | fun highOrderFunction(num: Int, action: (Int) -> Boolean): Boolean {
164 | return action(num)
165 | }
166 |
167 | fun parameterFunction(num: Int): Boolean {
168 | return num % 2 == 0
169 | }
--------------------------------------------------------------------------------
/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/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/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/chapter2OOP/Tutorial2_14Delegation2.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter2OOP
2 |
3 | import kotlin.properties.ReadWriteProperty
4 | import kotlin.reflect.KProperty
5 |
6 | fun main() {
7 |
8 | // // INFO 🔥 Delegated Properties
9 | // val example = Example()
10 | // // getValue() function of Delegate class is called
11 | // println(example.p)
12 | // // setValue() function of Delegate class is called
13 | // example.p = "NEW"
14 | // println(example.p)
15 | //
16 | // val derivedUser = DerivedUser()
17 | // derivedUser.todayTasks = "BUY SOMETHING"
18 | // println("PRINT: ${derivedUser.todayTasks}")
19 | //
20 | // // INFO 🔥 ReadWriteProperty
21 | // val upperCaseString = UpperCaseString()
22 | // upperCaseString.str = "Hello "
23 | // println("Uppercase String: ${upperCaseString.str}")
24 |
25 |
26 | // INFO 🔥 Delegating to another property
27 | val myDelegateClass = MyDelegateClass(10, ClassWithDelegate(5))
28 |
29 | myDelegateClass.delegatedToTopLevel = 100
30 | myDelegateClass.delegatedToMember = 34
31 | myDelegateClass.delegatedAnotherClass = 13
32 |
33 | println("Top level: $topLevelInt, " +
34 | "memberInt: ${myDelegateClass.memberInt}, " +
35 | "anotherClassInstance.anotherClassInt: ${myDelegateClass.anotherClassInstance.anotherClassInt}")
36 | /*
37 | Prints:
38 | Top level: 100, memberInt: 34, anotherClassInstance.anotherClassInt: 13
39 |
40 | 🔥 By delegating top level int to MyDelegate.delegatedToTopLevel any change on this
41 | property also changes topLevelInt
42 | */
43 |
44 |
45 | // INFO 🔥 Delegating to another property for Deprecating property
46 | val myClass = ClassDeprecateWithDelegate()
47 | // Notification: 'oldName: Int' is deprecated.
48 | // Use 'newName' instead
49 | myClass.oldName = 42
50 | println(myClass.newName) // 42
51 |
52 | myClass.newName = 100
53 | println("Old: ${myClass.oldName}, new: ${myClass.newName}")
54 | // Old: 100, new: 100
55 |
56 | }
57 |
58 |
59 | // INFO 🔥 Delegated Properties
60 |
61 | class Delegate {
62 |
63 | // 🔥 first parameter is the object you read p from
64 | // second parameter holds a description of p itself (for example, you can take its name).
65 | operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
66 | return "$thisRef, thank you for delegating '${property.name}' to me!"
67 | }
68 |
69 | operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
70 | println("$value has been assigned to '${property.name}' in $thisRef.")
71 | }
72 | }
73 |
74 | class Example {
75 | var p: String by Delegate()
76 | }
77 |
78 |
79 | class DelegatedUser {
80 |
81 | private var value: String? = null
82 |
83 | // INFO 🔥 thisRef: DerivedUser object, property is todayTasks of DerivedUser class
84 | operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
85 | return "DelegatedUser getValue() property type: ${property.name}, value: $value"
86 | }
87 |
88 | operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
89 | this.value = value
90 | println("DelegatedUser setValue() thisRef: $thisRef, property: $property, property.type: ${property.name}, value: $value")
91 | }
92 |
93 | }
94 |
95 | class DerivedUser {
96 | var todayTasks: String by DelegatedUser()
97 | }
98 |
99 | // INFO 🔥 ReadWriteProperty
100 | class UpperCaseString {
101 | var str by UpperCaseStringDelegate()
102 | }
103 |
104 | class UpperCaseStringDelegate : ReadWriteProperty {
105 |
106 | private var value: String = ""
107 |
108 | override fun getValue(thisRef: Any, property: KProperty<*>): String {
109 | return value
110 | }
111 |
112 | override fun setValue(thisRef: Any, property: KProperty<*>, value: String) {
113 | this.value = value.uppercase()
114 | }
115 |
116 | }
117 |
118 | // INFO 🔥 Delegating to another property
119 |
120 | var topLevelInt: Int = 2
121 |
122 | class ClassWithDelegate(var anotherClassInt: Int)
123 |
124 | class MyDelegateClass(var memberInt: Int, val anotherClassInstance: ClassWithDelegate) {
125 |
126 | var delegatedToMember: Int by this::memberInt
127 | var delegatedToTopLevel: Int by ::topLevelInt
128 |
129 | var delegatedAnotherClass: Int by anotherClassInstance::anotherClassInt
130 | }
131 |
132 | var MyDelegateClass.extDelegated: Int by ::topLevelInt
133 |
134 |
135 | // INFO 🔥 Delegating to another property for Deprecating property
136 | class ClassDeprecateWithDelegate {
137 | var newName: Int = 0
138 | @Deprecated("Use 'newName' instead", ReplaceWith("newName"))
139 | var oldName: Int by this::newName
140 | }
141 |
142 |
--------------------------------------------------------------------------------
/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/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_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/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/chapter2OOP/Tutorial2_2NestedClasses.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter2OOP
2 |
3 | fun main() {
4 |
5 | // TODO Static Nested Classes
6 | val line = BasicGraph.Line(1, 0, -2, 0)
7 | line.draw()
8 |
9 | // nested class must be initialized
10 | println(OuterOfNestedClass.NestedClass().description) // accessing property
11 | val objNested = OuterOfNestedClass.NestedClass() // object creation
12 | objNested.foo() // access member function
13 |
14 | // TODO Inner Classes
15 |
16 | val lineWithInner = BasicGraphWithInner("Graph with Inner").InnerLine(1, 2, 3, 4)
17 | lineWithInner.draw()
18 |
19 | println(OuterOfInnerClass().InnerClass().description) // accessing property
20 | val objInner = OuterOfInnerClass().InnerClass() // object creation
21 | objInner.foo() // access member function
22 |
23 | }
24 |
25 | // 🔥 INFO: Equivalent of Java's STATIC Nested class
26 |
27 | /*
28 | * INFO Nested class can NOT access to any members of outer class
29 | */
30 | class BasicGraph(val name: String) {
31 |
32 | class Line(val x1: Int, val y1: Int, val x2: Int, val y2: Int) {
33 | fun draw(): Unit {
34 | println("Drawing Line from ($x1:$y1) to ($x2, $y2)")
35 | }
36 | }
37 |
38 | fun draw(): Unit {
39 | println("Drawing the graph $name")
40 | }
41 | }
42 |
43 | class OuterOfNestedClass {
44 |
45 | private var name: String = "Ashley"
46 |
47 | class NestedClass {
48 |
49 | var description: String = "code inside nested class"
50 | private var id: Int = 101
51 |
52 | fun foo() {
53 | // 🔥 INFO cannot access the outer class member
54 | // print("type is ${type}")
55 | println("Id is ${id}")
56 | }
57 | }
58 |
59 | }
60 |
61 | /*
62 | Java Equivalent
63 | */
64 |
65 | /*
66 | public final class OuterOfNestedClass {
67 | private String name = "Ashu";
68 |
69 | public static final class NestedClass {
70 | @NotNull
71 | private String description = "code inside nested class";
72 | private int id = 101;
73 |
74 | @NotNull
75 | public final String getDescription() {
76 | return this.description;
77 | }
78 |
79 | public final void setDescription(@NotNull String var1) {
80 | Intrinsics.checkNotNullParameter(var1, "");
81 | this.description = var1;
82 | }
83 |
84 | public final void foo() {
85 | String var1 = "Id is " + this.id;
86 | boolean var2 = false;
87 | System.out.println(var1);
88 | }
89 | }
90 | }
91 |
92 | */
93 |
94 |
95 | // 🔥 INFO: Equivalent of Java's INNER class
96 | /**
97 | * Inner class which has inner tag in front of class name, of an access field of outer class unlike nested class
98 | */
99 | class BasicGraphWithInner(graphName: String) {
100 |
101 | private val name: String
102 |
103 | init {
104 | name = graphName
105 | }
106 |
107 | /**
108 | * Classes with inner declaration can access to members of outer class even if they are private
109 | */
110 | inner class InnerLine(val x1: Int, val y1: Int, val x2: Int, val y2: Int) {
111 | fun draw(): Unit {
112 | println("Drawing Line from ($x1:$y1) to ($x2, $y2) for graph $name ")
113 | }
114 | }
115 |
116 | fun draw(): Unit {
117 | println("Drawing the graph $name")
118 | }
119 |
120 | }
121 |
122 |
123 | class OuterOfInnerClass {
124 | private var name: String = "Ash"
125 |
126 | inner class InnerClass {
127 |
128 | var description: String = "code inside inner class"
129 | private var id: Int = 101
130 |
131 | fun foo() {
132 | // 🔥 INFO ACCESS the outer class member even when it's private
133 | println("type is $name")
134 | println("Id is $id")
135 | }
136 | }
137 | }
138 |
139 | /*
140 | public final class OuterOfInnerClass {
141 | private String name = "Ash";
142 |
143 | public final class InnerClass {
144 | @NotNull
145 | private String description = "code inside inner class";
146 | private int id = 101;
147 |
148 | @NotNull
149 | public final String getDescription() {
150 | return this.description;
151 | }
152 |
153 | public final void setDescription(@NotNull String var1) {
154 | Intrinsics.checkNotNullParameter(var1, "");
155 | this.description = var1;
156 | }
157 |
158 | public final void foo() {
159 | String var1 = "type is " + OuterOfInnerClass.this.name;
160 | boolean var2 = false;
161 | System.out.println(var1);
162 | var1 = "Id is " + this.id;
163 | var2 = false;
164 | System.out.println(var1);
165 | }
166 | }
167 | }
168 | */
169 |
170 |
171 | class A {
172 |
173 | private val somefield: Int = 1
174 |
175 | inner class B {
176 |
177 | private val somefield: Int = 1
178 |
179 | fun foo(s: String) {
180 | println("Field from InterfaceB" + this.somefield)
181 |
182 | // 🔥 this with @ annotation points to instance of defined class
183 | println("Field from InterfaceB" + this@B.somefield)
184 | println("Field from BaseClassA" + this@A.somefield)
185 | }
186 | }
187 | }
188 |
189 |
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter2OOP/Tutorial2_3OtherClasses.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter2OOP
2 |
3 | fun main() {
4 |
5 | // Companion Object
6 | val car = Car.makeCar(150)
7 | println(Car.cars.size)
8 |
9 | // Data class object
10 | val customer = Customer(1, "John", "Elm Street")
11 |
12 | var shape = Rectangle(1, 3)
13 |
14 |
15 | }
16 |
17 | // INFO Companion Object Class
18 | class Car(val horsepowers: Int) {
19 |
20 |
21 | companion object Factory {
22 | val cars = mutableListOf()
23 |
24 | fun makeCar(horsepowers: Int): Car {
25 | val car = Car(horsepowers)
26 | cars.add(car)
27 | return car
28 | }
29 | }
30 | }
31 |
32 |
33 | // INFO Data Class
34 | /*
35 | * 🔥
36 | */
37 | data class Customer(val id: Int, val name: String, var address: String)
38 |
39 |
40 | // INFO Enum Classes
41 | enum class Day {
42 | MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY,
43 | SATURDAY, SUNDAY
44 | }
45 |
46 | public enum class Planet(val mass: Double, val radius: Double) {
47 | MERCURY(3.303e+23, 2.4397e6),
48 | VENUS(4.869e+24, 6.0518e6),
49 | EARTH(5.976e+24, 6.37814e6),
50 | MARS(6.421e+23, 3.3972e6),
51 | JUPITER(1.9e+27, 7.1492e7),
52 | SATURN(5.688e+26, 6.0268e7),
53 | URANUS(8.686e+25, 2.5559e7),
54 | NEPTUNE(1.024e+26, 2.4746e7);
55 |
56 | }
57 |
58 | // INFO Abstract Class
59 |
60 | abstract class Shape protected constructor() {
61 |
62 | // IMPORTANT 🔥🔥 val, and var are NOT ALLOWED with SECOND constructor
63 | constructor(x: Int, Y: Int) : this() {
64 | xLocation = x
65 | yLocation = Y
66 | }
67 |
68 | abstract var xLocation: Int
69 | abstract var yLocation: Int
70 |
71 | var width: Double = 0.0
72 | var height: Double = 0.0
73 |
74 | abstract fun isHit(x: Int, y: Int): Boolean
75 | }
76 |
77 | /*
78 | public abstract class Shape {
79 | private double width;
80 | private double height;
81 |
82 | protected Shape() {
83 |
84 | }
85 |
86 | public Shape(int x, int Y) {
87 | this();
88 | }
89 |
90 | public abstract int getXLocation();
91 | public abstract void setXLocation(int var1);
92 | public abstract int getYLocation();
93 | public abstract void setYLocation(int var1);
94 |
95 | public final double getWidth() {
96 | return this.width;
97 | }
98 |
99 | public final void setWidth(double var1) {
100 | this.width = var1;
101 | }
102 |
103 | public final double getHeight() {
104 | return this.height;
105 | }
106 |
107 | public final void setHeight(double var1) {
108 | this.height = var1;
109 | }
110 |
111 | public abstract boolean isHit(int var1, int var2);
112 | }
113 | */
114 |
115 | class Ellipsis(xBase: Int, yBase: Int) : Shape(xBase, yBase) {
116 |
117 | override var xLocation: Int = 0
118 | override var yLocation: Int = 0
119 |
120 | override fun isHit(x: Int, y: Int): Boolean {
121 |
122 | val xRadius = width / 2
123 | val yRadius = height / 2
124 | val centerX = xLocation + xRadius
125 | val centerY = yLocation + yRadius
126 |
127 | if (xRadius == 0.0 || yRadius == 0.0)
128 | return false
129 |
130 | val normalizedX = centerX - xLocation
131 | val normalizedY = centerY - yLocation
132 | return (normalizedX * normalizedX) / (xRadius * xRadius) +
133 | (normalizedY * normalizedY) / (yRadius * yRadius) <= 1.0
134 | }
135 | }
136 |
137 | /*
138 | public final class Ellipsis extends Shape {
139 | private int xLocation;
140 | private int yLocation;
141 |
142 | public Ellipsis(int xBase, int yBase) {
143 | super(xBase, yBase);
144 | }
145 |
146 | public int getXLocation() {
147 | return this.xLocation;
148 | }
149 |
150 | public void setXLocation(int var1) {
151 | this.xLocation = var1;
152 | }
153 |
154 | public int getYLocation() {
155 | return this.yLocation;
156 | }
157 |
158 | public void setYLocation(int var1) {
159 | this.yLocation = var1;
160 | }
161 |
162 | public boolean isHit(int x, int y) {
163 | double xRadius = this.getWidth() / (double)2;
164 | double yRadius = this.getHeight() / (double)2;
165 | double centerX = (double)this.getXLocation() + xRadius;
166 | double centerY = (double)this.getYLocation() + yRadius;
167 | if (xRadius != 0.0D && yRadius != 0.0D) {
168 | double normalizedX = centerX - (double)this.getXLocation();
169 | double normalizedY = centerY - (double)this.getYLocation();
170 | return normalizedX * normalizedX / (xRadius * xRadius) + normalizedY * normalizedY / (yRadius * yRadius) <= 1.0D;
171 | } else {
172 | return false;
173 | }
174 | }
175 | }
176 | */
177 |
178 | class Rectangle(override var xLocation: Int, override var yLocation: Int) : Shape() {
179 |
180 | override fun isHit(x: Int, y: Int): Boolean {
181 | return x >= xLocation && x <= (xLocation + width) && y >=
182 | yLocation && y <= (yLocation + height)
183 | }
184 | }
185 |
186 | /*
187 | public final class Rectangle extends Shape {
188 | private int xLocation;
189 | private int yLocation;
190 |
191 | public Rectangle(int xLocation, int yLocation) {
192 | this.xLocation = xLocation;
193 | this.yLocation = yLocation;
194 | }
195 |
196 | public boolean isHit(int x, int y) {
197 | return x >= this.getXLocation() && (double)x <= (double)this.getXLocation() + this.getWidth() && y >= this.getYLocation() && (double)y <= (double)this.getYLocation() + this.getHeight();
198 | }
199 |
200 | public int getXLocation() {
201 | return this.xLocation;
202 | }
203 |
204 | public void setXLocation(int var1) {
205 | this.xLocation = var1;
206 | }
207 |
208 | public int getYLocation() {
209 | return this.yLocation;
210 | }
211 |
212 | public void setYLocation(int var1) {
213 | this.yLocation = var1;
214 | }
215 | }
216 | */
217 |
--------------------------------------------------------------------------------
/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/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/chapter2OOP/Tutorial2_5Properties.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter2OOP
2 |
3 | fun main() {
4 |
5 | // INFO Setters and getters
6 | // val setterAndGetterWrapper = SetterAndGetters()
7 | // println(setterAndGetterWrapper.stringRepresentation)
8 | // setterAndGetterWrapper.stringRepresentation = "Hello World"
9 |
10 | // INFO Backing Field
11 | val user = User("Jackson", "Hitch")
12 | user.myName = "Johnny"
13 |
14 | // INFO 🔥⚠️ Throws StackOverflow exception when get() called
15 | // println("User type ${user.myName}")
16 |
17 | // INFO Backing Property
18 | val humanWithBackingProperty = HumanWithBackingProperty()
19 | println("Human age: ${humanWithBackingProperty.age}")
20 | humanWithBackingProperty.age = 15
21 | println("Human age after set(): ${humanWithBackingProperty.age}")
22 | // Lambda method
23 | humanWithBackingProperty.printAge()
24 |
25 |
26 | }
27 |
28 | // INFO Setters and getters
29 | class SetterAndGetters {
30 |
31 | var stringRepresentation: String
32 | get() = this.toString()
33 | set(value) {
34 | setDataFromString(value) // parses the string and assigns values to other properties
35 | }
36 |
37 | // INFO 🔥🔥🔥⚠️ Using property = with a set() function calls set recursively and causes StackOverflow exception
38 | private fun setDataFromString(value: String) {
39 | // 🔥 !!! Causes recursive call to set() from this method
40 | // stringRepresentation = "New Assignment"
41 | println("🤨 SettersAndGetters setDataFromString $stringRepresentation")
42 | }
43 | }
44 |
45 |
46 | const val PREFIX = "[ABC]"
47 |
48 |
49 | // 🔥 INFO BACKING FIELDS
50 | class Person {
51 |
52 | // set: if value set to first type have length < 1 => throw error else add prefix "ABC" to the type
53 | // get: if type is not empty -> trim for remove whitespace and add '.' else return default type
54 | var lastName: String = ""
55 | get() {
56 | if (field.isNotEmpty()) {
57 | return field.trim() + "."
58 | }
59 | return field
60 | }
61 | set(value) {
62 | if (value.length > 1) {
63 | field = PREFIX + value
64 | } else {
65 | throw IllegalArgumentException("Last type too short")
66 | }
67 | }
68 | }
69 |
70 | /*
71 | public final class Person {
72 | @NotNull
73 | private String lastName = "";
74 |
75 | @NotNull
76 | public final String getLastName() {
77 | CharSequence var1 = (CharSequence)this.lastName;
78 |
79 | if (var1.length() > 0) {
80 |
81 | StringBuilder var10000 = new StringBuilder();
82 |
83 | String var3 = this.lastName;
84 |
85 | if (var3 == null) {
86 | throw new NullPointerException("null cannot be cast to non-null type kotlin.CharSequence");
87 | } else {
88 | return var10000.append(StringsKt.trim((CharSequence)var3).toString()).append(".").toString();
89 | }
90 | } else {
91 | return this.lastName;
92 | }
93 | }
94 |
95 | public final void setLastName(@NotNull String value) {
96 | if (value.length() > 1) {
97 | this.lastName = "[ABC]" + value;
98 | } else {
99 | throw (Throwable)(new IllegalArgumentException("Last type too short"));
100 | }
101 | }
102 | }
103 | */
104 |
105 |
106 | // INFO 🔥⚠️ Throws StackOverflow exception when get() called
107 | class User(private var name: String, private var surName: String) {
108 |
109 | var myName: String = name
110 | get() {
111 | return myName.substring(0, 4)
112 | }
113 |
114 | val fullName: String
115 | get() = "name: $name, surname: $surName"
116 | }
117 |
118 |
119 | // INFO 🔥⚠️ Throws StackOverflow exceptions when get() or set() called for firstName or LastName
120 | class User2 {
121 | var firstName: String //backing field generated
122 | get() = firstName
123 | set(value) {
124 | firstName = value
125 | }
126 | var lastName: String //backing field generated
127 | get() = lastName
128 | set(value) {
129 | lastName = value
130 | }
131 | val name: String //no backing field generated
132 | get() = "{$firstName $lastName}"
133 | var address: String = "XYZ" //^because there is no default //^implementation of an accessor
134 |
135 | }
136 |
137 |
138 | class Human {
139 | val age = 20
140 | get() {
141 | println("Age is: $field")
142 | return field
143 | }
144 | }
145 |
146 | // INFO Java Equivalent of Kotlin code for backing field. Note: This won't work in Kotlin class
147 | //public final class Human {
148 | // private final int age = 20;
149 | //
150 | // public final int getAge() {
151 | // String var1 = "Age is: " + this.age;
152 | // System.out.println(var1);
153 | // return this.age;
154 | // }
155 | //}
156 |
157 | // INFO 🔥🔥🔥 Backing Properties
158 |
159 | class HumanWithBackingProperty {
160 |
161 | private var _age: Int = 20
162 |
163 | var age: Int
164 | get() {
165 | println("HumanWithBackingProperty get()")
166 | return _age
167 | }
168 | set(value) {
169 | println("HumanWithBackingProperty set()")
170 | _age = value
171 | }
172 |
173 | val printAge: () -> Unit = {
174 | println("Age is: $_age")
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/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/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/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_9DataClasses.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter2OOP
2 |
3 | /**
4 | * Example for data classes
5 | *
6 | * * — The primary constructor needs to have at least one parameter
7 | * * — All primary constructor parameters need to be marked as val or var
8 | * * — Data classes cannot be abstract, open, sealed or inner
9 | */
10 | fun main() {
11 |
12 | val person1 = PersonData("John")
13 | val person2 = PersonData("John")
14 |
15 | // 🔥🔥 age property is not declared inside Constructor, so does NOT effect equals and hash code
16 | person1.age = 10
17 | person2.age = 20
18 |
19 | // 🔥🔥 Copying data from one data class to another, only copies properties in constructor
20 | val person3 = person2.copy(name = "Dave")
21 |
22 | // 🔥 If primary constructor properties have same values objects have Structural Equality
23 | val person4 = person2.copy(name = person2.name)
24 |
25 |
26 | // Prints: person1: 2314539, person2: 2314539, person3: 2122764, person4: 2314539
27 | println("person1: ${person1.hashCode()}, person2: ${person2.hashCode()}, " +
28 | "person3: ${person3.hashCode()}, person4: ${person4.hashCode()}")
29 |
30 | println("${person1.toString()}") // prints PersonData(name=John)
31 |
32 | // Referential equality returns true only for the SAME objects even for data classes
33 | println("Person1 == Person2 -> ${person1 == person2}") // prints true
34 | println("Person1 === Person2 -> ${person1 === person2}") // prints false
35 |
36 | // 🔥 variables with default values can be omitted when data class is instantiated
37 | val carData = CarData(manifacturer = "", model = "")
38 |
39 | /*
40 | *** EQUALITY ***
41 | */
42 |
43 | // == means Structural equality which looks properties of a class
44 | // === means Referential equality which is true for a and b point to the same object
45 |
46 | val bookData1 = BookData("LOTR", 54)
47 | val bookData2 = BookData("LOTR", 54)
48 | val bookData3 = bookData1
49 |
50 | val book1 = Book("LOTR", 54)
51 | val book2 = Book("LOTR", 54)
52 | val book3 = book1
53 |
54 | println("Book1: ${book1.hashCode()} == Book2: ${book2.hashCode()} -> ${book1 == book2}") // prints false
55 | // Book1: 1096979270 == Book2: 1078694789 -> false
56 | println("Book1 == Book2 -> ${book1 == book2}") // prints false
57 | println("Book1 === Book2 -> ${book1 === book2}") // prints false
58 |
59 | // Data class
60 | println("BookData1: ${bookData1.hashCode()} == BookData2: ${bookData2.hashCode()} -> ${bookData1 == bookData2}") // prints true
61 | // BookData1: 72624405 == BookData2: 72624405 -> true
62 | println("BookData2: ${bookData2.hashCode()} == BookData3: ${bookData3.hashCode()} -> ${bookData2 == bookData3}") // prints true
63 | // BookData2: 72624405 == BookData3: 72624405 -> true
64 |
65 | println("BookData1 === BookData2 -> ${bookData1 === bookData2}") // prints false
66 |
67 | println("Book1: ${book1.toString()}") // prints Book1: chapter2OOP.Book@1d44bcfa
68 | println("Book1Data: ${bookData1.toString()}") // prints Book1Data: BookData(name=LOTR, age=54)
69 |
70 |
71 | }
72 |
73 | //🔥🔥 To exclude a property from the generated implementations, declare it inside the class body:
74 | data class PersonData(val name: String) {
75 | var age: Int = 0
76 |
77 | }
78 |
79 | // 🔥 variables with default values can be omitted when data class is instantiated
80 | data class CarData(
81 | var type: Int? = 0,
82 | var manifacturer: String,
83 | var model: String
84 | ) {
85 | fun type(type: Int): CarData = apply { this.type = type }
86 |
87 | }
88 |
89 |
90 | /**
91 | * This example is from Stackoverflow
92 | *
93 | * definition 1
94 |
95 | data class Person (var name:String, var age:Int)
96 | definition 2
97 |
98 | class Person (var name:String, var age:Int)
99 | definition 3
100 |
101 | class Person (){
102 | var name:String = ""
103 | var age:Int = 1
104 | }
105 |
106 | Difference in equals, hashCode, & toString
107 | the most important difference between definition 1 and definitions 2 & 3 is that in definition 1,
108 | the equals, hashcode and toString methods are overridden for you:
109 |
110 | equals and hashCode methods test for structural equality
111 | toString method returns a nice, human-friendly string
112 | Code example:
113 |
114 | NOTE: in Kotlin, the == operator calls an object's .equals() method. see operator overloading
115 | on kotlinlang.org for more info.
116 |
117 | data class Person1 (var name:String, var age:Int)
118 | class Person2 (var name:String, var age:Int)
119 |
120 | @Test fun test1()
121 | {
122 | val alice1 = Person1("Alice", 22)
123 | val alice2 = Person1("Alice", 22)
124 | val bob = Person1("bob", 23)
125 |
126 | // alice1 and alice2 are structurally equal, so this returns true.
127 | println(alice1 == alice2) // true
128 |
129 | // alice1 and bob are NOT structurally equal, so this returns false.
130 | println(alice1 == bob) // false
131 |
132 | // the toString method for data classes are generated for you.
133 | println(alice1) // Person1(name=Alice, age=22)
134 | }
135 |
136 | @Test fun test2()
137 | {
138 | val alice1 = Person2("Alice", 22)
139 | val alice2 = Person2("Alice", 22)
140 | val bob = Person2("bob", 23)
141 |
142 | // even though alice1 and alice2 are structurally equal, this returns false.
143 | println(alice1 == alice2) // false
144 | println(alice1 == bob) // false
145 |
146 | // the toString method for normal classes are NOT generated for you.
147 | println(alice1) // Person2@1ed6993a
148 | }
149 | Difference in constructors
150 | another difference between definitions 1 & 2 and definition 3 is that:
151 |
152 | definitions 1 & 2 both have a constructor that takes 2 parameters
153 | definition 3 only has a no argument constructor that assigns default values to the class members.
154 | Code example:
155 |
156 | data class Person1 (var name:String, var age:Int)
157 | class Person2 (var name:String, var age:Int)
158 | class Person3 ()
159 | {
160 | var name:String = ""
161 | var age:Int = 1
162 | }
163 |
164 | @Test fun test3()
165 | {
166 | Person1("alice",22) // OK
167 | Person2("bob",23) // OK
168 | Person3("charlie",22) // error
169 |
170 | Person1() // error
171 | Person2() // error
172 | Person3() // OK
173 | }
174 | The copy method
175 | Finally, another difference between definition 1 and definitions 2 & 3 is that in definition 1,
176 | a copy method is generated for it. Here's an example of how it can be used:
177 |
178 | val jack = Person1("Jack", 1)
179 | val olderJack = jack.copy(age = 2)
180 |
181 | // jack.age = 1
182 | // olderJack.age = 2
183 | */
184 |
185 | class Book(val name: String, val age: Int)
186 |
187 | data class BookData(val name: String, val age: Int)
188 |
189 |
190 |
191 |
192 |
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter2OOP/Tutorial2_9DataClasses2Inheritance.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter2OOP
2 |
3 | fun main() {
4 |
5 | /*
6 | Overloading method getName in Corn and Vegetable let's these object to call
7 | one for the static type(type on left side of the equation val milkCorn:Vegetable = Corn())
8 |
9 | */
10 | val apple = Apple(0, "🍏")
11 | println("Apple name: ${apple.name}")
12 |
13 | val corn: Corn = Corn(0, "🌽")
14 | println("Corn name: ${corn.name}")
15 | corn.name = "🌽🌽"
16 | corn.printName()
17 |
18 | val milkCorn: Vegetable = corn
19 | corn.id = 20
20 | println("MilkCorn name: ${milkCorn.name}")
21 | milkCorn.name = "🌽x3"
22 | val m = milkCorn as Corn
23 | println("MilkCorn Changed name: ${milkCorn.name}, m id: ${m.id}")
24 | corn.printName()
25 |
26 |
27 | /*
28 | Prints
29 | Apple name: 🍏
30 | Corn name: 🌽
31 | Name: 🌽🌽, super name: 🌽
32 | MilkCorn name: 🌽🌽
33 | MilkCorn Changed name: 🌽x3, m id: 20
34 | Name: 🌽x3, super name: 🌽
35 | */
36 |
37 | val vegetableList = listOf(corn)
38 |
39 | vegetableList.forEach {
40 | print("Vegetable name: $it")
41 | }
42 | /*
43 | Prints:
44 | Vegetable name: Corn(id=20, name=🌽x3)
45 |
46 | */
47 | }
48 |
49 | open class Fruit {
50 | open var name: String = "fruit"
51 | }
52 |
53 | /*
54 | public class Fruit {
55 | @NotNull
56 | private final String name = "fruit";
57 |
58 | @NotNull
59 | public String getName() {
60 | return this.name;
61 | }
62 | }
63 | */
64 |
65 | data class Apple(val id: Int, override var name: String) : Fruit() {
66 |
67 | }
68 | /*
69 | public final class Apple extends Fruit {
70 |
71 | private final int id;
72 | @NotNull
73 | private String name;
74 |
75 | public Apple(int id, @NotNull String name) {
76 | super();
77 | this.id = id;
78 | this.name = name;
79 | }
80 |
81 | public final int getId() {
82 | return this.id;
83 | }
84 |
85 | @NotNull
86 | public String getName() {
87 | return this.name;
88 | }
89 |
90 | public void setName(@NotNull String var1) {
91 | Intrinsics.checkNotNullParameter(var1, "");
92 | this.name = var1;
93 | }
94 |
95 |
96 |
97 | public final int component1() {
98 | return this.id;
99 | }
100 |
101 | @NotNull
102 | public final String component2() {
103 | return this.getName();
104 | }
105 |
106 | }
107 | */
108 |
109 | open class Vegetable(open var name: String)
110 | /*
111 | public class Vegetable {
112 | @NotNull
113 | private final String name;
114 |
115 | @NotNull
116 | public String getName() {
117 | return this.name;
118 | }
119 |
120 | public Vegetable(@NotNull String name) {
121 | Intrinsics.checkNotNullParameter(name, "name");
122 | super();
123 | this.name = name;
124 | }
125 | }
126 | */
127 |
128 | class Bean(id: Int, name:String) : Vegetable(name) {
129 |
130 | fun printName() {
131 | println("Name: $name, super name: ${super.name}")
132 | }
133 | }
134 |
135 | /*
136 | public final class Bean extends Vegetable {
137 |
138 | public Bean(int id, @NotNull String name) {
139 | super(name);
140 | }
141 |
142 | public final void printName() {
143 | String var1 = "Name: " + this.getName() + ", super name: " + super.getName();
144 | boolean var2 = false;
145 | System.out.println(var1);
146 | }
147 |
148 |
149 | }
150 | */
151 |
152 | data class Corn(var id: Int, override var name: String) : Vegetable(name) {
153 |
154 | fun printName() {
155 | println("Name: $name, super name: ${super.name}")
156 | }
157 |
158 | }
159 |
160 | /*
161 | public final class Corn extends Vegetable {
162 | private final int id;
163 | @NotNull
164 | private String name;
165 |
166 | public Corn(int id, @NotNull String name) {
167 | Intrinsics.checkNotNullParameter(name, "name");
168 | super(name);
169 | this.id = id;
170 | this.name = name;
171 | }
172 |
173 | public final void printName() {
174 | String var1 = "Name: " + this.getName() + ", super name: " + super.getName();
175 | boolean var2 = false;
176 | System.out.println(var1);
177 | }
178 |
179 | public final int getId() {
180 | return this.id;
181 | }
182 |
183 | @NotNull
184 | public String getName() {
185 | return this.name;
186 | }
187 |
188 | public void setName(@NotNull String var1) {
189 | Intrinsics.checkNotNullParameter(var1, "");
190 | this.name = var1;
191 | }
192 |
193 | public final int component1() {
194 | return this.id;
195 | }
196 |
197 | @NotNull
198 | public final String component2() {
199 | return this.getName();
200 | }
201 |
202 | @NotNull
203 | public final Corn copy(int id, @NotNull String name) {
204 | Intrinsics.checkNotNullParameter(name, "name");
205 | return new Corn(id, name);
206 | }
207 |
208 | // $FF: synthetic method
209 | public static Corn copy$default(Corn var0, int var1, String var2, int var3, Object var4) {
210 | if ((var3 & 1) != 0) {
211 | var1 = var0.id;
212 | }
213 |
214 | if ((var3 & 2) != 0) {
215 | var2 = var0.getName();
216 | }
217 |
218 | return var0.copy(var1, var2);
219 | }
220 |
221 | @NotNull
222 | public String toString() {
223 | return "Corn(id=" + this.id + ", name=" + this.getName() + ")";
224 | }
225 |
226 | public int hashCode() {
227 | int var10000 = this.id * 31;
228 | String var10001 = this.getName();
229 | return var10000 + (var10001 != null ? var10001.hashCode() : 0);
230 | }
231 |
232 | public boolean equals(@Nullable Object var1) {
233 | if (this != var1) {
234 | if (var1 instanceof Corn) {
235 | Corn var2 = (Corn)var1;
236 | if (this.id == var2.id && Intrinsics.areEqual(this.getName(), var2.getName())) {
237 | return true;
238 | }
239 | }
240 |
241 | return false;
242 | } else {
243 | return true;
244 | }
245 | }
246 | }
247 | */
248 |
249 |
250 | abstract class Resource {
251 | abstract var id: Long
252 | abstract var location: String
253 | }
254 |
255 | data class Article(
256 | override var id: Long = 0,
257 | override var location: String = "",
258 | var isbn: String
259 | ) : Resource()
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter2OOP/model/ConstructorModels.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter2OOP.model
2 |
3 | class MyClass {
4 |
5 | // property (data member)
6 | private var name: String = "Tutorials.point"
7 |
8 | // member function
9 | fun printMe() {
10 | println("You are at the best Learning website Named-" + name)
11 | }
12 | }
13 |
14 | class MyObject(name: String) {
15 |
16 | val objName = name
17 |
18 | init {
19 | println("Name: $name")
20 | }
21 | }
22 | /*
23 | public final class MyObject {
24 | @NotNull
25 | private final String objName;
26 |
27 | @NotNull
28 | public final String getObjName() {
29 | return this.objName;
30 | }
31 |
32 | public MyObject(@NotNull String name) {
33 | Intrinsics.checkNotNullParameter(name, "name");
34 | super();
35 | this.objName = name;
36 | String var2 = "Name: " + name;
37 | boolean var3 = false;
38 | System.out.println(var2);
39 | }
40 | }
41 | */
42 |
43 |
44 | // INFO CONSTRUCTOR
45 | // age parameter can be NULL
46 | // 🔥 INFO If the primary constructor does not have any annotations or visibility modifiers,
47 | // the constructor keyword can be omitted:
48 | //🔥 INFO If the constructor has annotations or visibility modifiers,
49 | // the constructor keyword is required, and the modifiers go before it:
50 | class Person constructor(var firstName: String, val lastName: String, val age: Int?) {
51 | //...
52 | }
53 |
54 | // INFO INIT BLOCK
55 |
56 | // INFO During an instance initialization,
57 | // the initializer blocks are executed in the 🔥 SAME ORDER as they appear in the class body,
58 | // interleaved with the property initializers:
59 |
60 | class InitOrderDemo(name: String) {
61 |
62 | // 1st
63 | val firstProperty = "First property: $name".also(::println)
64 |
65 | // 2nd
66 | init {
67 | println("First initializer block that prints ${name}")
68 | }
69 |
70 | // 3rd
71 | val secondProperty = "Second property: ${name.length}".also(::println)
72 |
73 | // 4th
74 | init {
75 | println("Second initializer block that prints ${name.length}")
76 | }
77 | }
78 |
79 |
80 | class MYNewClass(private val name: String)
81 |
82 | /*
83 | public final class MYNewClass {
84 | private final String name;
85 |
86 | public MYNewClass(@NotNull String name) {
87 | Intrinsics.checkNotNullParameter(name, "name");
88 | super();
89 | this.name = name;
90 | }
91 | }
92 | */
93 |
94 |
95 | // INFO 🔥 Assign Constructor parameters to class fields
96 | // INFO 🔥 ⚠️ ️Prefixing your constructor arguments with val or var is not a must
97 | // if you don't want the getter (or setter if you use var) to be generated, you can always do the following:
98 |
99 | class Person2(firstName: String, lastName: String, howOld: Int?) {
100 |
101 | private val name: String
102 | private val age: Int?
103 |
104 | init {
105 | // IMPORTANT 🔥🔥🔥 Properties must be initialized in constructor(this could also be inside init{}),
106 | // or be abstract or lateinit
107 | this.name = "$firstName,$lastName"
108 | this.age = howOld
109 | }
110 |
111 | fun getName(): String = this.name
112 | fun getAge(): Int? = this.age
113 | }
114 |
115 | class Customer(name: String) {
116 | val customerKey = name.uppercase()
117 | }
118 |
119 | // INFO 🔥 Constructors with val/var properties
120 | class User(val id: Long, email: String) {
121 |
122 | val hasEmail = email.isNotBlank() //email can be accessed here
123 |
124 | init {
125 | //email can be accessed here
126 | println("Email $email")
127 | }
128 |
129 | fun getEmail() {
130 | // 🔥 email can't be accessed here
131 | }
132 | }
133 |
134 | // INFO SECONDARY CONSTRUCTORS
135 |
136 | class Person3 {
137 |
138 | // INFO Secondary Constructor
139 | constructor(firstName: String, lastName: String) {
140 | println("😳 Secondary constructor of Person3")
141 | }
142 | }
143 |
144 | class Person4 constructor(val firstName: String, val lastName: String, val age: Int?) {
145 |
146 | // INFO 🔥 Secondary Constructor that calls Primary Constructor
147 | constructor(firstName: String, lastName: String) : this(firstName, lastName, null) {
148 | println("😳 Secondary constructor of Person4")
149 | }
150 | }
151 |
152 | /*
153 |
154 | public final class Person4 {
155 |
156 | @NotNull
157 | private final String firstName;
158 | @NotNull
159 | private final String lastName;
160 | @Nullable
161 | private final Integer age;
162 |
163 | @NotNull
164 | public final String getFirstName() {
165 | return this.firstName;
166 | }
167 |
168 | @NotNull
169 | public final String getLastName() {
170 | return this.lastName;
171 | }
172 |
173 | @Nullable
174 | public final Integer getAge() {
175 | return this.age;
176 | }
177 |
178 | // 🔥 Primary Constructor
179 | public Person4(@NotNull String firstName, @NotNull String lastName, @Nullable Integer age) {
180 | super();
181 | this.firstName = firstName;
182 | this.lastName = lastName;
183 | this.age = age;
184 | }
185 |
186 | // 🔥 Secondary Constructor
187 | public Person4(@NotNull String firstName, @NotNull String lastName) {
188 | this(firstName, lastName, (Integer)null);
189 | String var3 = "\ud83d\ude33 Secondary constructor of Person4";
190 | System.out.println(var3);
191 | }
192 | }
193 |
194 | */
195 |
196 | class Constructors {
197 |
198 | constructor(i: Int) {
199 | println("😎 Secondary Constructor of Constructors class")
200 | }
201 |
202 | // INFO 🔥 init block is called before secondary constructor
203 | init {
204 | println("Init block of Constructors class")
205 | }
206 |
207 | }
208 |
209 | class Auto(age: Int) {
210 |
211 |
212 | init {
213 | println("🥳 Init block of Auto class with $age")
214 | }
215 |
216 | constructor(name: String) : this(0) {
217 | println("🚗🚗 Secondary Constructor of Auto with type $name")
218 | }
219 |
220 | constructor(i: Int, name: String) : this(i) {
221 | println("🚙 Secondary Constructor of Auto class with type $name and i $i")
222 | }
223 | }
224 |
225 | class SomeObject {
226 |
227 | constructor(age: Int)
228 |
229 | constructor(age: Int, name: String):this(age)
230 |
231 | }
232 | /*
233 |
234 | public final class Auto {
235 |
236 | public Auto(int age) {
237 | String var2 = "\ud83e\udd73 Init block of Auto class with " + age;
238 | System.out.println(var2);
239 | }
240 |
241 | public Auto(@NotNull String name) {
242 | this(0);
243 | String var2 = "\ud83d\ude97\ud83d\ude97 Secondary Constructor of Auto with type " + name;
244 | System.out.println(var2);
245 | }
246 |
247 | public Auto(int i, @NotNull String name) {
248 | this(i);
249 | String var3 = "\ud83d\ude99 Secondary Constructor of Auto class with type " + name + " and i " + i;
250 | System.out.println(var3);
251 | }
252 | }
253 |
254 | */
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter2OOP/model/InheritanceModels.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter2OOP.model
2 |
3 |
4 | open class Base(val name: String) {
5 |
6 | init {
7 | // INFO called 2nd
8 | println("Initializing Base")
9 | }
10 |
11 | open val size: Int =
12 | // INFO called 3rd
13 | name.length.also { println("Initializing size in Base: $it") }
14 | }
15 |
16 | class Derived(
17 | name: String,
18 | val lastName: String
19 | )
20 | // INFO called 1st
21 | : Base(name.capitalize().also { println("Argument for Base: $it") }) {
22 |
23 | init {
24 | // INFO called 4th
25 | println("Initializing Derived")
26 | }
27 |
28 | override val size: Int =
29 | // INFO called 5th
30 | (super.size + lastName.length).also { println("Initializing size in Derived:$it") }
31 | }
32 |
33 |
34 | open class BaseClassA {
35 |
36 | open fun f() {
37 | print("BaseClassA")
38 | }
39 |
40 | fun a() {
41 | print("a")
42 | }
43 | }
44 |
45 | interface InterfaceB {
46 |
47 | var name: String
48 |
49 | // interface members are 'open' by default
50 | fun f() {
51 | print("InterfaceB")
52 | }
53 |
54 | fun b() {
55 | print("b")
56 | }
57 |
58 | // INFO f(), and b() methods are not ABSTRACT but foo is abstract and must be
59 | // overridden on class that implement InterfaceB interface
60 | fun foo()
61 | }
62 |
63 | /*
64 | public interface InterfaceB {
65 | @NotNull
66 | String getName();
67 |
68 | void f();
69 |
70 | void b();
71 |
72 | void foo();
73 |
74 | // 🔥 This class gets generated because of methods with body in Interface in Java
75 | public static final class DefaultImpls {
76 | public static void f(@NotNull InterfaceB $this) {
77 | String var1 = "InterfaceB";
78 | boolean var2 = false;
79 | System.out.print(var1);
80 | }
81 |
82 | public static void b(@NotNull InterfaceB $this) {
83 | String var1 = "b";
84 | boolean var2 = false;
85 | System.out.print(var1);
86 | }
87 | }
88 | }
89 | */
90 |
91 | class C() : BaseClassA(), InterfaceB {
92 |
93 | override fun foo() {
94 | TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
95 | }
96 |
97 | private var className = ""
98 |
99 | override var name: String
100 | get() = className
101 | set(value) {
102 | className = value
103 | }
104 |
105 | // INFO only invokes methods called with super
106 | // 🔥 The compiler requires f() to be overridden because it's open fun in BaseClassA
107 | override fun f() {
108 | super.f() // call to BaseClassA.f()
109 | super.f() // call to InterfaceB.f() }
110 | }
111 |
112 | }
113 |
114 | class InterfaceTestClass(override var name: String) : InterfaceB {
115 |
116 | // 🔥 This should be implemented because it has no body in Interface
117 | override fun foo() {
118 | TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
119 | }
120 | }
121 |
122 | /*
123 | public final class InterfaceTestClass implements InterfaceB {
124 | @NotNull
125 | private String name;
126 |
127 | public InterfaceTestClass(@NotNull String name) {
128 | Intrinsics.checkNotNullParameter(name, "name");
129 | super();
130 | this.name = name;
131 | }
132 |
133 |
134 | public void foo() {
135 | String var1 = "not implemented";
136 | boolean var2 = false;
137 | throw (Throwable)(new NotImplementedError("An operation is not implemented: " + var1));
138 | }
139 |
140 | @NotNull
141 | public String getName() {
142 | return this.name;
143 | }
144 |
145 | public void setName(@NotNull String var1) {
146 | Intrinsics.checkNotNullParameter(var1, "");
147 | this.name = var1;
148 | }
149 |
150 | public void f() {
151 | InterfaceB.DefaultImpls.f(this);
152 | }
153 |
154 | public void b() {
155 | InterfaceB.DefaultImpls.b(this);
156 | }
157 | }
158 | */
159 |
160 |
161 | // INFO Super with Constructor
162 | // Parent class
163 | open class Computer(
164 | val name: String,
165 | val brand: String
166 | ) {
167 |
168 | open var age: Double = 0.0
169 |
170 | open fun start() {
171 |
172 | }
173 | }
174 |
175 | // Child class (initializes the parent class)
176 | class Laptop : Computer {
177 |
178 | override var age: Double = 0.0
179 | get() = super.age
180 | set(value) {
181 | field = value + 2
182 | }
183 |
184 |
185 | val batteryLife: Double
186 |
187 | // Calls super() to initialize the Parent class
188 | constructor(name: String, brand: String, batteryLife: Double) : super(name, brand) {
189 | this.batteryLife = batteryLife
190 | }
191 |
192 | // Calls another constructor (which calls super())
193 | constructor(name: String, brand: String) : this(name, brand, 0.0) {
194 |
195 | }
196 | }
197 |
--------------------------------------------------------------------------------
/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/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/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 | }
--------------------------------------------------------------------------------
/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 | }
--------------------------------------------------------------------------------
/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/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/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/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/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/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/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/chapter3Other/Tutorial3_6Annotation.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter3Other
2 |
3 |
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter3Other/Tutorial3_7Reflection.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter3Other
2 |
3 | fun main() {
4 |
5 | }
6 |
--------------------------------------------------------------------------------
/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/chapter4Functions/Tutorial4_1HigOrderFunctions.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter4Functions
2 |
3 | fun main() {
4 |
5 | // INFO 🔥 High-order functions
6 | val sum = arithmeticOperation(3, 4) { x, y ->
7 | x + y
8 | }
9 |
10 | println("Sum: $sum") // 7
11 |
12 | val multiply = arithmeticOperation(3, 4) { x, y ->
13 | x * y
14 | }
15 |
16 | println("Multiply: $multiply") // 12
17 |
18 |
19 | // INFO 🔥 High-order functions
20 | val bigger = compare(2, 3) { x, y ->
21 | x > y
22 | }
23 |
24 | val list = listOf(1.1, 5.3, 3.4)
25 | list.max {
26 | println("MAX double: $it")
27 | }
28 |
29 | // INFO 🔥 High-order functions
30 | // This function uses lambda
31 | val compareLambda: (Int, Int) -> Boolean = { x, y ->
32 | x > y
33 | }
34 |
35 | val bigger2 = compare(2, 3, compareLambda)
36 | println("Bigger: $bigger, Bigger2 $bigger2")
37 |
38 |
39 | val strFirst = compareStrings("Zeta", "Alpha") { x, y ->
40 | x.first() > y.first()
41 | }
42 | println("strFirst: $strFirst")
43 |
44 | val strLength = compareStrings("Zeta", "Alpha") { x, y ->
45 | x.length > y.length
46 | }
47 | println("strLength: $strLength")
48 |
49 | // lengthCompare(): (String, String) -> Boolean = { x, y -> x.length > y.length }
50 | val strLength2 = compareStrings("Alpha", "Zeta", lengthCompare())
51 | println("strLength2: $strLength2")
52 |
53 |
54 | // INFO 🔥 List High-order function
55 |
56 | val items = listOf(1, 2, 3, 4, 5)
57 |
58 | // Lambdas are code blocks enclosed in curly braces.
59 | val result: Int = items.fold(0, {
60 |
61 | // When a lambda has parameters, they go first, followed by '->'
62 | // acc: R, nextElement: T R: Int, T: Int
63 | acc: Int, nextElement: Int ->
64 |
65 | print("acc = $acc, i = $nextElement, ")
66 | val result: Int = acc + nextElement
67 | println("result = $result")
68 | // The last expression in a lambda is considered the return value:
69 | result
70 | })
71 |
72 |
73 | // Parameter types in a lambda are optional if they can be inferred:
74 | val joinedToString = items.fold("Elements:", { acc, i -> "$acc $i" })
75 |
76 | // Function references can also be used for higher-order function calls:
77 | val product = items.fold(1, Int::times)
78 |
79 | // High order function takes String and (Int) -> Int lambda function as parameter
80 | // Returns String to int or predefined result of lambda function
81 | // INFO 🔥 High-order function takes a LAMBDA function
82 | highOrderFun("3", lambdaFun())
83 |
84 | // INFO 🔥 High-order function takes a REGULAR function that returns LAMBDA function
85 | highOrderFun("3", nonLambdaFunction())
86 |
87 |
88 | val condition1 = 2 > 3
89 |
90 | // INFO 🔥 High-order function
91 | // this high-order function gets condition1 as Boolean, action1:() -> Unit and action2:()->Unit
92 | runWithCondition(
93 | condition1,
94 | {
95 | println("Action1 Invoked")
96 | },
97 | lambdaAction2()
98 | )
99 |
100 | }
101 |
102 | fun arithmeticOperation(num1: Int, num2: Int, predicate: (Int, Int) -> Int): Int {
103 | return predicate(num1, num2)
104 | }
105 |
106 | // INFO 🔥 High-order function
107 | fun compare(num1: Int, num2: Int, action: (Int, Int) -> Boolean): Boolean {
108 | return action(num1, num2)
109 | }
110 |
111 | // INFO 🔥 High-order function
112 | fun compareStrings(str1: String, str2: String, block: (String, String) -> Boolean): Boolean {
113 | return block(str1, str2)
114 | }
115 |
116 |
117 | // INFO 🔥 Lambda function
118 | fun lengthCompare(): (String, String) -> Boolean = { x, y -> x.length > y.length }
119 |
120 |
121 | // INFO 🔥 High-order function
122 | fun Collection.fold(
123 | initial: R,
124 | combine: (acc: R, nextElement: T) -> R
125 | ): R {
126 |
127 | var accumulator: R = initial
128 |
129 | for (element: T in this) {
130 | accumulator = combine(accumulator, element)
131 | }
132 |
133 | return accumulator
134 | }
135 |
136 | fun List.max(action: (T) -> Unit) {
137 |
138 | var max: Double = 0.0
139 | for (element: T in this) {
140 | element.toInt() > max
141 | }
142 | forEach {
143 | val number: Double = (it as? Double) ?: 0.0
144 | if (number > max) max = number
145 | }
146 |
147 | (max as? T)?.let {
148 | action(it)
149 | }
150 | }
151 |
152 | // INFO 🔥 High-order function
153 | fun invokeAfterDelay(delayInMs: Long, predicateAfterDelay: () -> Unit) {
154 | println("STARTING DELAY FUNCTION")
155 | delay(delayInMs)
156 | predicateAfterDelay()
157 | }
158 |
159 |
160 | fun delay(timeInMillis: Long = 0) {
161 | Thread.sleep(timeInMillis)
162 | }
163 |
164 |
165 | // INFO 🔥 High-order function
166 | fun highOrderFun(str: String, predicate: (String) -> Int): Int {
167 | return predicate(str)
168 | }
169 |
170 | // INFO 🔥 Lambda function
171 | fun lambdaFun(): (String) -> Int = {
172 | it.toIntOrNull() ?: -1
173 | }
174 |
175 | // INFO 🔥🔥 NOT a lambda function, REGULAR function that returns a LAMBDA function
176 | fun nonLambdaFunction(): (String) -> Int {
177 | return { s: String -> s.toIntOrNull() ?: -1 }
178 | }
179 |
180 | // INFO 🔥 High-order function
181 | fun runWithCondition(condition: Boolean, action1: () -> Unit, action2: (() -> Unit)? = null) {
182 | if (condition) action1()
183 | else if (action2 != null) action2()
184 | }
185 |
186 | // INFO 🔥 Lambda Function
187 | fun lambdaAction2(): () -> Unit = {
188 | println("Action2 Invoked")
189 | }
190 |
191 |
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter4Functions/Tutorial4_2FunctionTypes.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter4Functions
2 |
3 | fun main() {
4 |
5 |
6 | // INFO 🔥 Custom class that implements a function type as an interface
7 | val intFunction: (Int) -> Int = IntTransformer()
8 | println("intFunction: $intFunction(5)") // prints x * x
9 |
10 |
11 | // Lambda Expression that takes 2 int params and returns int
12 | val testFun: (Int, Int) -> Int = { x, y -> x + y }
13 | val testFunInferred = { x: Int, y: Int -> x + y }
14 | // Lambda means-> testFun: (Int, Int) -> Int
15 | val resFun = testFun(2, 4)
16 |
17 | // The compiler can infer the function types for variables if there is enough information:
18 | val a = { i: Int -> i + 1 } // The inferred type is (Int) -> Int
19 | println("a ${a(2)}")
20 |
21 |
22 | // INFO 🔥🔥 BaseClassA value of type (BaseClassA, InterfaceB) -> C can be passed or assigned
23 | // where a BaseClassA.(InterfaceB) -> C
24 | val repeatFun: String.(Int) -> String = { times:Int ->
25 | this.repeat(times)
26 | }
27 | val twoParameters: (String, Int) -> String = repeatFun // OK
28 | val twoParams: (String, Int) -> String = { str, times -> str.repeat(times) }
29 |
30 | val result = runTransformation(repeatFun) // OK
31 | val result2 = runTransformation(twoParameters)
32 | val result3 = runTransformation(twoParams)
33 |
34 | twoParameters("hi", 4)
35 |
36 | println("result: $result") // prints hello-hello-hello-
37 | println("result2: $result2") // prints hello-hello-hello-
38 | println("result3: $result3") // prints hello-hello-hello-
39 |
40 |
41 | // INFO 🔥 Invoking a function type instance
42 |
43 | // If the value has a receiver type, the receiver object should be passed as the first argument.
44 | // Another way to invoke a value of a function type with receiver is to prepend it with the receiver object,
45 | // as if the value were an extension function: 1.foo(2) ,
46 |
47 | val stringPlus: (String, String) -> String = String::plus
48 |
49 | // INFO 🔥 Both mean same thing
50 | // val intPlus: Int.(Int) -> Int = Int::plus
51 | val intPlus: Int.(Int) -> Int = { x -> this.plus(x) }
52 |
53 | println(stringPlus.invoke("<-", "->"))
54 | println(stringPlus("Hello, ", "world!"))
55 |
56 | println(intPlus.invoke(1, 1))
57 | println(intPlus(1, 2))
58 | println(2.intPlus(3)) // extension-like call
59 |
60 |
61 | val testString = "Hello World"
62 |
63 | // INFO High Order Function
64 | val resultHighOrder: String = exampleHighOrder(testString) {
65 | it.uppercase()
66 | }
67 |
68 | // INFO Function Literal With Receiver
69 | val resultLiteralReceiver: String = exampleLiteralWithReceiver(testString) {
70 | uppercase()
71 | }
72 |
73 | // INFO Extension Function
74 | val resultExtension: String = testString.exampleExtension {
75 | it.uppercase()
76 | }
77 |
78 | // INFO Extension Function that Literal With Receiver
79 | val resultExtensionLiteral: String = testString.exampleLiteralExtension {
80 | uppercase()
81 | }
82 |
83 | println("TEST-> resultHighOrder: $resultHighOrder, resultLiteralReceiver: $resultLiteralReceiver, resultExtension: $resultExtension, resultExtensionLiteral: $resultExtensionLiteral")
84 |
85 |
86 | }
87 |
88 |
89 | // INFO 🔥 Custom class that implements a function type as an interface
90 | class IntTransformer : (Int) -> Int {
91 | // override operator fun invoke(x: Int): Int = TODO()
92 | override operator fun invoke(x: Int): Int = x * x
93 | }
94 |
95 | // INFO 🔥 BaseClassA value of type (BaseClassA, InterfaceB) -> C can be passed or assigned where a BaseClassA.(InterfaceB) -> C
96 | fun runTransformation(action: (String, Int) -> String): String {
97 | return action("hello-", 3)
98 | }
99 |
100 | /*
101 | INFO 🔥 Both functions give the same result
102 | * First function is High Order function that takes function as a param that takes String as param
103 | * Second function is Function Literal With Receiver that is action is extension function of String
104 | * Third one is Extension Function which is called by a String object only
105 | * and this corresponds to String inside the function
106 | */
107 |
108 | // INFO 🔥 High Order Function
109 | fun exampleHighOrder(value: String, action: (String) -> String): String {
110 | return action(value)
111 | }
112 |
113 | /**
114 | action: String.() defines here that if we have a String inside this function
115 | that String call action() with no params since its String extension with .()
116 |
117 | 😎 Basically it means: action() lambda will be called only by receiver(String) inside this high-order
118 | function.
119 |
120 | 🎃 If we want to call lambda action() with any param, for instance action(String)
121 | we should change action: String.() to String.(String)
122 |
123 | */
124 | // INFO 🔥 Function Literal With Receiver
125 | fun exampleLiteralWithReceiver(value: String, action: String.() -> String): String {
126 | // INFO Both result implementations are the same
127 |
128 | // value here act as String of String.() and action is without params()
129 | val result = value.action()
130 | return result
131 | }
132 |
133 | /**
134 | * This is an extension function that does not require a String param since only String class instance
135 | * can call this function, and this caller String can be sent as a parameter to lambda
136 | * by using action(this)
137 | */
138 | // INFO 🔥 High Order Extension Function
139 | fun String.exampleExtension(action: (String) -> String): String {
140 | val result = action(this)
141 | return result
142 | }
143 |
144 | /**
145 | * This function is an extension function which can be called only by a String instance.
146 | * Since it has String.() literal with receiver and receiver is a String,
147 | * it's already called on a String which does not require a parameter as the function above
148 | */
149 | // INFO 🔥 Extension Function that Literal With Receiver
150 | fun String.exampleLiteralExtension(action: String.() -> String): String {
151 | // INFO Both result implementations are the same
152 | val result = action()
153 | return result
154 | }
155 |
156 |
--------------------------------------------------------------------------------
/tutorial/src/main/java/com/smarttoolfactory/tutorial/chapter4Functions/Tutorial4_3LambdaExpressions.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter4Functions
2 |
3 |
4 | /*
5 | Lambda function takes parameters from when it's invoked
6 | definition uses that argument in codeBody
7 |
8 | val lambdaName : Type = { argumentList -> codeBody }
9 | or
10 | val lambdaName: Type = {argument: TypeOfArgument -> codeBody }
11 | */
12 | fun main() {
13 |
14 | // INFO 🔥 Lambda Expression
15 | val lambda1: (String) -> Unit = { s -> println(s) }
16 | lambda1("lambda1 String")
17 |
18 |
19 | val lambda2 = { s: String -> println(s) }
20 | lambda2("lambda2 String 2")
21 |
22 | val sumAlternative1 = { x: Int, y: Int -> x + y }
23 | val sumAlternative2: (Int, Int) -> Int = { x, y -> x + y }
24 | println("Sum Alt1: ${sumAlternative1(2, 3)}")
25 | println("Sum Alt2: ${sumAlternative2(2, 3)}")
26 |
27 | // INFO Passing Lambda as last parameter
28 | val items = listOf(1, 2, 3)
29 |
30 | // If lambda is the last parameter it can be taken outside the parenthesis
31 | val prod = items.fold(1, { acc, e -> acc * e })
32 | val product = items.fold(1) { acc, e -> acc * e }
33 |
34 | // If the lambda is the only argument to that call, the parentheses can be omitted entirely:
35 | run { println("...") }
36 |
37 | // Info Single parameter it
38 | val ints = listOf(1, 2, 3)
39 | ints.filter { it > 0 } // this literal is of type '(it: Int) -> Boolean'
40 |
41 |
42 | // INFO 🔥🔥🔥 Lambda Expression with Receiver
43 |
44 | // Lambda expression that has a Receiver String. and function literal () -> Unit that returns Unit
45 |
46 |
47 | val greet: String.() -> Unit = {
48 | println("Function Literal Receiver: $this")
49 | }
50 |
51 | // Both implementations have same results
52 | greet("TestStringConcatenation String")
53 | "TestStringConcatenation String".greet()
54 |
55 | // Lambda expression that has a Receiver String. and function literal () -> String that returns a String
56 | val myString: String.() -> String = {
57 | "length is ${this.length}"
58 | }
59 | println("myString: ${myString("TestStringConcatenation")}")
60 | "TestStringConcatenation".myString()
61 |
62 | // Lambda expression that has a Receiver Int. and function literal () -> Boolean that returns a Boolean
63 | // 🤨 isEven becomes EXTENSION of an Integer by Int.(). () with no params means that
64 | // 🤨 isEven is called such as 3.isEven() or isEven(3)
65 | val isEven: Int.() -> Boolean = {
66 | this % 2 == 0
67 | }
68 | // Both returns same result
69 | isEven(3)
70 | 3.isEven()
71 |
72 | // Lambda expression that has a Receiver Int. and function literal (Int) -> Boolean that returns a Boolean
73 | val isWithCarry: Int.(Int) -> Boolean = { divider: Int ->
74 | this % divider != 0
75 | }
76 |
77 |
78 | // Both returns same result
79 | isWithCarry(3, 2)
80 | 3.isWithCarry(2)
81 |
82 |
83 | val total: Int.(Int) -> Int = { other -> this.plus(other) }
84 | println("Function Literal with Receiver total2: Int.(Int)-> Int: " + total(3, 4))
85 |
86 |
87 | val testLambdaReceiver: String.(Int) -> String = { number: Int ->
88 | this + number
89 | }
90 |
91 | testLambdaReceiver("Hello", 4)
92 | "Hello".testLambdaReceiver(4)
93 |
94 | // INFO 🔥🔥 Anonymous Function with Receiver
95 | // The anonymous function syntax allows you to specify the receiver type of a function literal directly.
96 | // This can be useful if you need to declare a variable of a function type with receiver, and to use it later.
97 | val sumWithLiteralParam = fun Int.(other: Int): Int = this + other
98 | val res1: Int = sumWithLiteralParam(3, 4)
99 | val res2: Int = 3.sumWithLiteralParam(4)
100 |
101 |
102 | // INFO 🔥🔥 Function Literal with Receiver
103 | // This function is defined as Function Literal with Receiver
104 | val isOdd = isOdd(4) {
105 | this % 2 == 1
106 | }
107 |
108 | createString({
109 |
110 | })
111 |
112 | // Function Literal with Receiver without Parentheses
113 | val stringCreated = createString {
114 | //here we're in the context of a `StringBuilder`
115 | append(4)
116 | append("hello")
117 |
118 |
119 | }
120 | println("stringCreated $stringCreated")
121 |
122 | val sb = StringBuilder()
123 | // val sbNew = extra({
124 | //
125 | // })
126 | //
127 | // extra {
128 | //
129 | // }
130 |
131 | // val ch = sbNew.extra2(3) {
132 | // val num = it * 2
133 | // num
134 | // }
135 |
136 | // INFO 🔥🔥 Function Literal that returns String
137 | val upperCase = createStringBlock(4) {
138 |
139 | // Thi predicate function returns String
140 | "createStringBlock $it"
141 | }
142 |
143 | println("Uppercase String: $upperCase")
144 |
145 | }
146 |
147 |
148 | // INFO 🔥🔥 Function Literal that returns Boolean
149 | fun isOdd(value: Int, action: Int.() -> Boolean): Boolean {
150 | // return action(value)
151 | return value.action()
152 | }
153 |
154 | // INFO 🔥🔥 High Oder Function
155 | fun createStringBlock(num: Int, block: (Int) -> String): String {
156 | return block(num).uppercase()
157 | }
158 |
159 |
160 | // INFO 🔥🔥 Function Literal with Receiver
161 | // StringBuilder.() sets this function as extension function of StringBuilder class
162 | // receiver is defined as StringBuilder
163 | fun createString(block: StringBuilder.() -> Unit): String {
164 |
165 | val sb = StringBuilder() // create the receiver object
166 | sb.block() // pass the receiver object to the lambda
167 |
168 | return sb.toString()
169 | }
170 |
171 | // INFO 🔥 Extension Functions Literal with Receiver
172 | fun StringBuilder.extra(block: StringBuilder.() -> Unit): StringBuilder {
173 | block()
174 | return this
175 | }
176 |
177 | fun StringBuilder.extra2(value: Int, block: (Int) -> Int): StringBuilder {
178 | this.append(block(value).toString())
179 | return this
180 | }
--------------------------------------------------------------------------------
/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/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/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/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/chapter6Advanced/DelegatedProperty.kt:
--------------------------------------------------------------------------------
1 | package com.smarttoolfactory.tutorial.chapter6Advanced
2 |
3 | import kotlin.reflect.KProperty
4 |
5 |
6 | fun main() {
7 |
8 | var delegatedNum1 by CalculateDelegate()
9 | var delegatedNum2 by delegateCalculationFunction()
10 |
11 | println("Initial delegatedNum1: $delegatedNum1, delegatedNum2: $delegatedNum2")
12 | delegatedNum1 = 4
13 | delegatedNum2 = 3
14 |
15 | println("Final delegatedNum1: $delegatedNum1, delegatedNum2: $delegatedNum2")
16 |
17 | /*
18 | Prints:
19 | 🔥 CalculateDelegate getValue() thisRef: null, property: var delegatedNum1: kotlin.Int
20 | 🔥 CalculateDelegate getValue() thisRef: null, property: var delegatedNum2: kotlin.Int
21 | Initial delegatedNum1: 0, delegatedNum2: 0
22 | 🤔 CalculateDelegate setValue() thisRef: null, property: var delegatedNum1: kotlin.Int, value: 4
23 | 🤔 CalculateDelegate setValue() thisRef: null, property: var delegatedNum2: kotlin.Int, value: 3
24 | 🔥 CalculateDelegate getValue() thisRef: null, property: var delegatedNum1: kotlin.Int
25 | 🔥 CalculateDelegate getValue() thisRef: null, property: var delegatedNum2: kotlin.Int
26 | Final delegatedNum1: 8, delegatedNum2: 6
27 | */
28 |
29 | //
30 | // val owner = Owner()
31 | // val newRes = Resource(5)
32 | //
33 | // println("Owner res: ${owner.varResource}")
34 | // owner.varResource = newRes
35 | // println("Owner res: ${owner.varResource}")
36 |
37 | /*
38 | Prints:
39 | 🚀 ResourceDelegate getValue() thisRef: chapter6Advanced.Owner@4445629, property: var chapter6Advanced.Owner.varResource: chapter6Advanced.Resource
40 | Owner res: chapter6Advanced.Resource@1622f1b
41 | 🍒 ResourceDelegate getValue() thisRef: chapter6Advanced.Owner@4445629, property: var chapter6Advanced.Owner.varResource: chapter6Advanced.Resource, value: chapter6Advanced.Resource@72a7c7e0
42 | 🚀 ResourceDelegate getValue() thisRef: chapter6Advanced.Owner@4445629, property: var chapter6Advanced.Owner.varResource: chapter6Advanced.Resource
43 | Owner res: chapter6Advanced.Resource@72a7c7e0
44 | */
45 |
46 | }
47 |
48 | /**
49 | * Delegate [CalculateDelegate] to this function
50 | */
51 | fun delegateCalculationFunction() = CalculateDelegate()
52 |
53 | class CalculateDelegate {
54 | var value = 0
55 |
56 | operator fun getValue(thisRef: Any?, property: KProperty<*>): Int {
57 | println("🔥 CalculateDelegate getValue() thisRef: $thisRef, property: $property")
58 | return value
59 | }
60 |
61 | operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) {
62 | println("🤔 CalculateDelegate setValue() thisRef: $thisRef, property: $property, value: $value")
63 | this.value = value * 2
64 | }
65 |
66 | }
67 |
68 |
69 | @Suppress("NOTHING_TO_INLINE")
70 | inline operator fun CalculateDelegate.getValue(thisRef: Any?, property: KProperty<*>): Int = value
71 |
72 |
73 | @Suppress("NOTHING_TO_INLINE")
74 | inline operator fun CalculateDelegate.setValue(thisObj: Any?, property: KProperty<*>, value: Int) {
75 | this.value = value
76 | }
77 |
78 | /*
79 | JAVA
80 |
81 | static final KProperty[] $$delegatedProperties =
82 | new KProperty[]{(KProperty)Reflection.mutableProperty0(new MutablePropertyReference0Impl(DelegatedPropertyKt.class, "delegatedNum1", "", 1)), (KProperty)Reflection.mutableProperty0(new MutablePropertyReference0Impl(DelegatedPropertyKt.class, "delegatedNum2", "", 1))};
83 |
84 | public static final void main() {
85 | CalculateDelegate var10000 = new CalculateDelegate();
86 | KProperty var1 = $$delegatedProperties[0];
87 | CalculateDelegate delegatedNum1 = var10000;
88 | var10000 = delegateCalculationFunction();
89 | KProperty var3 = $$delegatedProperties[1];
90 | CalculateDelegate delegatedNum2 = var10000;
91 | String var4 = "Initial delegatedNum1: " + delegatedNum1.getValue((Object)null, var1) + ", delegatedNum2: " + delegatedNum2.getValue((Object)null, var3);
92 | boolean var5 = false;
93 | System.out.println(var4);
94 | delegatedNum1.setValue((Object)null, var1, 4);
95 | delegatedNum2.setValue((Object)null, var3, 3);
96 | var4 = "Final delegatedNum1: " + delegatedNum1.getValue((Object)null, var1) + ", delegatedNum2: " + delegatedNum2.getValue((Object)null, var3);
97 | var5 = false;
98 | System.out.println(var4);
99 | }
100 |
101 |
102 | public final class CalculateDelegate {
103 | private int calculatedProperty;
104 |
105 | public final int getValue(@Nullable Object thisRef, @NotNull KProperty property) {
106 | Intrinsics.checkNotNullParameter(property, "property");
107 | String var3 = "\ud83d\udd25 CalculateDelegate getValue() thisRef: " + thisRef + ", property: " + property;
108 | boolean var4 = false;
109 | System.out.println(var3);
110 | return this.calculatedProperty;
111 | }
112 |
113 | public final void setValue(@Nullable Object thisRef, @NotNull KProperty property, int value) {
114 | Intrinsics.checkNotNullParameter(property, "property");
115 | String var4 = "\ud83e\udd14 CalculateDelegate setValue() thisRef: " + thisRef + ", property: " + property + ", value: " + value;
116 | boolean var5 = false;
117 | System.out.println(var4);
118 | this.calculatedProperty = value * 2;
119 | }
120 | }
121 | */
122 |
123 | class Resource(var id: Int = 0) {
124 | override fun toString(): String {
125 | return "${super.toString()} with id: $id"
126 | }
127 | }
128 |
129 | class Owner {
130 | var varResource: Resource by ResourceDelegate()
131 | }
132 |
133 | class ResourceDelegate(private var resource: Resource = Resource()) {
134 |
135 | operator fun getValue(thisRef: Owner, property: KProperty<*>): Resource {
136 |
137 | println("🚀 ResourceDelegate getValue() thisRef: $thisRef, property: $property")
138 | return resource
139 | }
140 |
141 | operator fun setValue(thisRef: Owner, property: KProperty<*>, value: Any?) {
142 |
143 | println("🍒 ResourceDelegate getValue() thisRef: $thisRef, property: $property, value: $value")
144 | if (value is Resource) {
145 | resource = value
146 | }
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/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