Creative Commons Licence This work is licensed under a Creative Commons
Attribution-ShareAlike 4.0 International License

Examples of Kotlin making your Java code better

Andy Balaam
artificialworlds.net/blog

Contents

Kotlin

Kotlin

Things that are good

Gentle nudges

Good patterns

Examples

Value objects

public class Thing { private final String name; private final String desc; public Thing(String name, String desc) { this.name = name; this.desc = desc; } public String getName() { return name; } // ...

Value objects

public class Thing { // ... @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((desc == null) ? 0 : desc.hashCode()); result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } // ...

Value objects

public class Thing { // ... @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } Thing other = (Thing) obj; if (desc == null) { if (other.desc != null) { return false; } } else if (!desc.equals(other.desc)) { return false; } if (name == null) { if (other.name != null) { return false; } } else if (!name.equals(other.name)) { return false; } return true; } // ...

Value objects

public class Thing { // ... @Override public String toString() { return "Thing(name=" + name + ", desc=" + desc + ")"; } // ...

Value objects

Value objects

data class ThingK(val name: String, val desc: String)

Parameters

public class Message { final String id; final String customer; final String to; final String from; final String body; public Message(String id) { this(id, null, null, null, null); } public Message forCustomer(String customer) { return new Message(... } public Message withTo(String to) { // ...

Parameters

Message m = new Message("234") .withTo("012") .forCustomer("Acme");

Parameters

data class MessageK( val id: String, val customer: String? = null, val to: String? = null, val from: String? = null, val body: String? = null )

Parameters

val m = MessageK("234", to="012", customer="Acme")

Null safety

public class Scorer { static final Map<String, Integer> wordValues = new HashMap<>(); static { wordValues.put("purple", 3); wordValues.put("lavender", 5); wordValues.put("amethyst", 50); } // ...

Null safety

public class Scorer { // ... final Map<String, Integer> scores = new HashMap<>(); void scoreRequest(String user, String path) { scores.merge( user, wordValues.get(path), Integer::sum ); } int total(String user) { return scores.get(user); }

Null safety

@Test public void Different_users_are_independent() { Scorer s = new Scorer(); s.scoreRequest("user1", "purple"); s.scoreRequest("user2", "purple"); s.scoreRequest("user1", "lavendar"); // CRASH assertThat(s.total("user1"), equalTo(8)); assertThat(s.total("user2"), equalTo(3)); }

Null safety

private val wordValues = mapOf( Pair("purple", 3), Pair("lavender", 5), Pair("amethyst", 50) )

Null safety

class ScorerK { val scores = mutableMapOf<String, Int>() fun scoreRequest(user: String, path: String) { scores.merge( user, wordValues[path] ?: 0, Integer::sum ) } fun total(user: String): Int { return scores[user] ?: 0 } }

Null safety

class ScorerK { val scores = mutableMapOf<String, Int>() fun scoreRequest(user: String, path: String) { scores.merge( user, wordValues[path] ?: 0, Integer::sum ) } fun total(user: String): Int { return scores[user] ?: 0 } }

Null safety

Immutability

public class Emitter { public void handleMessage(// ... long start, end; // ... start = System.currentTimeMillis(); String url = urls.get(m.to); if (url == null) { // ... } for(start = 0; start < 3; start++) { // ... } end = System.currentTimeMillis(); System.out.println(m.id + ": " + (end-start));

Immutability

public class Emitter { public void handleMessage(// ... final long start, end; // ... start = System.currentTimeMillis(); String url = urls.get(m.to); if (url == null) { // ... } for(start = 0; start < 3; start++) { ERROR! // ... } end = System.currentTimeMillis(); System.out.println(m.id + ": " + (end-start));

Immutability

class EmitterK { fun handleMessage(// ... val start: Long val end: Long // ... start = System.currentTimeMillis() val url = urls[m.to] if (url == null) { // ... } for(start in 0..3) { // ... } end = System.currentTimeMillis() println(m.id + ": " + (end - start))

Immutability

class EmitterK { fun handleMessage(// ... val start: Long val end: Long // ... start = System.currentTimeMillis() val url = urls[m.to] if (url == null) { // ... } for(start in 0..3) { // Warning: name shadowed // ... } end = System.currentTimeMillis() println(m.id + ": " + (end - start))

Immutability

Handling cases

long reattemptTs = NEVER; switch (code) { case 451: case 2020: reattemptTs = now + (ONE_HOUR * tries); break; case 711: case 1522: reattemptTs = now + ONE_MINUTE; break; case 2: default: reattemptTs = NEVER; break; } return reattemptTs;

Handling cases

return when (code) { 451, 2020 -> now + (ONE_HOUR * tries) 711, 1522 -> now + ONE_MINUTE 2 -> NEVER else -> NEVER }

Handling cases

sealed class Response(val code: Long); class Ok : Response(0) class FatalError(code: Long) : Response(code) class FastError(code: Long) : Response(code) class SlowError(code: Long) : Response(code) // ... return when (code) { is SlowError -> now + (ONE_HOUR * tries) is FastError -> now + ONE_MINUTE is FatalError -> null is Ok -> null }

Handling cases

return when (code) { 451, 2020 -> now + (ONE_HOUR * tries) 711, 1522 -> now + ONE_MINUTE 2 -> NEVER else -> NEVER }

Constructors

class Requester { Requester(String scheme, String host, HttpClient client) { this.scheme = scheme; this.host = host; this.client = client; } Requester( String user, String pass, String host, boolean useSsl) { this(useSsl, host, new SimpleClient(user, pass)); } Requester(boolean useSsl, String host, HttpClient client) { this(useSsl ? "https" : "http", host, client); }

Constructors

class RequesterK( val scheme: String, val host: String, val client: HttpClient ) { constructor( user: String, pass: String, host: String, useSsl: Boolean) : this(useSsl, host, SimpleClient(user, pass)) constructor( useSsl: Boolean, host: String, client: HttpClient) : this(if (useSsl) "https" else "http", host, client)

Constructors

Summary

More info

Videos youtube.com/user/ajbalaam
Twitter @andybalaam
mastodon.social @andybalaam@mastodon.social
Blog artificialworlds.net/blog
Projects artificialworlds.net
GitHub github.com/andybalaam