Strings & Basistypen
String-Templates statt Konkatenation, dreifach-gequotete Roh-Strings und ein Typsystem ohne Primitives - Int, Long, Double sind echte Typen, vereinheitlicht, aber effizient kompiliert.
Deutsche Übersetzung in Arbeit
Diese Lektion ist noch nicht ins Deutsche übersetzt und wird daher auf Englisch angezeigt. Der Rest der Seite ist vollständig lokalisiert.
Auf dieser Seite
Two everyday things read very differently in Kotlin: strings and basic types. String templates end the
"..." + variable + "..." concatenation ritual, and triple-quoted strings handle multi-line text cleanly. And
Kotlin's type system has no primitives - Int, Long, Double, Boolean are all real classes, unifying
the type hierarchy while the compiler still uses efficient JVM primitives under the hood. Both are small daily
wins for a Java developer.
String templates
In Java you build strings with + concatenation or String.format. Kotlin has string templates - embed a
variable or expression directly with $:
val name = "Ada"
val age = 36
println("$name is $age years old") // simple variable: $name
println("Next year she'll be ${age + 1}") // an expression: ${...}
println("Name length: ${name.length}") // any expression in ${}$variable inserts a simple variable; ${expression} inserts any expression. Compare the Java:
System.out.println(name + " is " + age + " years old") - the template version reads like the sentence it
produces, with no + noise. This is the same idea as Java's newer text blocks and formatted, but inline and
used constantly.
Multi-line and raw strings
Triple quotes create a raw string that spans lines and doesn't process escape sequences - ideal for JSON, SQL,
or regex where Java's \\ escaping is painful:
val json = """
{
"name": "$name",
"age": $age
}
""".trimIndent() // trimIndent() removes the common leading indentation
val regex = """\d{3}-\d{4}""".toRegex() // no double-backslash escapingtrimIndent() is the idiomatic companion - it strips the leading whitespace you added for code readability, so
the string's actual content starts at the left margin. (Templates still work inside triple-quoted strings, as
$name shows.)
No primitives: a unified type system
Java splits types into primitives (int, double, boolean - lowercase, not objects) and their boxed
wrappers (Integer, Double, Boolean - objects). This split causes autoboxing surprises and means primitives
can't be used as generic type arguments (List<int> is illegal; you need List<Integer>).
Kotlin has only the class types - Int, Long, Short, Byte, Double, Float, Boolean, Char:
val count: Int = 42 // a real type, capital I - no separate 'int'
val big: Long = 10_000_000_000
val ratio: Double = 3.14
val flag: Boolean = true
val list: List<Int> = listOf(1, 2, 3) // Int works directly as a generic argumentThere's no int-vs-Integer distinction to trip over. But here's the clever part: the compiler still uses JVM
primitives under the hood wherever possible. An Int local variable compiles to a JVM int (fast, no boxing);
it only boxes to an Integer when it must (e.g. as a nullable Int? or a generic type argument), exactly when
Java would. So you get a clean, unified type model in the source and efficient primitive performance in the
bytecode - the best of both.
Numeric literals and conversions
A couple of details Java developers should note:
- Underscores in literals for readability:
1_000_000,0xFF_EC_DE. - No implicit widening. Kotlin won't silently convert an
Intto aLong; you convert explicitly with.toLong(),.toDouble(), etc. This is stricter than Java (which auto-widens) and prevents a class of subtle bugs, at the cost of an occasional explicit.toX().
Int? boxes - nullability has a cost
Because a non-null Int compiles to a primitive int but a nullable Int? must be able to hold null, an Int? is
boxed to an Integer under the hood. Usually irrelevant, but in hot loops or huge collections of nullable numbers
it matters - a List<Int?> boxes every element. Prefer non-nullable numeric types on performance-sensitive paths,
and know that nullability, not the Int/Integer syntax, is what triggers boxing in Kotlin.
Java's primitives and wrappers are like having two entirely separate sets of measuring cups - a lightweight everyday set (int, double) and a fancy boxed set for special occasions (Integer, Double) - and constantly having to remember which drawer a recipe needs, sometimes swapping between them mid-cook (autoboxing). Kotlin gives you one labeled set of cups (Int, Double) that you use everywhere, so there's no drawer-juggling in your recipe (source code). Behind the kitchen door, the staff quietly hand you the lightweight cup when that's all that's needed and only fetch the heavier boxed one when the dish truly requires it (nullable or generic) - you get the convenience of one set with the efficiency of the right cup each time, without thinking about it. String templates are just writing the recipe in plain sentences ('add $sugar cups of sugar') instead of gluing fragments together.
Rewrite this Java in idiomatic Kotlin: it builds a greeting with concatenation - `String msg = "Hi " + user.getName()
- ", you have " + count + " messages";
- and separately declaresint count = 5;used in aList` of counts. Show the string template version and explain how Kotlin represents the int in the list versus as a plain local.
How does Kotlin's handling of basic types differ from Java's, in source and in bytecode?
Key takeaways
- String templates embed variables and expressions directly: "$name is ${age + 1}" - no + concatenation, reading like the sentence produced.
- Triple-quoted raw strings span multiple lines without escape processing (great for JSON/SQL/regex); trimIndent() strips the code-indentation.
- Kotlin has no primitives in source - Int, Long, Double, Boolean are class types usable directly as generic arguments (no int-vs-Integer split).
- The compiler still uses efficient JVM primitives under the hood, boxing only when necessary (a nullable Int? or a generic type argument) - same performance model as Java.
- Numeric literals allow underscores (1_000_000), and Kotlin requires explicit conversions (.toLong(), .toDouble()) with no implicit widening - stricter than Java.