Upgrade to Pro — share decks privately, control downloads, hide ads and more …

10 Kotlin Tricks in 10(ish) Minutes (Devoxx US ...

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.

10 Kotlin Tricks in 10(ish) Minutes (Devoxx US 2017)

Kotlin is new language growing in popularity as a complement to Java. Its major advantages and features compared to Java are immediately appealing. While it's quick to learn, it also has a lot of small and thoughtful parts which can be harder to discover. This short talk will cover 10 of my favorites with real-world examples. Attendees should come in having seen some Kotlin but looking to learn even more.

Video: https://youtu.be/0sPzDwS55wM

Avatar for Jake Wharton

Jake Wharton PRO

March 21, 2017
Tweet

More Decks by Jake Wharton

Other Decks in Programming

Transcript

  1. Why Kotlin? class User {
 public String getName() {
 //

    ...
 }
 public void setName(String name) {
 // ...
 }
 } // ^^^ Java
  2. Why Kotlin? class User {
 public String getName() {
 //

    ...
 }X
 public void setName(String name) {
 // ...
 }Y
 }Z // ^^^ Java vvv Kotlin val user = User()
 println("Name is " + user.name)
  3. Why Kotlin? class User {
 public String getName() {
 //

    ...
 }X
 public void setName(String name) {
 // ...
 }Y
 }Z // ^^^ Java vvv Kotlin val user = User()
 println("Name is ${user.name}")
  4. Why Kotlin? class User {
 public String getName() {
 //

    ...
 }X
 public void setName(String name) {
 // ...
 }Y
 }Z // ^^^ Java vvv Kotlin val user = User()
 println("Name is $user")
  5. Why Kotlin? val user = User()
 user = User()
 


    var currentUser = User()
 currentUser = User()
  6. Why Kotlin? fun Date.isTuesday(): Boolean {
 return day == 2


    } val epoch = Date(1970, 0, 0)
 if (epoch.isTuesday()) {
 println("The epoch was a tuesday.")
 } else {
 println("The epoch was not a tuesday.")
 }
  7. #01 Explosive Placeholders class Test : Runnable {
 override fun

    run() {
 // TODO doSomethingElse()?
 }B
 }A
  8. #01 Explosive Placeholders class Test : Runnable {Y
 override fun

    run() {Z
 if (something()) {
 doSomething()
 } else {
 // TODO doSomethingElse()?
 }C
 }B
 }A
  9. #01 Explosive Placeholders class Test : Runnable {Y
 override fun

    run() {Z
 if (something()) {
 doSomething()
 } else {
 // TODO doSomethingElse()?
 }C
 }B
 }A
  10. #01 Explosive Placeholders class Test : Callable<String> {Y
 override fun

    call(): String {Z
 if (something()) {
 return doSomething()
 } else {
 // TODO return doSomethingElse()?
 }C
 }B
 }A Runnable
 run
  11. #01 Explosive Placeholders class Test : Callable<String> {Y
 override fun

    call(): String {Z
 if (something()) {
 return doSomething()
 } else {
 // TODO return doSomethingElse()?
 }C
 }B
 }A Runnable
 run
  12. #01 Explosive Placeholders class Test : Callable<String> {
 override fun

    call(): String {
 if (something()) {
 return doSomething()
 } else {
 throw UnsupportedOperationException("TODO doSomethingElse()?")
 }C
 }B
 }A 
 
 
 
 
 // return
  13. #01 Explosive Placeholders class Test : Callable<String> {
 override fun

    call(): String {
 if (something()) {
 return doSomething()
 } else {
 TODO("doSomethingElse()?")
 }C
 }B
 }A
  14. #01 Explosive Placeholders class Test : Callable<String> {
 override fun

    call(): String {
 if (something()) {
 return doSomething()
 } else {
 TODO("doSomethingElse()?")
 }C
 }B
 }A
  15. #02 Semantic Validation static String join(String sep, List<String> strings) {


    if (sep == null) throw new NullPointerException("sep == null");
 if (strings == null) throw new NullPointerException("strings == null"); 
 // ...
 }Z
  16. #02 Semantic Validation static String join(String sep, List<String> strings) {


    if (sep == null) throw new NullPointerException("sep == null");
 if (sep.length() < 2) { throw new IllegalArgumentException("sep.length() < 2: " + sep); }Y
 if (strings == null) throw new NullPointerException("strings == null"); 
 // ...
 }Z
  17. #02 Semantic Validation static String join(String sep, List<String> strings) {


    Preconditions.checkNotNull(sep, "sep == null");
 if (sep.length() < 2) {
 throw new IllegalArgumentException("sep.length() < 2: " + sep);
 }Y
 Preconditions.checkNotNull(strings, "strings == null");
 
 // ...
 }Z 
 if == null) throw new NullPointerException(
 
 if == null) throw new NullPointerException(
  18. #02 Semantic Validation static String join(String sep, List<String> strings) {


    Preconditions.checkNotNull(sep, "sep == null");
 Preconditions.checkArgument(sep.length() < 2, "sep.length() < 2: " + sep);
 Preconditions.checkNotNull(strings, "strings == null");
 
 // ...
 }Z 
 
 if ) {
 throw new IllegalArgumentException(
 }Y
  19. #02 Semantic Validation static String join(String sep, List<String> strings) {


    Preconditions.checkNotNull(sep, "sep == null");
 Preconditions.checkArgument(sep.length() < 2, "sep.length() < 2: " + sep);
 Preconditions.checkNotNull(strings, "strings == null");
 
 // ...
 }Z 
 
 if ) {
 throw new IllegalArgumentException(
 }Y
  20. #02 Semantic Validation fun join(sep: String, strings: List<String>): String {


    Preconditions.checkArgument(sep.length < 2, "sep.length < 2: " + sep)
 // ...
 }Z static 
 Preconditions.checkNotNull(sep, "sep == null");
 ;
 Preconditions.checkNotNull(strings, "strings == null");
  21. #02 Semantic Validation fun join(sep: String, strings: List<String>): String {


    require(sep.length < 2) { "sep.length < 2: " + sep }
 // ...
 }Z 
 Preconditions.checkArgument , )
  22. #02 Semantic Validation fun join(sep: String, strings: List<String>): String {


    require(sep.length < 2) { "sep.length < 2: " + sep }
 // ...
 }Z
  23. #02 Semantic Validation fun join(sep: String, strings: List<String>): String {


    require(sep.length < 2) { "sep.length < 2: " + sep }
 // ...
 }Z 
 Preconditions.checkArgument , )
  24. #02 Semantic Validation fun join(sep: String, strings: List<String>): String {


    if (sep.length < 2) { throw IllegalArgumentException("sep.length < 2: " + sep) }
 // ...
 }Z 
 require ) { }
  25. #02 Semantic Validation // throws IllegalArgumentException require(value: Boolean) require(value: Boolean,

    lazyMessage: () -> Any) requireNotNull(value: T?): T requireNotNull(value: T?, lazyMessage: () -> Any): T // throws IllegalStateException check(value: Boolean) check(value: Boolean, lazyMessage: () -> Any) checkNotNull(value: T?): T checkNotNull(value: T?, lazyMessage: () -> Any): T // throws AssertionError assert(value: Boolean) assert(value: Boolean, lazyMessage: () -> Any)
  26. #03 Anything and Nothing fun printName(user: User?) {
 val name

    = user?.name ?: throw IllegalArgumentException("User was null")
 println("Name is $name.")
 }
  27. #03 Anything and Nothing fun printName(user: User?) {
 val name

    = user?.name ?: throw IllegalArgumentException("User was null")
 println("Name is $name.")
 }Z
  28. #03 Anything and Nothing fun printName(user: User?) {
 val name

    = user?.name ?: throw IllegalArgumentException("User was null")
 println("Name is $name.")
 }Z
  29. #03 Anything and Nothing fun printName(user: User?) {
 val name

    = user?.name ?: throw IllegalArgumentException("User was null")
 println("Name is $name.")
 }Z
  30. #03 Anything and Nothing fun printName(user: User?) {
 val name

    = user?.name ?: throw IllegalArgumentException("User was null")
 println("Name is $name.")
 }Z
  31. #03 Anything and Nothing fun printName(user: User?) {
 if (user

    != null) {
 println("Name is ${user.name}.")
 }Y
 throw IllegalArgumentException("User was null")
 }Z 
 val name = ?.name ?:
  32. #03 Anything and Nothing fun printName(user: User?) {
 if (user

    != null) {
 println("Name is ${user.name}.")
 }Y
 throw IllegalArgumentException("User was null")
 }Z
  33. #03 Anything and Nothing fun printName(user: User?) {
 if (user

    != null) {
 println("Name is ${user.name}.")
 }Y
 throw IllegalArgumentException("User was null")
 println("A user has no name.")
 }Z
  34. #03 Anything and Nothing fun runServer(serverSocket: ServerSocket) {X
 while (true)

    {
 handleSocket(serverSocket.accept())
 }Y
 }Z runServer(ServerSocket(80))
 println("Running!")
  35. #03 Anything and Nothing fun runServer(serverSocket: ServerSocket): Nothing {X
 while

    (true) {
 handleSocket(serverSocket.accept())
 }Y
 }Z runServer(ServerSocket(80))
 println("Running!")
  36. #03 Anything and Nothing fun runServer(serverSocket: ServerSocket): Nothing {
 while

    (true) {
 handleSocket(serverSocket.accept())
 }
 } runServer(ServerSocket(80))
 println("Running!")
  37. #04 Let val user: User? = null
 
 if (user

    != null) {X
 // user not null
 }X
  38. #04 Let var user: User? = null
 
 if (user

    != null) {X
 // user might be null
 }X
  39. #04 Let var user: User? = null
 
 user?.let {X


    // it == user not null
 }X 
 
 if ( != null)
  40. #04 Let var user: User? = null
 
 user?.let {

    
 // it == user not null, only read once!
 }X
  41. #04 Let class Foo {
 @Volatile var user: User? =

    null
 
 fun doSomething() {
 user?.let { user ->
 // user not null, only read once!
 }X
 }Y
 }Z 
 
 
 it ==
  42. #04 Let class Foo {
 @Volatile var user: User? =

    null
 
 fun doSomething() {
 user?.apply { user ->
 // user not null, only read once!
 }X
 }Y
 }Z 
 
 
 
 let
  43. #04 Let class Foo {
 @Volatile var user: User? =

    null
 
 fun doSomething() {
 user?.run { user ->
 // user not null, only read once!
 }X
 }Y
 }Z
  44. #04 Let class Foo {
 @Volatile var user: User? =

    null
 
 fun doSomething() {
 user?.also { user ->
 // user not null, only read once!
 }X
 }Y
 }Z
  45. #05 Multiline String Literals val foo = "FOO!"
 val bar

    = "BAR!"
 val baz = "BAZ!"
 
 val string = """|$foo
 1|$bar
 2|$baz""".trimMargin()
  46. #06 Lazy but Speedy class NamePrinter(val firstName: String, val lastName:

    String) {
 fun printName() {
 println("$firstName $lastName")
 }Y
 }Z
  47. #06 Lazy but Speedy class NamePrinter(val firstName: String, val lastName:

    String) {
 var fullName: String? = null
 
 fun printName() {
 if (fullName == null) {
 fullName = "$firstName $lastName"
 }X
 println(fullName)
 }Y
 }Z
  48. #06 Lazy but Speedy class NamePrinter(val firstName: String, val lastName:

    String) {
 val fullName: String by lazy { "$firstName $lastName" }X
 
 fun printName() {
 println(fullName)
 }Y
 }Z 
 r ? = null
 
 
 if (fullName == null) {
 fullName =
 }X
  49. #06 Lazy but Speedy class NamePrinter(val firstName: String, val lastName:

    String) {
 val fullName: String by lazy { "$firstName $lastName" }X
 
 fun printName() {
 println(fullName)
 }Y
 }Z
  50. #06 Lazy but Speedy import kotlin.LazyThreadSafetyMode.NONE
 
 class NamePrinter(val firstName:

    String, val lastName: String) {
 val fullName: String by lazy(NONE) { "$firstName $lastName" }X
 
 fun printName() {
 println(fullName)
 }Y
 }Z
  51. #07 Code Block Measurement val helloStart = System.currentTimeMillis()
 println("Hello, world!")


    val helloTook = System.currentTimeMillis() - helloStart
 println("Saying 'hello' took ${helloTook}ms")
  52. #07 Code Block Measurement val helloTook = measureTimeMillis {
 println("Hello,

    world!")
 }X
 
 println("Saying 'hello' took ${helloTook}ms") val helloStart = System.currentTimeMillis()
 
 System.currentTimeMillis() - helloStart
  53. #07 Code Block Measurement val helloTook = measureTimeNanos {
 println("Hello,

    world!")
 }X
 
 println("Saying 'hello'Ztook ${helloTook}ns")
  54. #07 Code Block Measurement var helloTook = measureTimeNanos {
 println("Hello,

    world!")
 }X helloTook += measureTimeNanos {
 println("Hello, world!")
 }X
 
 println("Saying 'hello' twiceZtook ${helloTook}ns") l
  55. #08 Deprecation Levels import kotlin.DeprecationLevel.ERROR
 
 @Deprecated("Use strings.joinToString(sep).", level =

    ERROR)X
 fun join(sep: String, strings: List<String>): String { 
 // ...
 }Z
 
 join(", ", listOf("me", "you"))
  56. #08 Deprecation Levels import kotlin.DeprecationLevel.ERROR
 
 @Deprecated("Use strings.joinToString(sep).", level =

    ERROR)X
 fun join(sep: String, strings: List<String>): String { 
 // ...
 }Z
 
 join(", ", listOf("me", "you"))
  57. #08 Deprecation Levels import kotlin.DeprecationLevel.ERROR
 
 @Deprecated("Use strings.joinToString(sep).", level =

    ERROR)X
 fun join(sep: String, strings: List<String>): String { 
 // ...
 }Z
 
 join(", ", listOf("me", "you")) Error:(10, 1) Kotlin: Using 'join(String, List<String>): String' is an error. Use strings.joinToString(sep).
  58. #08 Deprecation Levels import kotlin.DeprecationLevel.HIDDEN
 
 @Deprecated("Use strings.joinToString(sep).", level =

    HIDDEN)X
 fun join(sep: String, strings: List<String>): String { 
 // ...
 }Z
 
 join(", ", listOf("me", "you")) ERROR ERROR Error:(10, 1) Kotlin: Using 'join(String, List<String>): String' is an error. Use strings.joinToString(sep).
  59. #08 Deprecation Levels import kotlin.DeprecationLevel.HIDDEN
 
 @Deprecated("Use strings.joinToString(sep).", level =

    HIDDEN)
 fun join(sep: String, strings: List<String>): String { 
 // ...
 }
 
 join(", ", listOf("me", "you"))
  60. #09 Deprecation Replacements @Deprecated("Use strings.joinToString(sep).",
 replaceWith = ReplaceWith("strings.joinToString(sep)"))X
 fun join(sep:

    String, strings: List<String>): String { 
 // ...
 }Z
 
 listOf("me", "you").joinToString(", ")
  61. #09 Deprecation Replacements @Deprecated("Use strings.joinToString(sep).",
 replaceWith = ReplaceWith("strings.joinToString(sep)"))X
 fun join(sep:

    String, strings: List<String>): String { 
 // ...
 }Z 
 
 
 
 
 
 join(", ", listOf("me", "you"))
  62. #09 Deprecation Replacements @Deprecated("Use Guava's Joiner.",
 replaceWith = ReplaceWith("Joiner.on(sep).join(strings)",
 imports

    = "com.google.common.base.Joiner"))X fun join(sep: String, strings: List<String>): String { 
 // ...
 }Z
 
 join(", ", listOf("me", "you")) strings.joinToString(sep) 
 .joinToString(
  63. #09 Deprecation Replacements @Deprecated("Use Guava's Joiner.",
 replaceWith = ReplaceWith("Joiner.on(sep).join(strings)",
 imports

    = "com.google.common.base.Joiner"))X fun join(sep: String, strings: List<String>): String { 
 // ...
 }Z
 
 join(", ", listOf("me", "you"))X 
 
 
 
 Joiner.on(", ").join(listOf("me", "you"))
  64. #09 Deprecation Replacements import com.google.common.base.Joiner
 @Deprecated("Use Guava's Joiner.",
 replaceWith =

    ReplaceWith("Joiner.on(sep).join(strings)",
 imports = "com.google.common.base.Joiner"))X fun join(sep: String, strings: List<String>): String { 
 // ...
 }Z
 
 Joiner.on(", ").join(listOf("me", "you")) 
 
 
 
 
 
 join(", ", listOf("me", "you"))X
  65. #10 Erasing Erasure fun sort(strings: List<String>) {
 // ...
 }Y

    
 fun sort(ints: List<Int>) {
 // ...
 }Z
  66. #10 Erasing Erasure fun sort(strings: List) {
 // ...
 }Y

    
 fun sort(ints: List) {
 // ...
 }Z
  67. #10 Erasing Erasure fun sort(strings: List<String>) {
 // ...
 }Y

    
 fun sort(ints: List<Int>) {
 // ...
 }Z
  68. #10 Erasing Erasure fun sortStrings(strings: List<String>) {
 // ...
 }Y

    
 fun sortInts(ints: List<Int>) {
 // ...
 }Z
  69. #10 Erasing Erasure fun sort(strings: List<String>) {
 // ...
 }Y

    
 fun sort(ints: List<Int>) {
 // ...
 }Z
  70. #10 Erasing Erasure @JvmName("sortStrings")
 fun sort(strings: List<String>) {
 // ...


    }Y
 @JvmName("sortInts")
 fun sort(ints: List<Int>) {
 // ...
 }Z