17 мая 2017
Today the Android team is excited to announce that we are officially adding support for the Kotlin programming language. Kotlin is a brilliantly designed, mature language that we believe will make Android development faster and more fun. It has already been adopted by several major developers — Expedia, Flipboard, Pinterest, Square, and others — for their production apps. Kotlin also plays well with the Java programming language; the effortless interoperation between the two languages has been a large part of Kotlin's appeal.
package helloWorld fun main(args: ArrayAt first glance, you will see comforting elements like curly braces, classes, packages, functions and methods. But as you go deeper, you will discover that although Kotlin is based on familiar concepts, it is a uniquely modern, elegant and pragmatic riff on those models. In particular, Kotlin is highly expressive with minimal syntactic friction between your thoughts and what you have to type in order to express those thoughts. If when writing code you have asked yourself questions that began "why do I have to …?" you will be pleased to learn that in Kotlin the answer to many of those questions is "you don't!") { println("Hello World!") }
equals()
,
hashCode()
and toString()
when implementing a simple
class. Here is a typical example from the Java programming language (in a
microscopic font for brevity).
public class Customer { private String name; private String email; private String company; public Customer(String name) { this(name, "", ""); } public Customer(String name, String email) { this(name, email, ""); } public Customer(String name, String email, String company) { this.name = name; this.email = email; this.company = company; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getCompany() { return company; } public void setCompany(String company) { this.company = company; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Customer customer = (Customer) o; if (name != null ? !name.equals(customer.name) : customer.name != null) return false; if (email != null ? !email.equals(customer.email) : customer.email != null) return false; return company != null ? company.equals(customer.company) : customer.company == null; } @Override public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + (email != null ? email.hashCode() : 0); result = 31 * result + (company != null ? company.hashCode() : 0); return result; } @Override public String toString() { return "Customer{" + "name='" + name + '\'' + ", email='" + email + '\'' + ", company='" + company + '\'' + '}'; } }In Kotlin, you don't have to type any of that. This single line is equivalent to the entire class above.
data class Customer(var name: String, var email: String = "", var company: String = "")
var neverNull: String = "something" var mightBeNull: String? = null // "?" indicates this can be null if (neverNull.length > 0) { // This is OK … } if (mightBeNull.length > 0) { // Compiler catches this error for you … }Named parameters and default arguments
fun orderPizza(size: Size, pepperoni: Boolean, mushrooms: Boolean, ham: Boolean, pineapple: Boolean, pickles: Boolean, sausage: Boolean, peppers: Boolean, onion: Boolean) { ... } // Wait… did I just order pickles on my pizza? // Why do we even have that option? orderPizza(Size.LARGE, true, false, false, false, true, false, true, false)Compare that to a similar scenario using named parameters and default arguments:
fun orderPizza(size: Size, pepperoni: Boolean = false, mushrooms: Boolean = false, ham: Boolean = false, pineapple: Boolean = false, pickles: Boolean = false, sausage: Boolean = false, peppers: Boolean = false, onion: Boolean = false) { ... } orderPizza(Size.LARGE, ham = true, mushrooms = true)In addition to helping to avoid tragic pizza outcomes, this is much easier to read. It also reduces the number of variants of overloaded functions you need to write.
// Please don't put this in your app! when { password.equals("password") -> println("Insecure password!") password.length < 4 -> println("Too short!") else -> { println("Secure password!") } }Smart Casts
if (obj is String) { // Compiler casts obj to a String for you. // (Would work with && instead of nested ifs too.) if (obj.length > 0) { … } }This generalizes to the when statement as well:
// Assume reasonable implementations of Cat and Dog when (obj) { is Cat -> obj.meow(...) is Dog -> obj.woof(...) else -> { … } }Extension functions
toPigLatin
method, you can now add it yourself
without having to create a new helper class to wrap String or going through the
trouble of serving on a language committee:
// The "String." prefix indicates that this method should // extend the existing String class fun String.toPigLatin() : String { ... } val plainOldString : String = "some text" // Can now call toPigLatin as if were a method on String println(plainOldString.toPigLatin()) // Or: println("some text".toPigLatin())Destructuring Declarations
data class Order(val itemCode: String, val quantity: Int, val price: Float)A function that uses one of these classes as the return type is very close to supporting multiple return values:
fun getOrder(...): Order { ... return Order(itemCode, quantity, price); }To get all the way there, you can use the destructuring declaration syntax. The following statement takes the
Order
object, extracts its three
properties, and then assigns them to the three variables what
,
howMany
and howMuch
— all courtesy of the Kotlin
compiler, which also infers the correct types for you.
val (what, howMany, howMuch) = getOrder(...)Lambdas
fun allStrings(collection: CollectionThat lambda syntax is building block of one of Kotlin's coolest features: the ability to create builders that use JSON-like syntax that also happens to be syntactically valid Kotlin. This example is adapted from an extended discussion here, but you can get the flavor of what it possible with this snippet:)= collection.all { it is String }
fun generatePage(withEmphasis : Boolean) { val result = html { head { title { +"Kotlin Builders" } } body { h1 { +"Kotlin Builders" } p { +"This is " if (withEmphasis) b { +"really " } +"interesting" a(href = "https://goo.gl/rHwJio") { +"More here" } } } } println(result) }There are a couple of interesting things going on here. First, this shows how expressive Kotlin's functional syntax can be: in this example, "
html
", "head
", "body
, etc. are all just
functions written in Kotlin and the stuff in curly braces that follows are
functional parameters. (This snippet uses functions with names that match HTML
tags to build a representation of a web page, but of course you can use this
pattern to build any complex data structure with whatever names you want.) The
second interesting thing is the "withEmphasis
" conditional. This
may look like we are mixing code (if (withEmphasis)
…) with data
(all the HTML-esque tags), but the "data" here is actually just more code. Since
it is all really just code, this lets you build complex data structures using a
declarative syntax while also having inline access to the full capabilities of
the Kotlin language.