Last active
April 25, 2019 10:17
-
-
Save muthuraj57/446128b34eba099425574417cb6c37e7 to your computer and use it in GitHub Desktop.
Kotlin Basics
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.muthuraj.kotlinBasics.kotlinbasics; | |
import android.graphics.Color; | |
import android.util.Log; | |
import android.view.View; | |
import android.widget.TextView; | |
import androidx.annotation.NonNull; | |
import org.json.JSONException; | |
import org.json.JSONObject; | |
import java.io.*; | |
import java.util.ArrayList; | |
import java.util.List; | |
/** | |
* Created by Muthuraj on 2019-03-13. | |
* <p> | |
*/ | |
public class JavaClass { | |
private String someField = "test"; | |
public static class Dog { | |
String name; | |
String owner; | |
String anotherField = "test"; | |
public Dog(){ | |
} | |
public Dog(String name, String owner) { | |
this.name = name; | |
this.owner = owner; | |
} | |
final void print(){ | |
new DogKt.InnerDog(); | |
System.out.println("Name: " + name + ", Owner: " + owner); | |
System.out.println(this); | |
DogKt dogKt = new DogKt("name", "owner"); | |
dogKt.getName(); | |
} | |
void setDetailsInterface(DetailsInterface detailsInterface){ | |
detailsInterface.getDetails(); | |
} | |
@NonNull | |
@Override | |
public String toString() { | |
return "Name: " + name + ", Owner: " + owner; | |
} | |
String getName(){ | |
return name; | |
} | |
String getOwner(){ | |
return owner; | |
} | |
// public void setName(String name) { | |
// this.name = name; | |
// } | |
public void setOwner(String owner) { | |
this.owner = owner; | |
} | |
@Override | |
public boolean equals(Object o) { | |
if (this == o) return true; | |
if (o == null || getClass() != o.getClass()) return false; | |
Dog dog = (Dog) o; | |
if (name != null ? !name.equals(dog.name) : dog.name != null) return false; | |
return owner != null ? owner.equals(dog.owner) : dog.owner == null; | |
} | |
} | |
// <========================== Function =========================> | |
int add(int a, int b){ | |
return a + b; | |
} | |
void addAndPrint(int a, int b){ | |
System.out.println(a+b); | |
} | |
// <========================== Late init =========================> | |
String variable = ""; | |
int a = 10; | |
String anotherVariable; | |
void initializeVariable(){ | |
anotherVariable = "value goes here"; | |
} | |
//Calling access() before initializeVariable will crash with | |
//NullPointerException exception | |
void access(){ | |
System.out.println(anotherVariable); | |
} | |
// <========================== Object creation =========================> | |
Dog dogInstance = new Dog("Tiger", "Muthu"); | |
void test(){ | |
dogInstance.print(); | |
} | |
// <========================== Val, Var =========================> | |
final String logTag = "Java"; | |
String logTagAnother = "Java"; | |
void test1(){ | |
logTag = "Cannot change"; //Compile time error | |
logTagAnother = "Can change this"; | |
} | |
// <========================== Smart casting =========================> | |
void test2(){ | |
String value = null; | |
int a; | |
if (value == null) { | |
System.out.println(value.length()); // Run time error (crash) | |
a = 1; | |
} else{ | |
System.out.println(value.length()); | |
a = 2; | |
} | |
} | |
// <========================== Named Arguments =========================> | |
void test5(){ | |
Dog dog = new Dog("Tiger", "Muthu"); | |
} | |
// <========================== Default Arguments =========================> | |
//Default arguments can be achieved in Java using method overriding | |
String formatString(String str, boolean upperCase, boolean printLog){ | |
if(upperCase){ | |
if(printLog){ | |
String result = str.toUpperCase(); | |
Log.d("formatString", result); | |
return result; | |
} else{ | |
return str.toUpperCase(); | |
} | |
} else{ | |
if(printLog){ | |
Log.d("formatString", str); | |
} | |
return str; | |
} | |
} | |
String formatString(String str){ | |
return formatString(str, false, false); | |
} | |
void test6(){ | |
formatString("test", false, true); | |
formatString("test"); | |
} | |
// <========================== Static =========================> | |
static String NAME = "StaticExample"; | |
static final int AGE = 20; | |
void test3(){ | |
NAME = "Some other value"; | |
AGE = 21; //Compile time error | |
} | |
static void staticMethod(){ | |
} | |
static class Test{ | |
} | |
// <========================== Loops =========================> | |
void test7(){ | |
List<String> list = new ArrayList<>(); | |
list.add("1"); | |
list.add("2"); | |
list.add("3"); | |
list.add("4"); | |
list.add("5"); | |
for (String item : list) { | |
System.out.println("item: "+item); | |
} | |
} | |
// <========================== Inheritance, Object, Override =========================> | |
class BullDog extends Dog implements SomeInterface{ | |
public BullDog(String name, String owner) { | |
super(name, owner); | |
//network call | |
} | |
public BullDog(String name) { | |
super(name, "test"); | |
//network call | |
} | |
@Override | |
public void method() { | |
} | |
void printBullDog(){ | |
System.out.println("BullDog name: " + name + ", owner: " + owner); | |
} | |
} | |
interface SomeInterface{ | |
void method(); | |
} | |
// <========================== init block =========================> | |
// <========================== Casting, Type check =========================> | |
void test4(){ | |
Dog dog = new Dog("name goes here", "owner goes here"); | |
((BullDog) dog).printBullDog(); | |
if (dog instanceof BullDog) { | |
((BullDog) dog).printBullDog(); | |
} else{ | |
dog.print(); | |
} | |
} | |
void test5(Object obj){ | |
if (obj instanceof String) { | |
((String) obj).length(); | |
} | |
((String) obj).length(); | |
} | |
// <========================== Switch vs when =========================> | |
void test6(Object obj){ | |
String a = "2"; | |
String b = "4"; | |
boolean sss; | |
if(a == b){ | |
sss = true; | |
} else{ | |
sss = false; | |
} | |
String res = ""; | |
if(obj == 1 || obj == 2){ | |
res = "One"; | |
} else if(obj == "Testing"){ | |
res = "Testing String"; | |
} else if(obj instanceof Long){ | |
res = "Long"; | |
} else if(!(obj instanceof Double)){ | |
res = "Not a Double"; | |
} | |
switch (((int) obj)){ | |
case 1: | |
res = "one"; | |
break; | |
case 2: | |
res = "two"; | |
break; | |
default: | |
res = "no value"; | |
break; | |
} | |
} | |
// <========================== Singleton =========================> | |
//Refer SingletonExample.java | |
// <========================== Lambda =========================> | |
void lambdaTes(){ | |
TextView textView = new TextView(this); | |
//Java classic Anonymous inner class | |
textView.setOnClickListener(new View.OnClickListener() { | |
@Override | |
public void onClick(View v) { | |
//showToast | |
} | |
}); | |
//Java lambda | |
textView.setOnClickListener(v -> { | |
//showToast | |
}); | |
Dog dog = new Dog(); | |
dog.setDetailsInterface(new DetailsInterface() { | |
@Override | |
public void getDetails() { | |
//Do something | |
} | |
}); | |
} | |
interface DetailsInterface { | |
void getDetails(); | |
} | |
// <========================== Collections =========================> | |
private List<String> list = new ArrayList<>(); | |
void test8(){ | |
list.add("apple"); | |
list.add("orange"); | |
} | |
// <========================== Inner class =========================> | |
/* | |
* 1. Normal inner classes can access outer class members | |
* 2. Normal inner classes can only be created with outer class instance | |
* 3. Static inner classes can't access outer class members | |
* 4. Static inner classes can be created directly without any instance | |
* */ | |
// <========================== Equality =========================> | |
// == checks reference | |
// .equals() checks value | |
void testEquality(){ | |
String first = null;//"Test"; | |
String second = "Test"; | |
boolean firstResult = first == second; //returns true | |
String stringFromSomeCalculation = "OneTestOne".substring(3, 7); | |
boolean secondResult = stringFromSomeCalculation == second; // returs false | |
first.equals(second); // will crash since first is null | |
} | |
// <========================== Exceptions =========================> | |
//Checked exceptions should be handled with try catch or | |
//throws should be added in Class/method signature | |
JSONObject toJson(String jsonString) throws JSONException { | |
return new JSONObject(jsonString); | |
} | |
void exceptionTest(){ | |
String string = " \"data\" : { \"key\" : \"value\" }"; | |
//Compiler error since exception is handled | |
JSONObject jsonObj = toJson(string); | |
try { | |
JSONObject jsonObject = toJson(string); // works fine | |
} catch (JSONException e) { | |
e.printStackTrace(); | |
} | |
} | |
// <========================== Closable =========================> | |
void testClosable(){ | |
//Classic Java way | |
FileInputStream fileInputStream = null; | |
try { | |
fileInputStream = new FileInputStream(new File("test.txt")); | |
//do something with fileInputStream | |
} catch (FileNotFoundException e) { | |
e.printStackTrace(); | |
} finally { | |
if (fileInputStream != null) { | |
try { | |
fileInputStream.close(); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
} | |
} | |
//Try with resources | |
try (FileInputStream stream = new FileInputStream(new File("test.txt"))) { | |
//do something with stream | |
} catch (FileNotFoundException e) { | |
e.printStackTrace(); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
} | |
// <========================== Extension functions =========================> | |
JSONObject toJson(String jsonString) throws JSONException { | |
return new JSONObject(jsonString); | |
} | |
int toColor(String colorValue){ | |
return Color.parseColor(colorValue); | |
} | |
void extenstionFuncTest(){ | |
String string = " \"data\" : { \"key\" : \"value\" }"; | |
String value = "#ff3431"; | |
JSONObject json = toJson(string); | |
int color = toColor(value); | |
} | |
// <========================== Collections utils =========================> | |
void collectionsUtilTest(){ | |
List<Integer> list = new ArrayList<>(); | |
list.add(1); | |
list.add(2); | |
list.add(3); | |
list.add(4); | |
list.add(5); | |
List<String> result = new ArrayList<>(); | |
for (Integer value :list){ | |
if (value > 2) { | |
result.add(value.toString()); | |
} | |
} | |
} | |
// <========================== Common Extensions - Java equivalent=========================> | |
private Dog dog = null; | |
void commonExtensionsTest(){ | |
dog = new Dog(); | |
dog.name = "something"; | |
dog.owner = "owner"; | |
if (dog != null) { | |
String name = dog.name; | |
if (name != null && !name.isEmpty()) { | |
someOtherFunction(name); | |
} | |
} | |
} | |
void someOtherFunction(String name){ | |
//Do something | |
} | |
// <========================== Data class =========================> | |
class Name{ | |
private String firstName; | |
private String lastName; | |
public Name(String firstName, String lastName){ | |
this.firstName = firstName; | |
this.lastName = lastName; | |
} | |
public String getFirstName() { | |
return firstName; | |
} | |
public void setFirstName(String firstName) { | |
this.firstName = firstName; | |
} | |
public String getLastName() { | |
return lastName; | |
} | |
public void setLastName(String lastName) { | |
this.lastName = lastName; | |
} | |
@Override | |
public boolean equals(Object o) { | |
if (this == o) return true; | |
if (o == null || getClass() != o.getClass()) return false; | |
Name name = (Name) o; | |
if (firstName != null ? !firstName.equals(name.firstName) : name.firstName != null) return false; | |
return lastName != null ? lastName.equals(name.lastName) : name.lastName == null; | |
} | |
@Override | |
public int hashCode() { | |
int result = firstName != null ? firstName.hashCode() : 0; | |
result = 31 * result + (lastName != null ? lastName.hashCode() : 0); | |
return result; | |
} | |
@Override | |
public String toString() { | |
return "Name{" + | |
"firstName='" + firstName + '\'' + | |
", lastName='" + lastName + '\'' + | |
'}'; | |
} | |
} | |
void dataClassTest(){ | |
Name name = new Name("Muthu", "Raj"); | |
Name anotherName = new Name("Muthu", "Raj"); | |
name.equals(anotherName); | |
System.out.println(name); | |
} | |
// <========================== Enums =========================> | |
enum LoginStateEnum{ | |
LOGGED_IN, | |
LOGGING_IN, | |
LOGGED_OUT | |
} | |
void enumTest(){ | |
LoginStateEnum loggedInState = getLoggedInEnumState(); | |
switch (loggedInState) { | |
case LOGGED_IN: | |
System.out.println("Logged in "); | |
//Update UI to reflect login state | |
break; | |
case LOGGED_OUT: | |
System.out.println("Logged out"); | |
//Update UI to reflect logged state | |
break; | |
} | |
} | |
LoginStateEnum getLoggedInEnumState(){ | |
//check and return current login state | |
return LoginStateEnum.LOGGED_IN; | |
} | |
String enumCheckAllBranches(){ | |
LoginStateEnum loggedInState = getLoggedInEnumState(); | |
String state = ""; | |
switch (loggedInState) { | |
case LOGGED_IN: | |
state = "Logged in"; | |
break; | |
case LOGGED_OUT: | |
state = "Logged out"; | |
break; | |
} | |
return state; | |
} | |
// <========================== Sealed Class =========================> | |
class LoginState{ | |
} | |
class LoggedIn extends LoginState{ | |
String name; | |
public LoggedIn(String name) { | |
this.name = name; | |
} | |
} | |
class LoggedOut extends LoginState{ | |
} | |
LoginState getLoggedInState() { | |
if(true /*login check*/){ | |
return new LoggedIn("Muthuraj"); | |
} else{ | |
return new LoggedOut(); | |
} | |
} | |
void loginTest(){ | |
LoginState loginState = getLoggedInState(); | |
if(loginState instanceof LoggedIn){ | |
String userName = ((LoggedIn) loginState).name; | |
//Update UI | |
} else if(loginState instanceof LoggedOut){ | |
//Update UI | |
} | |
} | |
// <========================== Ranges =========================> | |
void ranges(){ | |
for (int i = 0; i < 10; i++) { | |
System.out.println(i); | |
} | |
} | |
void getViewGroupChildren(){ | |
List<View> children = new ArrayList<>(); | |
LinearLayout linearLayout = new LinearLayout(this); | |
for (int i = 0; i < linearLayout.getChildCount(); i++) { | |
children.add(linearLayout.getChildAt(i)); | |
} | |
} | |
// <========================== Compile time constants =========================> | |
//There is no compile time constants in Java | |
class Constants{ | |
public static final String URL = "https://www.google.com"; | |
public static final String EVENT = "clicked"; | |
} | |
// <========================== Multi line String =========================> | |
public static void main(String[] args) { | |
multiLineString(); | |
} | |
static void multiLineString(){ | |
String s = "This" + | |
"is" + | |
"a " + | |
"multi-" + | |
"line" + | |
"string"; | |
System.out.println(s); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* $Id$ */ | |
package com.muthuraj.kotlinBasics.kotlinbasics | |
import android.graphics.Color | |
import android.util.Log | |
import android.view.View | |
import android.view.ViewGroup | |
import android.widget.TextView | |
import androidx.recyclerview.widget.RecyclerView | |
import com.muthuraj.kotlinBasics.kotlinbasics.JavaClass.* | |
import org.json.JSONObject | |
import java.io.File | |
import java.io.FileInputStream | |
import java.lang.Exception | |
import java.util.ArrayList | |
/** | |
* Created by Muthuraj on 2019-03-13. | |
* | |
*/ | |
open class DogKt(var name: String, val owner: String = "test") { | |
open val anotherField: String = "test" | |
//Another way to provide constructor | |
// constructor(name: String = "Muthu", owner: String = "Owner") { | |
// this.name = name | |
// this.owner = owner | |
// } | |
fun print(): Int{ | |
val s = 1 | |
val s1 = 2 | |
//Java style string concat | |
println("Name: " + name + ", Owner: " + owner) | |
//String interpolation | |
println("Name: $name, ${s+s1} Owner: $owner") | |
val dog = Dog(name, owner) | |
return 1 | |
} | |
fun setDetailsInterface(detailsInterface: DetailsInterface){ | |
detailsInterface.getDetails() | |
} | |
//Custom operator overloading | |
operator fun plusAssign(name: String){ | |
this.name = name | |
} | |
class InnerDog(){ | |
init { | |
// name | |
} | |
} | |
} | |
class DogKt1(private var name: String, private var owner: String){ | |
fun print(): Int{ | |
println("Name: " + name + ", Owner: " + owner) | |
return 1 | |
} | |
} | |
// <========================== Function =========================> | |
//Function body and return keyword is not needed if return | |
// statement is single line | |
fun add(a: Int, b: Int): Int = a + b | |
//System.out.println => println | |
fun addAndPrint(a: Int, b: Int){ | |
println(a+b) | |
} | |
// <========================== Late init =========================> | |
//Also refer MainFragment in MainActivity.kt | |
var variable = "" | |
var a = 10 | |
lateinit var anotherVariable: String | |
fun initializeVariable(): Unit{ | |
anotherVariable = "value goes here" | |
} | |
//Calling access() before initializeVariable will crash with | |
//UninitializedPropertyAccessException exception | |
fun access(){ | |
println(anotherVariable) | |
} | |
// <========================== Object creation =========================> | |
var dogInstance = DogKt("Tiger", "Muthu") //no new keyword | |
fun test(){ | |
dogInstance.print() | |
} | |
// <========================== Val, Var =========================> | |
val logTag = "Kotlin" | |
var logTagAnother = "Java" | |
fun test1(){ | |
logTag = "Cannot change" //Compile time error | |
logTagAnother = "Can change this" | |
} | |
// <========================== Smart casting =========================> | |
fun test2(){ | |
var value: String? = null | |
val dog: DogKt? = null | |
val lenght = value?.length ?: 0 | |
if (value == null) { | |
println(value.length) //Compile time error | |
} else{ | |
value = "Assign some value" | |
println(value.length) //Smart casted from String? to String | |
} | |
} | |
/** | |
* Recap | |
* | |
* class | |
* fun | |
* val | |
* var | |
* void vs Unit | |
* class instance creation (no new keyword) | |
* null, not null (?.) | |
* | |
* a ?: "abv" | |
* null safety ?,?: | |
* if..else (no ternary) | |
* smart casting | |
*/ | |
// <========================== Named Arguments =========================> | |
fun test5() { | |
val dog = Dog("Muthu", "Tiger") | |
//Constructor order doesn't matter if called this way | |
val dog1 = DogKt(owner = "Muthu",name = "Tiger") | |
//Function parameters order doesn't matter if called this way | |
named("name",age = 5, owner = "Muthu") | |
} | |
fun named(name: String, owner: String?, age: Int){ | |
//Do something | |
} | |
// <========================== Default Arguments =========================> | |
fun formatString(str: String, upperCase: Boolean = false, printLog: Boolean): String { | |
if (upperCase) { | |
if (printLog) { | |
val result = str.toUpperCase() | |
Log.d("formatString", result) | |
return result | |
} else { | |
return str.toUpperCase() | |
} | |
} else { | |
if (printLog) { | |
Log.d("formatString", str) | |
} | |
return str | |
} | |
} | |
fun test6() { | |
//upperCase will be false here | |
formatString(str = "test", printLog = false) | |
} | |
// <========================== Static =========================> | |
class StaticHelper{ | |
//No static keyword. Everything inside companion is static. | |
companion object { | |
private var NAME = "StaticExample" | |
val AGE = 20 | |
fun staticMethod(){ | |
} | |
} | |
fun test3(){ | |
NAME = "Some other value" | |
AGE = 21 //Compile time error | |
} | |
} | |
// <========================== Loops =========================> | |
fun test7() { | |
val list = ArrayList<String>() | |
list.add("1") | |
list.add("2") | |
list.add("3") | |
list.add("4") | |
list.add("5") | |
for (item in list) { | |
println("item: $item") | |
} | |
} | |
// <========================== Inheritance, Any, Override =========================> | |
//Java Object == Kotlin Any | |
class BullDog(name: String, owner: String = "test"): DogKt(owner = owner, name = name), SomeInterface{ | |
//Another way to provide constructor | |
// constructor(name: String, owner: String): super(name, owner) | |
//Called after constructor invocation | |
init { | |
//network call | |
} | |
fun printBullDog(){ | |
println("BullDog name: $name, owner: $owner") | |
} | |
override val anotherField: String = "test1" | |
override fun method() { | |
} | |
} | |
interface SomeInterface{ | |
fun method() | |
} | |
// <========================== init block =========================> | |
// <========================== Casting, Type check =========================> | |
fun test4(){ | |
val dog: DogKt = DogKt("name goes here", "owner goes here") | |
(dog as? BullDog)?.printBullDog() ?: "something" | |
if (dog is BullDog) { | |
dog.printBullDog() //Smart casted from DogKt to BullDog | |
} else{ | |
dog.print() | |
} | |
} | |
fun test5(obj: Any){ | |
if (obj is String) { | |
obj.length | |
} | |
(obj as? String)?.length | |
(obj as String).length | |
} | |
/** | |
* Recap | |
* | |
* Named arguments | |
* Default arguments | |
* static fields and methods | |
* Loops | |
* Inheritance, override | |
* Any | |
* Init block | |
* Type check and type casting | |
*/ | |
// <========================== Switch vs when =========================> | |
fun test6(obj: Any?) { | |
val a = "2" | |
val b = "4" | |
val sss = if (a == b) true else false | |
val ss: String? | |
when (obj) { | |
1,2,32,4 -> ss = "One" | |
"Testing" -> ss = "Testing String" | |
is Long -> ss = "Long" | |
!is Double -> ss = "Not a Double" | |
else -> ss = null | |
} | |
val res: String | |
when(obj){ | |
1 -> { | |
res = "one"; | |
} | |
2 ->{ | |
res = "two" | |
} | |
else ->{ | |
res = "no value" | |
} | |
} | |
} | |
// <========================== Singleton =========================> | |
//Refer SingletonExample.kt | |
// <========================== Lambda =========================> | |
fun lambdaTest(){ | |
val textView = TextView(this) | |
//Kotlin lambda | |
textView.setOnClickListener {v-> | |
//showToast | |
} | |
val dog = Dog(); | |
dog.setDetailsInterface { | |
//Do something | |
} | |
//SAM conversion won't work with Kotlin interface. | |
//So anonymous inner class is the way to go here. | |
val dogKt = DogKt() | |
dogKt.setDetailsInterface(object: DetailsInterface { | |
override fun getDetails() { | |
} | |
}) | |
} | |
interface DetailsInterface{ | |
fun getDetails() | |
} | |
// <========================== Collections =========================> | |
fun test8(){ | |
//Java style | |
val list = ArrayList<String>() | |
list.add("apple") | |
list.add("orange") | |
//Kotlin style | |
val immutableList: List<String> = listOf("apple","orange") | |
val mutableList: MutableList<String> = mutableListOf("apple","orange") | |
mutableList.add("") | |
} | |
/** | |
* Recap | |
* | |
* Switch vs when | |
* Singleton (object) | |
* Lambda, SAM conversion | |
* Collections (listOf, mutableListOf) | |
*/ | |
// <========================== Top level declaration =========================> | |
//Every method, variable in this file is declared at top level | |
// <========================== Inner class =========================> | |
/* | |
* 1. Default inner class is Java style static inner class | |
* 2. Classes with `inner` keyword can access outer class member and | |
* can only be created with outer class instance | |
* */ | |
class KotlinAdapter: RecyclerView.Adapter<RecyclerView.ViewHolder>() { | |
// private val data = mutableListOf<String>() | |
//This is better than above line | |
private var data = emptyList<String>() | |
fun updateData(newData: List<String>){ | |
//For val mutableList type | |
// data.clear() | |
// data.addAll(newData) | |
//For val list type | |
data = newData | |
notifyDataSetChanged() | |
} | |
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { | |
return ViewHolder(View.inflate(parent.context, R.layout.activity_main, parent)) | |
} | |
override fun getItemCount(): Int { | |
return data.size | |
} | |
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { | |
(holder as ViewHolder).setData(data[position]) | |
} | |
} | |
class ViewHolder(private val item: View): RecyclerView.ViewHolder(item){ | |
private val textView = item.findViewById<TextView>(R.id.text_view) | |
fun setData(data: String){ | |
item | |
textView.text = data | |
} | |
} | |
// <========================== Lazy delegate =========================> | |
//Refer MainActivity.kt | |
/** | |
* Recap | |
* | |
* Top level declaration | |
* Inner class | |
* Lazy delegate, lateinit var | |
*/ | |
// <========================== Equality =========================> | |
// == checks value | |
// === checks reference | |
internal fun testEquality() { | |
val first: String? = null//"Test" | |
val second = "Test" | |
val firstResult = first == second //returns true | |
val stringFromSomeCalculation = "OneTestOne".substring(3, 7) | |
stringFromSomeCalculation == second // returs true | |
} | |
// <========================== Exceptions =========================> | |
//No checked exceptions | |
fun toJson(jsonString: String): JSONObject?{ | |
return JSONObject(jsonString) | |
} | |
//One way to handle exception (return null on exception case) | |
fun toJson(jsonString: String): JSONObject?{ | |
try { | |
return JSONObject(jsonString) | |
}catch (e: Exception){ | |
return null | |
} | |
} | |
fun exceptionTest(){ | |
val string: String? = " \"data\" : { \"key\" : \"value\" }" | |
//No compiler error to handle exception | |
val json = string.toJson() | |
} | |
// <========================== Closable =========================> | |
//kotlin way | |
fun testClosable(){ | |
val fileInputStream = FileInputStream(File("test.txt")) | |
fileInputStream.use {stream -> | |
//do something with stream | |
} | |
} | |
// <========================== Extension functions =========================> | |
//fun toJson(jsonString: String): JSONObject{ | |
// return JSONObject(jsonString) | |
//} | |
fun String.toJson(): JSONObject { | |
return JSONObject(this) | |
} | |
fun View.isVisible(): Boolean{ | |
return visibility == View.VISIBLE | |
} | |
fun String.toColor(): Int{ | |
return Color.parseColor(this) | |
} | |
fun extensionFuncTest(){ | |
val string = " \"data\" : { \"key\" : \"value\" }" | |
val value = "#ff3431" | |
val json = string.toJson() | |
val color = value.toColor() | |
} | |
// <========================== Collections utils =========================> | |
//Filter, map, find, any, sublist, subtract, union | |
fun collectionsUtilTest(){ | |
val list = listOf(1,2,3,4,5) | |
val anotherList = listOf(4,5,3,2,1) | |
arrayOf(1,2,3) | |
list.filter { it > 2 } | |
.map { it.toString() } | |
} | |
// <========================== Common Extensions =========================> | |
//let, apply, takeIf | |
private var dog: Dog? = null | |
private val dogg = Dog().apply { | |
name = "" | |
owner = "" | |
} | |
fun commonExtensionsTest(){ | |
val d = Dog() | |
d.name = "something" | |
d.owner = "owner" | |
dog = Dog().apply { | |
name = "something" | |
owner = "owner" | |
} | |
if (dog != null) { | |
if (dog!!.name != null) { | |
someOtherFunction(dog!!.name!!) | |
} | |
} | |
val name = dog?.name | |
someOtherFunction(dog?.name) //Error | |
dog?.name | |
?.takeIf { it.isNotEmpty() } | |
?.let { someOtherFunction(it) } | |
} | |
fun someOtherFunction(name: String): Int?{ | |
//Do something | |
return name.length | |
} | |
// <========================== Data class =========================> | |
data class Name(val firstName: String, var lastName: String){ | |
} | |
fun dataClassTest(){ | |
val name = Name("Muthu", "Raj") | |
name.copy(lastName = "Raja") | |
//send name to server | |
} | |
// <========================== Enums =========================> | |
enum class LoginStateEnum { | |
LOGGED_IN, | |
LOGGING_IN, | |
LOGGED_OUT | |
} | |
fun enumTest(){ | |
val loginState = getLoggedInEnumState() | |
//when produces compile errors only if when statement result is consumed. | |
//To do that, we create a dummy extension method named consumeWhen | |
//and call that with when statement. | |
when (loginState) { | |
LoginStateEnum.LOGGED_IN -> { | |
println("Logged in ") | |
//Update UI to reflect login state | |
"Logged in " | |
} | |
LoginStateEnum.LOGGED_OUT -> { | |
println("Logged out") | |
//Update UI to reflect logged state | |
"Logged out" | |
} | |
}.consumeWhen() //without this call, when won't produce error | |
} | |
fun <T> T.consumeWhen(): T{ | |
return this | |
} | |
fun getLoggedInEnumState(): LoginStateEnum{ | |
//check and return current login state | |
return LoginStateEnum.LOGGED_IN | |
} | |
fun enumCheckAllBranches(): String{ | |
val loginState = getLoggedInEnumState() | |
val state: String | |
when (loginState) { | |
LoginStateEnum.LOGGED_IN -> { | |
state = "Logged in" | |
} | |
LoginStateEnum.LOGGED_OUT -> { | |
state = "Logged out" | |
} | |
} | |
return state | |
} | |
// <========================== Sealed class =========================> | |
sealed class LoginState { | |
class LoggedIn(val name: String) : LoginState() | |
class LoggedOut : LoginState() | |
class LoggingIn : LoginState() | |
} | |
fun getLoggedInState(): LoginState{ | |
if(true /*login check*/){ | |
return LoginState.LoggedIn("Muthuraj") | |
} else{ | |
return LoginState.LoggedOut() | |
} | |
} | |
fun loginTest(){ | |
val loginState = getLoggedInState() | |
when (loginState) { | |
is LoginState.LoggedIn -> { | |
val userName = loginState.name | |
//Update UI | |
} | |
is LoginState.LoggedOut -> { | |
//Update UI | |
} | |
}.consumeWhen() | |
} | |
fun <T> T.consumeWhen(): T{ | |
return this | |
} | |
// <========================== Operator overloading =========================> | |
fun operators(){ | |
val list = mutableListOf("1", "2", "3", "4") | |
list.get(2) //==> list[2] | |
list.add("5") //==> list += "5" | |
list.set(2, "5") //==> list[2] = "5" | |
list[2] | |
list += "5" | |
list[2] = "5" | |
var a: Int = 5 | |
a += 4 | |
val anotherList = listOf("5", "6") | |
val newList = list + anotherList | |
list -= anotherList //subtracts contents of anotherList from list | |
val map = mapOf("1" to "4", "2" to "5") | |
val value = map["2"] | |
} | |
// <========================== Ranges =========================> | |
//1. Range can be created with double dot or until keyword. | |
//2. Ranges can only created for primitive types | |
//3. All common collection utils are available for range too (ex: map, filter..) | |
fun ranges(){ | |
val range = 0..10 | |
//Prints 0 to 10 (including 10) | |
for (i in 0..10){ | |
println(i) | |
} | |
//Prints 0 to 9 | |
for (i in 0..10-1){ | |
println(i) | |
} | |
// 0..10-1 ==> 0 until 10 | |
val list = listOf<String>() | |
for (i in 0 until list.size){ | |
println(i) | |
} | |
} | |
fun getViewGroupCildren(){ | |
val linearLayout = LinearLayout(this) | |
val children = (0 until linearLayout.childCount) | |
.map { linearLayout.getChildAt(it) } | |
} | |
// <========================== set, get =========================> | |
// set will have `value` and `field` | |
// `value` will hold new value passed through set call | |
// `field` can be used to refer the actual member field | |
// get will have `field` | |
class Employee(name: String){ | |
var salary: Double = 0.0 | |
private set | |
get() { | |
//do something on getSalary call | |
return field | |
} | |
private val _name = name | |
fun updateSalary(newSalary: Double){ | |
salary = newSalary | |
} | |
} | |
fun setTest(){ | |
val employee = Employee("Name") | |
val sal = employee.salary //get is public, so this will work | |
employee.salary = 0.0 //set is private, so this will be compile error | |
} | |
// <========================== Compile time constants =========================> | |
//Used with const keyword | |
//Can be used only in top level declaration, inside object or companion object | |
//Primitive types and Strings only supported | |
class CompileExample { | |
companion object { | |
const val EVENT = 2 | |
const val URL = "https://www.google.com+$EVENT" | |
} | |
} | |
fun compileTest(){ | |
println(CompileExample.URL)// this is equal to println("https://www.google.com+2") | |
} | |
// <========================== Multi line String =========================> | |
//used withing triple quotes | |
fun main(){ | |
/*val string = "This is" + | |
"a " + | |
"multi" + | |
"line" + | |
"string" | |
println(string)*/ | |
val string = """This | |
this | |
this | |
dfas | |
""" | |
println(string) | |
} | |
// <========================== Higher order functions =========================> | |
//Functions can be stored in Class fields, local fields inside function, can be passes as parameter to other | |
//functions or class constructors. | |
// Function type syntax ==> ({parameters goes here}) -> {Return Type} | |
//ex: (String) -> Boolean ==> A function that takes String as an argument and returns a Boolean | |
val abc: () -> Unit = { | |
} | |
fun higherOrderFunctions(){ | |
//Parenthesis optional if last parameter is lambda/func | |
val dog: Dog = Dog() | |
//With parenthesis | |
dog.setDetailsInterface(10, { | |
//do something | |
}) | |
//Without parenthesis | |
dog.setDetailsInterface(10) { | |
//do something | |
} | |
dog.setDetailsInterface(10, abc) | |
//DetailsInterface is from Java and is SAM construct (it has single abstract method). So it can used as lambda. | |
//All lambdas can be used as function in Kotlin. | |
} | |
// <========================== Higher order function examples =========================> | |
//Functions can be called using () or invoke() | |
//inline means, the function body will be replaced in call site. | |
//inline is used with higher order functions for performance. | |
inline fun Any.log(msg: () -> String) { | |
if (BuildConfig.DEBUG) { | |
Log.d("${this::class.java.simpleName}: ", msg()) | |
//or | |
Log.d("${this::class.java.simpleName}: ", msg.invoke()) | |
} | |
} | |
class LogTest(callback: () -> Unit) { | |
private val logMsg = | |
{ | |
"something" | |
} | |
fun testlog() { | |
log(logMsg) | |
log { "something" } | |
log({ "something" }) | |
//Arrays.toString won't even be called for Release build. | |
log { | |
Arrays.toString(arrayOf(1,2,3)) | |
} | |
} | |
} | |
fun viewClickListenerTest(){ | |
val view = TextView(this) | |
//Higher order function with argument syntax. | |
val clickListener = { view: View-> | |
//do something | |
} | |
view.setOnClickListener(clickListener) | |
} | |
fun runAsync(bgBlock: ((DogKt) -> Unit)?) { | |
Thread(object : Runnable { | |
override fun run() { | |
//do network call | |
val dog = DogKt("") | |
if (bgBlock != null) { | |
bgBlock(dog) | |
} | |
//or | |
bgBlock?.invoke(dog) | |
} | |
}).start() | |
} | |
fun mainTest(){ | |
runAsync { | |
print("success") | |
} | |
} | |
inline fun <R> tryWith(sendNonFatal: Boolean = true, fragileCode: () -> R?): R? { | |
try { | |
return fragileCode() | |
} catch (e: Exception) { | |
if (sendNonFatal) { | |
// Analytics.setNonFatalException(e) | |
} | |
if (BuildConfig.DEBUG) { | |
e.printStackTrace() | |
} | |
return null | |
} | |
} | |
fun tryWithTest(){ | |
val json = tryWith(sendNonFatal = false) { JSONObject("some json") } | |
} | |
inline fun <R> R?.orElse(block: () -> R): R { | |
return this ?: block() | |
} | |
fun orElseTest(){ | |
val dog: Dog? = null | |
val anotherDog: Dog? = null | |
dog?.name?.length | |
?: anotherDog?.name?.length ?: 0 | |
//or | |
dog?.name?.length | |
.orElse { anotherDog?.name?.length ?: 0 } | |
} | |
// <========================== TypeAlias =========================> | |
//give alternate name to some type (can be class or function) | |
typealias NewDog = Dog | |
typealias Callback = () -> Unit | |
fun typeAliasTest(){ | |
val dog = NewDog() | |
val callback: Callback = { | |
} | |
dog.setDetailsInterface(1, callback) | |
} | |
fun runSomething(callback: Callback){ | |
callback() | |
} | |
// <========================== Higher Order Functions with Receivers =========================> | |
fun List<String>.filterWithReceiver(condition: String.() -> Boolean): List<String> { | |
return this.filter { condition(it) } | |
} | |
fun receiverTest() { | |
val list = listOf("a", "abcd", "cd", "hello", "hi", "apple") | |
val newList = list.filterWithReceiver { | |
this.startsWith("a") | |
} | |
println(newList) | |
} | |
inline fun SharedPreferences.edit( | |
action: SharedPreferences.Editor.() -> Unit | |
) { | |
val editor = edit() | |
action(editor) | |
editor.apply() | |
} | |
fun sharedPreferenceTest(){ | |
appContext.getSharedPreferences("file_name", Context.MODE_PRIVATE) | |
.edit { | |
putBoolean("someBoolean", false) | |
putString("someString", "something") | |
} | |
} | |
inline fun View.runOnViewTreeObserver(crossinline action: () -> Unit) { | |
viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { | |
override fun onGlobalLayout() { | |
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { | |
viewTreeObserver.removeOnGlobalLayoutListener(this) | |
} else{ | |
viewTreeObserver.removeGlobalOnLayoutListener(this) | |
} | |
action() | |
} | |
}) | |
} | |
fun viewOnLayoutTest(){ | |
val view = TextView(this) | |
view.runOnViewTreeObserver { | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.muthuraj.kotlinBasics.kotlinbasics | |
import android.os.Bundle | |
import android.view.LayoutInflater | |
import android.view.View | |
import android.view.ViewGroup | |
import android.widget.TextView | |
import androidx.appcompat.app.AppCompatActivity | |
import androidx.fragment.app.Fragment | |
class MainActivity : AppCompatActivity() { | |
//findViewById will be called on first time access of textView | |
private val textView: TextView by lazy { findViewById<TextView>(R.id.text_view) } | |
override fun onCreate(savedInstanceState: Bundle?) { | |
super.onCreate(savedInstanceState) | |
setContentView(R.layout.activity_main) | |
} | |
override fun onStart() { | |
super.onStart() | |
//lazy block is executed now | |
textView.text = "start" | |
} | |
override fun onStop() { | |
super.onStop() | |
//textView is cached from previous initialization | |
textView.text = "stop" | |
val string = " \"data\" : { \"key\" : \"value\" }" | |
string.toJson() | |
} | |
} | |
class MainFragment : Fragment() { | |
private lateinit var textView: TextView | |
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { | |
return inflater.inflate(R.layout.activity_main, container, false) | |
} | |
override fun onActivityCreated(savedInstanceState: Bundle?) { | |
super.onActivityCreated(savedInstanceState) | |
textView = view!!.findViewById(R.id.text_view) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* $Id$ */ | |
package com.muthuraj.kotlinBasics.kotlinbasics | |
import android.view.LayoutInflater | |
import android.view.View | |
import android.view.ViewGroup | |
import androidx.recyclerview.widget.RecyclerView | |
/** | |
* Created by Muthuraj on 2019-04-14. | |
* | |
* Jambav, Zoho Corporation | |
*/ | |
class ChatAdapter : RecyclerView.Adapter<ChatViewHolder>() { | |
var data = emptyList<ChatData>() | |
fun updateData(newData: List<ChatData>) { | |
data = newData | |
notifyDataSetChanged() | |
} | |
override fun getItemViewType(position: Int): Int { | |
return when (data[position]) { | |
is ChatData.Date -> R.layout.chat_date | |
is ChatData.UnreadHeader -> R.layout.chat_unread_header | |
is ChatData.SentMessage -> R.layout.chat_sent | |
is ChatData.ReceivedMessage -> R.layout.chat_received //else case is not needed since we covered all cases | |
} | |
} | |
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ChatViewHolder { | |
val inflater = LayoutInflater.from(parent.context) | |
return ChatViewHolder(inflater.inflate(viewType, parent, false)) | |
} | |
override fun onBindViewHolder(holder: ChatViewHolder, position: Int) { | |
val chatData = data[position] | |
when (chatData) { | |
is ChatData.Date -> { | |
chatData.text //set this in UI | |
} | |
is ChatData.UnreadHeader -> { | |
chatData.text //set this in UI | |
} | |
is ChatData.SentMessage -> { | |
chatData.message //set this in UI | |
} | |
is ChatData.ReceivedMessage -> { | |
chatData.message //set this in UI | |
} | |
}.consumeWhen() //without this method call, there will be no compile error if extra states are added to ChatData | |
} | |
override fun getItemCount() = data.size | |
} | |
sealed class ChatData { | |
data class Date(val text: String) : ChatData() | |
data class UnreadHeader(val text: String) : ChatData() | |
data class SentMessage(val senderName: String, val dateTime: String, val message: String) : ChatData() | |
data class ReceivedMessage(val senderName: String, val dateTime: String, val message: String) : ChatData() | |
} | |
class ChatViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.muthuraj.kotlinBasics.kotlinbasics; | |
/** | |
* Created by Muthuraj on 2019-03-13. | |
*/ | |
public class SingletonExample { | |
private static final SingletonExample ourInstance = new SingletonExample(); | |
public static SingletonExample getInstance() { | |
return ourInstance; | |
} | |
private SingletonExample() { | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* $Id$ */ | |
package com.muthuraj.kotlinBasics.kotlinbasics | |
/** | |
* Created by Muthuraj on 2019-03-13. | |
*/ | |
object SingletonExampleKt |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment