Russische Insel
im finnischen Golf, 32km vor Petersburg
statisch typisierte
Allzweck-
Sprache für
Freie Software
APL 2.0 – IDE, compiler, libs, build tools
backed by JetBrains
20 Vollzeit & Community
„dogfooding“: 0,5 Mio. LOC
Stabil
Start: ~2010, v1.0 Feb. '16
Long-term backward compatibility
Integrationen
IntelliJ, Eclipse, Netbeans
Maven, Ant, Gradle, CLI
Juli 2011
Offizielle Vorstellung
1.0 – Februar 2016
Production-ready, LTS version
1.1 – April 2017
Coroutines, Type Aliases, JS, Android
Mai 2017
Google integriert Kotlin in Android
1.2 – November 2017
Multiplattform-Support
1.3 – November 2018
Contracts, Unsigneds,
Inline Classes
import java.util.*
fun main(args: Array<String>) {
val name = if (args.size > 0) args[0] else "Publikum"
val zuschauer = Gast(name, title = Title.wertes)
println(zuschauer)
println("Hallo ${zuschauer.title} ${zuschauer.name}")
}
class Gast(val name: String,
var zeit: Date = Date(),
val title: Title)
enum class Title { Herr, Frau, wertes }
← Optional semicolons
← Top-level functions
← Kein new
,
named Params
← String interpolation
← Default values
← val
≙ public final
Mischen von Java & Kotlin-Code
bei problemlosem, gleichzeitigen Zugriff in beide Richtungen
Typangaben üblicherweise nur an Schnittstellen erforderlich
getX()
/setX()
-Paare
x
public final class Gast {
@NotNull
private final String name;
@NotNull
private Date zeit;
@Nullable
private final Title title;
@NotNull
public final String getName() {
return this.name;
}
@NotNull
public final Date getZeit() {
return this.zeit;
}
public final void setZeit(@NotNull Date date) {
checkParameterIsNotNull(date, "<set-?>");
this.zeit = date;
}
@Nullable
public final Title getTitle() {
return this.title;
}
public Gast(@NotNull String name,
@NotNull Date zeit,
@Nullable Title title) {
checkParameterIsNotNull(name, "name");
checkParameterIsNotNull(zeit, "zeit");
this.name = name;
this.zeit = zeit;
this.title = title;
}
public Gast(String string, Date date,
Title title, int n) {
if ((n & 2) != 0) {
date = new Date();
}
this(string, date, title);
}
@NotNull
public final String component1() {
return this.name;
}
@NotNull
public final Date component2() {
return this.zeit;
}
@Nullable
public final Title component3() {
return this.title;
}
@NotNull
public final Gast copy(@NotNull String name,
@NotNull Date zeit,
@Nullable Title title) {
checkParameterIsNotNull(name, "name");
checkParameterIsNotNull(zeit, "zeit");
return new Gast(name, zeit, title);
}
public String toString() {
return "Gast(name=" + this.name +
", zeit=" + this.zeit +
", title=" + this.title + ")";
}
public int hashCode() {
String s = this.name;
Date d = this.zeit;
Title t = this.title;
return ((s != null ? s.hashCode() : 0) * 31
+ (d != null ? d.hashCode() : 0)) * 31
+ (t != null ? t.hashCode() : 0);
}
public boolean equals(Object object) {
if (this == object) return true;
if (!(object instanceof Gast))
return false;
Gast gast = (Gast)object;
if (!areEqual(this.name, gast.name)
|| !areEqual(this.zeit, gast.zeit)
|| !areEqual(this.title, gast.title))
return false;
return true;
}
}
… 3 Attribute!
fun String.lastChar() = this.get(this.length - 1)
this
zeigt auf das erweitertete Objekt// Verwendung
val c = "Hallo Zuschauer!".lastChar()
// Extension property für das Android EditText Widget
var EditText.stringValue: String
get() = text.toString()
set(str) { setText(str) }
// Verwendung
nameField.stringValue = "Max Muster"
Funktionen sind Sprachelemente erster Klasse und können daher auch als Variablen, Properties, Parameter und Rückgabewerte genutzt werden.
Durch Verschachtelung lassen sich Funktionen höherer Ordnung (Higher-order functions) erschaffen
view.setOnClickListener({ e -> doSomething(e) })
↓
view.setOnClickListener() { e -> doSomething(e) }
↓
view.setOnClickListener { e -> doSomething(e) }
↓
view.setOnClickListener { doSomething(it) }
List<String> list = Arrays.asList("a","b","c");
for (int index = 0; index < list.size(); index++) {
if (index % 2 == 0)
System.out.println(index + " -> " + list.get(index));
}
val list = listOf("a", "b", "c")
for (index in list.indices.filter { it % 2 == 0 }) {
println("$index -> ${list.get(index)}")
}
Nur-lesbare Variablen
aufwandsfrei durch val
statt var
Standard-Collection Interfaces (List
, Set
, …) sind read-only
Zum ändern muss man z.B. MutableList
statt List nutzen
Klassen & Methoden sind final
by Default
open class ExtendableClass {
open fun overridableMethod() { … }
}
class Derived: ExtendableClass() {
override fun overridableMethod() { … }
}
null
und seine Folgen
Nur explizit Nullwert-fähige Typen
akzeptieren null
.
Ungeprüfte Zugriffe führen zu Compile-Fehlern!
An den Schnittstellen baut Kotlin
Prüfungen & @NotNull
Annotationen ein.
null
-Werte aus Java-CodeAlle Rückgabewerte aus Java-Code als T?
zu verstehen
wäre zwar richtig, aber extrem unkomfortabel.
Daher besitzt Kotlin das Konzept sog. Platform Types T!
.
↓
static
-Feld kein direktes static
in Kotlin, sondern companion object
Mehr Ausdrücke (if
, ?:
, ?.
, …)
Pattern matching (when
)
String Templates
Syntactic Sugar
listOf(…)
, repeat(3){…}
,
with(x){…}
, x.apply{…}
, …
public
sind Default
kein new
– ;
optional
Operatoren & Dekomposition über Namen
Ausdrucksstärke
Standard-Bibliothek
Konventionen
EditText editTitle = (EditText) v.findViewById(R.id.edit_title);
editTitle.setText(mItem.getTitle());
CheckBox enabledBox = (CheckBox) v.findViewById(R.id.enable_box);
enabledBox.setChecked(true);
Button createButton = (Button) v.findViewById(R.id.create_entry);
createButton.setOnClickListener(new OnClickListener() {
@Override public void onClick(View button) {
createElement();
}
});
… ständige Lookups & Typecasts von Views über findViewById()
.
Das Kotlin Android Extensions erzeugt virtuelle mylayout.xml
-Pakete
import kotlinx.android.synthetic.main.mylayout.*
edit_title.setText(mItem.title)
enable_box.isChecked = true
create_entry.setOnClickListener { createElement() }
Ein einfacher Import erlaubt typsicheren Zugriff auf alle
darin enthaltene View-Elemente direkt als simples Property.
Ohne zusätzlichen Code, Annotations oder Runtime!
class FirstClassFunction(
val f1: (String) -> Int,
val f2: (Int) -> Boolean) {
fun strToBool(str: String): Boolean {
val f: (String) -> Boolean = higherOrderFun()
return f(str)
}
private fun higherOrderFun(): (String) -> Boolean {
return { x -> f2(f1(x)) }
}
}
fun main(args: Array<String>) {
val c = FirstClassFunction(
Integer::parseInt,
{ it % 2 == 0 }
)
val strings = listOf("2", "7", "8")
println(strings.map(c::strToBool))
}
← Funktion als Parameter
← Funktion als Variable
← Funk. als Rückgabewert
← Kombination via Lambda
← Funk.-Referenz
← Lambda-Ausdruck
→ Was kommt raus?
null
– Typische KonstellationÜber Namenskonventionen. Feste Menge & Präzedenz
Es ist möglich, Funktionssignaturen zu definieren, die Lambda-Ausdrücke
erwarten bei denen this
auf Zielobjekte eines bestimmten Typs zeigen.
Darüber sind typsichere DSLs möglich:
← Erwartet Funktion mit this
vom Typ HTML
← Erstellung des receiver object
← Führe Lambda auf receiver object aus
← Kurzform von html({…})
← Lambda-Ausdruck für einen HTML
-„Empfänger“
build.gradle.kts
→ http://try.kotl.in/