Better Apps with Kotlin!
Pavel Shackih, SBT
t.me/PavelShackih
Motivation
Android core app quality: the app does not crash, force
close, freeze, or otherwise function abnormally on any
targeted device.
Motivation
Android core app quality: the app does not crash, force
close, freeze, or otherwise function abnormally on any
targeted device.
JSR-305, Android Support Annotations
@Nonnull
@Override
public User save(@Nonnull User user) {
// ...
userDao.save(user);
// ...
return user;
}
JSR-305, Android Support Annotations
1. Hard to maintain.
2. Verbose, but could be simplified using @ParametersAreNonnullByDefault or
@ParametersAreNullableByDefault.
3. Just warning.
4. “Leak” NPE.
5. ~6500 in SBOL.
Optional<T>
@Override
public Optional<User> findById(long id) {
return Optional.ofNullable(userDao.findById(id));
}
public void printUser(long id) {
Optional<User> optional = findById(id);
optional.ifPresent(user -> System.out.println(user));
}
Optional<T>
1. Verbose.
2. GC overhead.
3. Problem with third-party libraries.
Here comes Kotlin
fun main(args: Array<String>) {
val hello = "Hello, Innopolis!"
println(hello)
}
Here comes Kotlin
● statically-typed, object-oriented, functional;
● target: JVM, Android, JS, Native (in progress);
● fully interoperable with Java;
● compact runtime lib, good tooling;
● runs as fast as an equivalent on Java;
● easy to learn for Java developers;
● official Android development language.
Not nullable types by default
var foo: String = "Foo" // var foo = "Foo"
foo = null // Compile error: Null can not be a value of a non-null type String
var bar: String? = "Bar"
bar = null // Ok
bar = foo // Ok
foo = bar // Error
Not nullable types by default
String
String?
String? = String or null
Deal with nullable types
val user: User? = null
println(user.address.street)
// Error: only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable
receiver of type kotlin.String?
Smartcast
val user: User? = null
if (user != null && user.address != null) {
println(user.address.street) // Now: user: User, address: Address
}
User?
User
Address?
Address
Safe call operator ?.
val user: User? = null
println(user?.address)
if (user != null) {
return user.getAddress();
} else {
return null;
}
user?.address
user.address
null
*Kotlin in Action
user != null
user == null
Safe call operator always returns
nullable type of <T>, so <T> result type
transform to type <T?>
println(user?.address?.street)
Chaining safe call operators:
Elvis operator ?:
val user: User? = null
println(user ?: ADMIN)
if (user != null) {
return user;
} else {
return ADMIN;
}
user
user
ADMIN
*Kotlin in Action
user != null
user == null
println(user?.address?.street ?: UNKNOWN_STREET)
Let function
val user: User? = null
user?.let { println(it) }
if (user != null) {
System.out.println(user);
}
user
println(user)
user != null
*Kotlin in Action
Not null assertions: !! operator
val user: User? = null
println(user!!.address)
System.out.println(user.getAddress());
user
user.address
NullPointerException
*Kotlin in Action
user != null
user == null
Platform types and Java interoperability
Java Kotlin
@Nullable + String String?
@NotNull + String String
String String!
String! = String or String?
val stringValue = Java.getString()
println(stringValue.length) // Ok
println(stringValue?.length) // Ok
Kotlin nullability: Examples
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main2)
val id = savedInstanceState.getString(ID) // compile error
}
}
class MyIntentService : IntentService("MyIntentService") {
override fun onHandleIntent(intent: Intent?) {
val param1 = intent.getStringExtra(EXTRA_PARAM1) // compile error
}
}
Intrinsics
● Apply Intrinsics.checkParameterIsNotNull() for every public function for each
non-null parameter.
● Disable using -Xno-param-assertions or Proguard.
JDK 1.8 Kotlin
@Override
public void forEachRemaining(DoubleConsumer
action) {
Objects.requireNonNull(action);
if (count == -2) {
action.accept(first);
count = -1;
}
}
@NotNull
public User save(@NotNull User user) {
Intrinsics.checkParameterIsNotNull(user, "user");
this.userDao.save(user);
return user;
}
Kotlin nullability
1. Hard to maintain built-in type system.
2. Verbose special syntax for nullable values.
3. Not error, just a warning, no guarantees compile time error.
4. “Leak” NPE kotlin intrinsics.
5. GC overhead no overhead at all.
6. Problem with third-party libraries kotlin compiler could read default java
annotations from external byte code.
Extension functions
Java Kotlin
public static boolean isEmpty(@Nullable String string) {
return string == null || string.isEmpty();
}
fun String?.isEmpty(): Boolean {
return this == null || this.length == 0
}
String text = ...;
if (isEmpty(text)) {
System.out.println("Empty text!");
}
val text = ...
if (text.isEmpty()) {
println("Empty text!")
}
Extension functions: Lambdas
fun String.printWithCondition(predicate: (s: String) -> Boolean) {
if (predicate(this)) {
println(this)
}
}
val text = "Hello"
text.printWithCondition { it == "Hello" }
Extension functions: Lambdas with inline
inline fun String.printWithCondition(predicate: (s: String) -> Boolean) {
if (predicate(this)) {
println(this)
}
}
val text = "Hello"
text.printWithCondition { it == "Hello" }
String text = "Hello";
if(Intrinsics.areEqual(text, "Hello")) {
System.out.println(text);
}
Extension functions: AutoCloseable
val fos = FileOutputStream("data.txt")
val result = fos.use {
// do some stuff with stream
"result"
}
println(result)
val resultSet: ResultSet? = ...
resultSet?.use {
println(it.getString(USER_ID))
}
Extension functions: Collections
val list = listOf("Foo", "Bar", "Buzz")
list.filter { it.startsWith("B") } // [Bar, Buzz]
list.map { it.toUpperCase() } // [FOO, BAR, BUZZ]
list.flatMap { it.asIterable() } // [F, o, o, B, a, r, B, u, z, z]
list.groupBy { it.first() } // {F=[Foo], B=[Bar, Buzz]}
list.fold(0, { acc, s -> acc + s.length }) // 10
list.reduce { acc, s -> s + acc } // BuzzBarFoo
Extension functions: Collections
1. Immutable by default.
2. Mutable collections should be created explicitly, e.g. by mutableListOf(),
mutableSetOf(), mutableMapOf() or using constructors.
3. Not lazy by default: each transformation → new collection.
4. Sequences are lazy like a Java 8 Streams. No parallelism.
5. Default implementations: ArrayList, HashSet and HashMap.
6. Array supports same functional operators.
Extension functions: Lambda Extensions
inline fun String.printWithCondition(predicate: String.() -> Boolean) {
if (predicate()) { // predicate(this)
println(this)
}
}
val text = "Hello"
text.printWithCondition { length > 3 }
Extension functions: Standard functions
public inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }
val user = User().apply {
id = 1L
name = "John Smith"
}
public inline fun <T, R> T.let(block: (T) -> R): R = block(this)
user?.let {
println(user.name)
}
Conclusion: tools
1. Dagger 2, Butterknife, RxJava 2, Retrofit 2, Realm, Room...
2. Built-in plugin in AS 3.0.
3. Static analysis - https://github.com/arturbosch/detekt.
4. https://kotlinlang.org/docs/reference/coding-conventions.html.
5. Proguard - ok.
6. Debugging - as java.
7. Compile speed - as java - https://habrahabr.ru/company/badoo/blog/329026/.
8. Java projects: Spring 5, Reactor, Corda, Gradle, Spark.
9. Android projects: Hotellook, Avito.
Conclusion: next
1. Intro to Kotlin at Google IO 17: https://youtu.be/X1RVYt2QKQE.
2. Jake Wharton and Christina Lee at Google IO 17:
https://youtu.be/fPzxfeDJDzY.
3. https://developer.android.com/kotlin/index.html.
4. https://kotlinlang.org/docs/reference/.
5. 10 Kotlin Tricks in 10 ish minutes by Jake Wharton:
https://youtu.be/0sPzDwS55wM.
6. Kotlin in Action: https://www.manning.com/books/kotlin-in-action.
7. Kotlin type system: http://natpryce.com/articles/000818.html.
8. Perfomance: https://goo.gl/J2FVSm and https://goo.gl/CDKxw9.
Conclusion: community
1. https://t.me/kotlin_lang @kotlin_lang.
2. http://slack.kotlinlang.org/.
3. http://www.kotlinweekly.net/.

Боремся с NPE вместе с Kotlin, Павел Шацких СберТех

  • 1.
    Better Apps withKotlin! Pavel Shackih, SBT t.me/PavelShackih
  • 2.
    Motivation Android core appquality: the app does not crash, force close, freeze, or otherwise function abnormally on any targeted device.
  • 3.
    Motivation Android core appquality: the app does not crash, force close, freeze, or otherwise function abnormally on any targeted device.
  • 4.
    JSR-305, Android SupportAnnotations @Nonnull @Override public User save(@Nonnull User user) { // ... userDao.save(user); // ... return user; }
  • 5.
    JSR-305, Android SupportAnnotations 1. Hard to maintain. 2. Verbose, but could be simplified using @ParametersAreNonnullByDefault or @ParametersAreNullableByDefault. 3. Just warning. 4. “Leak” NPE. 5. ~6500 in SBOL.
  • 6.
    Optional<T> @Override public Optional<User> findById(longid) { return Optional.ofNullable(userDao.findById(id)); } public void printUser(long id) { Optional<User> optional = findById(id); optional.ifPresent(user -> System.out.println(user)); }
  • 7.
    Optional<T> 1. Verbose. 2. GCoverhead. 3. Problem with third-party libraries.
  • 9.
    Here comes Kotlin funmain(args: Array<String>) { val hello = "Hello, Innopolis!" println(hello) }
  • 10.
    Here comes Kotlin ●statically-typed, object-oriented, functional; ● target: JVM, Android, JS, Native (in progress); ● fully interoperable with Java; ● compact runtime lib, good tooling; ● runs as fast as an equivalent on Java; ● easy to learn for Java developers; ● official Android development language.
  • 11.
    Not nullable typesby default var foo: String = "Foo" // var foo = "Foo" foo = null // Compile error: Null can not be a value of a non-null type String var bar: String? = "Bar" bar = null // Ok bar = foo // Ok foo = bar // Error
  • 12.
    Not nullable typesby default String String? String? = String or null
  • 13.
    Deal with nullabletypes val user: User? = null println(user.address.street) // Error: only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type kotlin.String?
  • 14.
    Smartcast val user: User?= null if (user != null && user.address != null) { println(user.address.street) // Now: user: User, address: Address } User? User Address? Address
  • 15.
    Safe call operator?. val user: User? = null println(user?.address) if (user != null) { return user.getAddress(); } else { return null; } user?.address user.address null *Kotlin in Action user != null user == null Safe call operator always returns nullable type of <T>, so <T> result type transform to type <T?> println(user?.address?.street) Chaining safe call operators:
  • 16.
    Elvis operator ?: valuser: User? = null println(user ?: ADMIN) if (user != null) { return user; } else { return ADMIN; } user user ADMIN *Kotlin in Action user != null user == null println(user?.address?.street ?: UNKNOWN_STREET)
  • 17.
    Let function val user:User? = null user?.let { println(it) } if (user != null) { System.out.println(user); } user println(user) user != null *Kotlin in Action
  • 18.
    Not null assertions:!! operator val user: User? = null println(user!!.address) System.out.println(user.getAddress()); user user.address NullPointerException *Kotlin in Action user != null user == null
  • 19.
    Platform types andJava interoperability Java Kotlin @Nullable + String String? @NotNull + String String String String! String! = String or String? val stringValue = Java.getString() println(stringValue.length) // Ok println(stringValue?.length) // Ok
  • 20.
    Kotlin nullability: Examples classMainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main2) val id = savedInstanceState.getString(ID) // compile error } } class MyIntentService : IntentService("MyIntentService") { override fun onHandleIntent(intent: Intent?) { val param1 = intent.getStringExtra(EXTRA_PARAM1) // compile error } }
  • 21.
    Intrinsics ● Apply Intrinsics.checkParameterIsNotNull()for every public function for each non-null parameter. ● Disable using -Xno-param-assertions or Proguard. JDK 1.8 Kotlin @Override public void forEachRemaining(DoubleConsumer action) { Objects.requireNonNull(action); if (count == -2) { action.accept(first); count = -1; } } @NotNull public User save(@NotNull User user) { Intrinsics.checkParameterIsNotNull(user, "user"); this.userDao.save(user); return user; }
  • 22.
    Kotlin nullability 1. Hardto maintain built-in type system. 2. Verbose special syntax for nullable values. 3. Not error, just a warning, no guarantees compile time error. 4. “Leak” NPE kotlin intrinsics. 5. GC overhead no overhead at all. 6. Problem with third-party libraries kotlin compiler could read default java annotations from external byte code.
  • 23.
    Extension functions Java Kotlin publicstatic boolean isEmpty(@Nullable String string) { return string == null || string.isEmpty(); } fun String?.isEmpty(): Boolean { return this == null || this.length == 0 } String text = ...; if (isEmpty(text)) { System.out.println("Empty text!"); } val text = ... if (text.isEmpty()) { println("Empty text!") }
  • 24.
    Extension functions: Lambdas funString.printWithCondition(predicate: (s: String) -> Boolean) { if (predicate(this)) { println(this) } } val text = "Hello" text.printWithCondition { it == "Hello" }
  • 25.
    Extension functions: Lambdaswith inline inline fun String.printWithCondition(predicate: (s: String) -> Boolean) { if (predicate(this)) { println(this) } } val text = "Hello" text.printWithCondition { it == "Hello" } String text = "Hello"; if(Intrinsics.areEqual(text, "Hello")) { System.out.println(text); }
  • 26.
    Extension functions: AutoCloseable valfos = FileOutputStream("data.txt") val result = fos.use { // do some stuff with stream "result" } println(result) val resultSet: ResultSet? = ... resultSet?.use { println(it.getString(USER_ID)) }
  • 27.
    Extension functions: Collections vallist = listOf("Foo", "Bar", "Buzz") list.filter { it.startsWith("B") } // [Bar, Buzz] list.map { it.toUpperCase() } // [FOO, BAR, BUZZ] list.flatMap { it.asIterable() } // [F, o, o, B, a, r, B, u, z, z] list.groupBy { it.first() } // {F=[Foo], B=[Bar, Buzz]} list.fold(0, { acc, s -> acc + s.length }) // 10 list.reduce { acc, s -> s + acc } // BuzzBarFoo
  • 28.
    Extension functions: Collections 1.Immutable by default. 2. Mutable collections should be created explicitly, e.g. by mutableListOf(), mutableSetOf(), mutableMapOf() or using constructors. 3. Not lazy by default: each transformation → new collection. 4. Sequences are lazy like a Java 8 Streams. No parallelism. 5. Default implementations: ArrayList, HashSet and HashMap. 6. Array supports same functional operators.
  • 29.
    Extension functions: LambdaExtensions inline fun String.printWithCondition(predicate: String.() -> Boolean) { if (predicate()) { // predicate(this) println(this) } } val text = "Hello" text.printWithCondition { length > 3 }
  • 30.
    Extension functions: Standardfunctions public inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this } val user = User().apply { id = 1L name = "John Smith" } public inline fun <T, R> T.let(block: (T) -> R): R = block(this) user?.let { println(user.name) }
  • 31.
    Conclusion: tools 1. Dagger2, Butterknife, RxJava 2, Retrofit 2, Realm, Room... 2. Built-in plugin in AS 3.0. 3. Static analysis - https://github.com/arturbosch/detekt. 4. https://kotlinlang.org/docs/reference/coding-conventions.html. 5. Proguard - ok. 6. Debugging - as java. 7. Compile speed - as java - https://habrahabr.ru/company/badoo/blog/329026/. 8. Java projects: Spring 5, Reactor, Corda, Gradle, Spark. 9. Android projects: Hotellook, Avito.
  • 32.
    Conclusion: next 1. Introto Kotlin at Google IO 17: https://youtu.be/X1RVYt2QKQE. 2. Jake Wharton and Christina Lee at Google IO 17: https://youtu.be/fPzxfeDJDzY. 3. https://developer.android.com/kotlin/index.html. 4. https://kotlinlang.org/docs/reference/. 5. 10 Kotlin Tricks in 10 ish minutes by Jake Wharton: https://youtu.be/0sPzDwS55wM. 6. Kotlin in Action: https://www.manning.com/books/kotlin-in-action. 7. Kotlin type system: http://natpryce.com/articles/000818.html. 8. Perfomance: https://goo.gl/J2FVSm and https://goo.gl/CDKxw9.
  • 33.
    Conclusion: community 1. https://t.me/kotlin_lang@kotlin_lang. 2. http://slack.kotlinlang.org/. 3. http://www.kotlinweekly.net/.