Next level of Android Development
Language safeness - more errors can be prevented by checks at compile time instead of falling at run time. Also language is referred as safe when it is promoting way of coding that is know as more secure.
Sir Charles Hoare
"This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years."
var person: Person
Must be inilialized
var person: Person = null
Not null type cannot be null
var person: Person? = null
? after type makes it nullable
person.name
Nullable must be unpacked
person?.name
Safe call (null if person is null)
person!!.name
Unsafe call (exception if person is null)
if(person != null) {
person.name
}
Smart Cast (after nullability check, object is casted to not-null)
if(person == null)
return
person.name
if(person != null && person.name == "Marcin")
if(person == null || person.age < 18)
person?.name ?: "unknown"
val name = person?.name ?: throw Error("No person or name is null")
val name = person?.name ?: return
val name: String = "Marcin"
Read only
var name: String = "Marcin"
Read-write
val list = listOf("A", "B", "C")
val name: String by lazy { getNameFromForm() }
MutableList
Mutable
List
Immutable
var list = listOf("A", "B", "C")
list += "D"
list -= "A"
val list = mutableListOf("A", "B", "C")
list.add("D")
list.remove("A")
// Java
public class PersonJava {
private String name;
private String surname;
private int age;
PersonJava(String name, String surname, int age) {
this.setName(name);
this.setSurname(surname);
this.setAge(age);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
class Person {
var name: String
var surname: String
var age: Int
constructor(name: String, surname: String, age: Int) {
this.name = name
this.surname = surname
this.age = age
}
}
Yap, this is exactly the same
Getters and setters are there
class Person(name: String, surname: String, age: Int) {
var name: String = name
var surname: String = surname
var age: Int = age
}
Still the same
Primary constructor
class Person(
var name: String,
var surname: String,
var age: Int
)
// Kotlin
class Person(
var name: String,
var surname: String,
var age: Int
)
// Java
public class PersonJava {
private String name;
private String surname;
private int age;
PersonJava(String name, String surname, int age) {
this.setName(name);
this.setSurname(surname);
this.setAge(age);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
// Kotlin
data class Person(
var name: String,
var surname: String,
var age: Int
)
// Java
public class PersonJava {
private String name;
private String surname;
private int age;
PersonJava(String name, String surname, int age) {
this.setName(name);
this.setSurname(surname);
this.setAge(age);
}
@Override
public String toString() {
return "PersonJava{" +
"name='" + name + '\'' +
", surname='" + surname + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PersonJava that = (PersonJava) o;
if (age != that.age) return false;
if (name != null ? !name.equals(that.name) : that.name != null) return false;
return surname != null ? surname.equals(that.surname) : that.surname == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + (surname != null ? surname.hashCode() : 0);
result = 31 * result + age;
return result;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
person.toString() // Person { name = "Marcin, ...
person1 == person2 // Checks equal of each field
person.copy(surname = "Moskała")
// New object with only chosen properties changed
var name: String? = null
get() = name?.capitalize()
set(value) {
if(value == null || value.length == 0) return
field = value
}
We can still edit getters and setters
Kotlin property = Java private field + accessors
accessors = getter for var, getter + setter for var
class Person(val name: String, val surname: String) {
val fullName: String
get() = "$name $surname"
}
Here Kotlin property is just a setter
view.visibility = View.GONE
view.hide()
ViewUtils.hide(view)
StringUtils.capitalize(str)
val replacedStr = StringUtils.replaceAll(str, "name" to name, "surname" to surname)
val capitalizedStr = StringUtils.capitalize(replacedStr)
str.capitalize()
str.replaceAll("{name}" to name, "{surname}" to surname)
.capitalize()
fun String.noLongerThen(max: Int): String {
return this.substring(0, Math.min(max, this.length))
}
fun main(args: Array<String>) {
println("Joe".noLongerThen(4)) // Joe
println("James".noLongerThen(4)) // Jame
println("Ashley".noLongerThen(4)) // Ashl
}
Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
fun Context.toast(text: String) {
Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
}
toast(text)
val Context.inflater
get() = getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
var View.isVisible: Boolean
get() = visibility == View.VISIBLE
set(value) {
visibility = if (value) View.VISIBLE else View.GONE
}
context.inflater
progress.isVisible = true
fun double(i: Int) = i * 2
class A() {
fun triple(i: Int) = i * 3
fun twelveTimes(i: Int): Int {
fun fourTimes(i: Int) = double(double(i))
return triple(fourTimes(i))
}
}
fun main(args: Array<String>) {
double(1) // 2
A().twelveTimes(2) // 24
}
Top-level function
Mamber function
Local function
fun setUpCounter() {
var a: Int = 0
fun showValue() {
counterView.text = "$a"
}
counterPlusView.setOnClickListener { a++; showValue() }
counterPlusView.setOnClickListener { a--; showValue() }
}
// Java
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getBaseContext(), "Button clicked", Toast.LENGTH_LONG).show();
}
});
button.setOnClickListener { toast("Button clicked") }
students.filter { it.passing }
.sortedBy { it.grade }
.take(10)
.joinToString(
prefix = "Best 10 students are:\n",
separator = "\n",
transform = { (name, surname) -> "$name $surname" }
)
inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
val destination = ArrayList<R>()
for (item in this) destination.add(transform(item))
return destination
}
inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> {
val destination = ArrayList<T>()
for (item in this) if(predicate(item)) destination.add(item)
return destination
}
"This is Sparta".map { it.toUpperCase() }.toString() // THIS IS SPARTA
Type is inferred
Everything is an expression
fun <T : Comparable<T>> List<T>.quickSort(): List<T> = when {
size <= 1 -> this
else -> {
val pivot = first()
val (smaller, greater) = drop(1).partition { it <= pivot }
smaller.quickSort() + pivot + greater.quickSort()
}
}
Powerset in mathematics is set of all possible subsets of this set, including this set and empty set.
powerset({}) == {{}}
powerset({1}) == {{}, {1}}
powerset({1, 2}) == {{}, {1}, {2}, {1, 2}}
fun <T> Collection<T>.powerset(): Set<Set<T>> = when {
isEmpty() -> setOf(setOf())
else -> drop(1).powerset().let { it + it.map { it + first() } }
}
powerset({1, 2}) = powerset({2}) + powerset({2}).map { it + 1 }
powerset({2}) = powerset({}) + powerset({}).map { it + 2 }
powerset({}) = {{}}
powerset((2)) = {{}} + {{2}} = {{}, {2}}
powerset({1, 2}) = {{}, {2}} + {{1}, {1, 2}} = {{}, {1}, {2}, {1, 2}}
fun <T> Collection<T>.powerset(): Set<Set<T>> = powerset(this, setOf(setOf()))
private tailrec fun <T> powerset(left: Collection<T>, acc: Set<Set<T>>): Set<Set<T>> = when {
left.isEmpty() -> acc
else ->powerset(left.drop(1), acc + acc.map { it + left.first() })
}
Function Literals with Receiver
Multi-platform programming in Kotlin
kotlinlang.com
https://blog.jetbrains.com/kotlin/2017/05/kotlin-on-android-now-official/
https://blog.gradle.org/kotlin-meets-gradle
https://developer.android.com/kotlin/index.html
http://www.opinie.senior.pl/zdjecia/Sosy-majonezy-musztardy/Ketchup-0-dodatku-cukru-30378-big.png
https://medium.com/@giuliani.arnaud/kotlin-in-production-one-year-later-d6d3b66f870c
http://2.bp.blogspot.com/-46cd0AT4Dwo/VmuhPnUH1iI/AAAAAAAAMDs/m8HX2l39mks/s1600/cropped-chiquita-dm2-minion-dave-bananas.jpg
http://dobsondev.com/2014/06/06/the-elvis-operator/
Next level of Android Development