Skip to content

Instantly share code, notes, and snippets.

@johanvergeer
Last active March 5, 2018 16:49
Show Gist options
  • Save johanvergeer/b7f249026a3a487a1fcbef94ffae8442 to your computer and use it in GitHub Desktop.
Save johanvergeer/b7f249026a3a487a1fcbef94ffae8442 to your computer and use it in GitHub Desktop.
Kotlin
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 {
}
// 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)
// 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)
// 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()
}
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