Last active
March 5, 2018 16:49
-
-
Save johanvergeer/b7f249026a3a487a1fcbef94ffae8442 to your computer and use it in GitHub Desktop.
Kotlin
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.redgyro.education.`oo-classes-functions-inheritance` | |
fun main(args: Array<String>) { | |
/** | |
* Kotlin has 4 access modifiers | |
* Just like in Java there is "public", "private", "protected" | |
* | |
* And there is "internal" | |
* | |
* Default access modifier | |
* ======================= | |
* | |
* Top level items are public by default. (In Java is everything package private by default) | |
* If a top level item is private, everything in the same file can access the item | |
* | |
* Classes can be declared private, so everything in the same file can access the class | |
* | |
* Internal access modifier | |
* ======================== | |
* Something that is marked as internal is accessible in the same module | |
* | |
* Access modifiers on top level items | |
* =================================== | |
* | |
* | Access modifier | Kotlin | Java | |
* |-----------------|--------------------------------|--------------------- | |
* | private | Visible within the same file | Can't be used | |
* | protected | Can't be used | Con't be used | |
* | public | Visible everywhere | Visible everywhere | |
* | internal | Visible within the same module | N.A. | |
*/ | |
// The private Employee class is accessible | |
val employee = Employee() | |
} | |
private class Employee { | |
} |
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
// An array is a class in Kotlin | |
// Create an array an add values to int | |
val names = arrayOf("John", "Eve", "Adam") | |
// Under the covers the arrayOf() function creates an Array<T> | |
// We can use array indexing | |
val name = names[1] | |
// The array has a constructor. Therefore we can pass a Lambda expression | |
val integers = Array<Int>(4) { i -> i + 1 } | |
// And we can remove the explicit type declaration | |
val integers2 = Array(4) { i -> i + 1 } | |
// To create an array of all zeroes | |
val zeroes = Array(100) { i -> 0 } | |
// And we can even remove the i parameter | |
val zeroes2 = Array(100) { 0 } | |
// If we don't initialize the array on creation, we do have to | |
// specify the type explicitly | |
val uninitializedArray: Array<Int> | |
// Now the array can be initialized once | |
uninitializedArray = Array(19) { i -> (i + 1) * 10 } | |
// Create a mixed array | |
val mixedArray = arrayOf('a', "John", 1, 1L) | |
// Which will give us an array of Any | |
println(mixedArray is Array<Any>) | |
// Passing arrays of primitives. This might be used when calling a Java method that | |
// has an array of primitive values as an input parameter | |
val primitiveIntArray = intArrayOf(1, 2, 4) | |
// Convert an existing array into an array of primitives | |
val classIntArray = arrayOf(1, 2, 3) | |
val convertedPrimitiveIntArray = classIntArray.toIntArray() | |
// Convert back to a typed array | |
val typedIntArray = convertedPrimitiveIntArray.toTypedArray() | |
// To create an array of primitive types without initializing the values | |
// This will create an array of all zeroes | |
val primitiveIntArray2 = intArrayOf(4) |
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
// The long way of defining a class with a constructor parameter | |
/** | |
* Kotlin has the notion of what's called a primary constructor, | |
* which is defined outside the curly braces | |
*/ | |
class Employee constructor(firstName: String) { | |
val firstName: String // firstName has to be initialized in the init block | |
/** | |
* Initializer block | |
* ================= | |
* It is not a constructor, but is used in conjunction with the primary constructor | |
* The constructor cannot have an embedded init block | |
*/ | |
init { | |
this.firstName = firstName | |
} | |
} | |
// Since we don't do anything with firstName in the init block we can remove | |
// the init block | |
class Employee constructor(firstName: String) { | |
val firstName: String = firstName | |
} | |
// Since Kotlin want's to remove as much boilerplate as possible, | |
// the property can also be declared inside the primary constructor | |
class Employee constructor(val firstName: String) { | |
} | |
// The constructor keyword is also not required as long as the constructor is public | |
class Employee (val firstname: String) { | |
} | |
// If an access modifier has to be used on the constructor, the constructor keyword is required | |
class Employee protected constructor (val firstName: string) { | |
} | |
// And since we don't do anything inside the class, we can remove the curly braces | |
class Employee constructor(val firstName: String) | |
/** | |
* Secondary constructors | |
* ====================== | |
*/ | |
class Employee(val firstName: String) { | |
// The secondary constructor cannot declare a property | |
// So we'll have to do this manually here | |
var fullTime: Boolean = true | |
// Create a secondary constructor to handle extra parameters | |
// Just like we would do in Java | |
// This also means we will have to delegate all parameters used | |
// in the primary constructor using this() | |
constructor(firstName: String, fullTime: Boolean) : this(firstName) { | |
this.fullTime = fullTime | |
} | |
} | |
// Using default parameter values instead of a secondary constructor | |
class Employee(val firstName: String, var fullTime: Boolean = true) |
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
// vararg parameter | |
// ================ | |
// We can accept an arbitrary amount of arguments using the vararg argument | |
// We can only have one vararg parameter in a function! | |
data class Car(val color: String, val brand: String) | |
fun printColors(vararg cars: Car){ | |
for (car in cars){ | |
println(car.color) | |
} | |
} | |
//... Some code creating the cars collection ... | |
printColors(cars) | |
// It does not have to be the last argument, as long as we use named parameters! | |
fun printColors(vararg cars: Car, str: String){ | |
for (car in cars){ | |
println(car.color) | |
} | |
} | |
printColors(cars, str="color") | |
// If the vararg is the last parameter, we don't have to use named parameters | |
fun printColors(str: String, vararg cars: Car){ | |
for (car in cars){ | |
println(car.color) | |
} | |
} | |
printColors("color", cars) | |
/** | |
* Spread operator | |
* ================= | |
* If we would like to send a array to a vararg parameter, it won't be accepted by default. | |
* for this we use the spread operator, which will unpack the array. | |
*/ | |
val manyCars = arrayOf(car1, car2, car3) | |
printColors(*manyCars) | |
// The spread operator also allows us to combine multiple arrays | |
val otherCars = arrayOf(car4, car5) | |
val lotsOfCars = arrayOf(*manyCars, *otherCars) | |
/** | |
* Extension functions | |
* =================== | |
* Extension functions can be used to extend existing classes | |
* | |
*/ | |
// The Java way (ish) | |
class Utils { | |
fun upperFirstAndLast(str: String): String { | |
val upperFirst = str.substring(0, 1).toUpperCase() + str.substring(1) | |
return upperFirst.substring(0, upperFirst.length - 1) + str.substring(upperFirst.length - 1).toUpperCase() | |
} | |
} | |
// The Kotlin way | |
fun String.upperFirstAndLast(): String { | |
val upperFirst = this.substring(0, 1).toUpperCase() + this.substring(1) | |
return upperFirst.substring(0, upperFirst.length - 1) + this.substring(upperFirst.length - 1).toUpperCase() | |
} | |
// We can even remove the this keyword | |
fun String.upperFirstAndLast(): String { | |
val upperFirst = substring(0, 1).toUpperCase() + substring(1) | |
return upperFirst.substring(0, upperFirst.length - 1) + substring(upperFirst.length - 1).toUpperCase() | |
} |
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.redgyro.education.nullreferences | |
fun main(args: Array<String>) { | |
// In Kotlin we can't just assign a null value | |
val str: String = null // This will throw an error: Null cannot be a value of a non-null type String | |
// To make a value nullable, follow the type with a questionmark | |
val nullableString: String? = "This isn't null" | |
// But now this will throw an error | |
nullableString.toUpperCase() // Only safe (?.) or non-null (.!!) calls are allowed ... | |
// The Java solution | |
if (nullableString != null) | |
nullableString.toUpperCase() // This will work | |
// But there is a shorter way of doing this | |
nullableString?.toUpperCase() // This will also work, and is much more concise | |
// Chaining properties | |
val bank = Bank(null) | |
val nullableCountryCode = bank.address?.country?.countryCode | |
// To assign a default value is the actual value evaluates to null | |
// we use the Elvis operator | |
val countryCode = bank.address?.country?.countryCode ?: "NL" | |
// Kotlin has something called safe casting | |
val something: Any = arrayOf(1, 3, 4) | |
val str3: String = something as? String ?: "Just in case" | |
// If we are 100% sure the non-null assertion can be used | |
// If one of the values will be null anyway (But why would that be possible if we were absolutely sure :) ) | |
// A KotlinNullPointerException will be thrown | |
val countryCode2 = bank.address!!.country!!.countryCode | |
// we can pass a nullable value to a not-null parameter using the non-null assertion | |
// But the function will not check if the value is null since the parameter is | |
// not of a nullable type | |
val nullParameter: String? = null | |
// This is a brute force approach that might introduce a KotlinNullPointerException | |
printText(nullParameter!!) | |
/** | |
* let function | |
*/ | |
// This is what we would like to accomplish | |
if (nullParameter != null) { | |
printText(nullParameter) | |
} | |
// Shorthand option using the let function | |
nullParameter?.let { printText(it) } | |
} | |
data class Bank(val address: Address?) | |
data class Address(val country: Country?) | |
data class Country(val countryCode: String) | |
fun printText(text: String) { | |
println(text) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment