---?image=assets/image/background.jpg
- My Background
- Why Kotlin?
- Code Code Code
- Demo Application
@ul
- >10 years Java
- more than 1 year @ Meshcloud
- solution-oriented developer @ulend
@ul
- all Java frameworks can be used without big problems
- same development paradigm as Java
- step-by-step conversion of existing Java app
- it's Java without the flaws + useful candy @ulend +++
@ul
- Practical, not academic
- Expressive
- Developed by JetBrains, Open Source -> great IDE support
- Convert Java to Kotlin Button
- Great tips how to optimize code within editor
- Strictly-Typed -> Null-Safety @ulend
@ul
- Billing of Cloud Platform
- Resources (VMs, Apps, etc)
- Projects are container of resources
- Service to calculate costs per project @ulend
buildscript {
ext {
kotlinVersion = '1.2.71'
kotlinPlugin = 'org.jetbrains.kotlin:kotlin-gradle-plugin'
}
dependencies {
classpath "$kotlinPlugin:$kotlinVersion"
}
}
+++
apply plugin: "java"
apply plugin: "kotlin"
sourceSets {
main.kotlin.srcDirs += 'src/main/java'
main.java.srcDirs += 'src/main/java'
}
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
}
val x = "value" // immutable & type inference
var y: Boolean // mutable
+++ Type Inference
// Java (< Java 10)
Map<ResourceType, List<Resource>> resourceMapByType =
service.findResourceMapByType();
// Kotlin
val resourceMapByType = service.findResourceMapByType()
+++ Functions
fun sum(a: Int, b: Int): Int {
return a + b
}
// expression body & type inference
fun sum(a: Int, b: Int) = a + b
+++
fun formatText() = if (projects.isEmpty()) "n/a" else projects
+++ Null checks during compilation
var x = "value"
x = null // compile error
+++ Safe calls
var x: MyClass?
val child = x?.child // if x == null -> null
+++ Intelligent compiler
if (x != null) {
val child = x.child // knows that x != null
}
+++ Smart casts
if (x is String) {
print(x.length) // x is automatically cast to String
}
+++ Elvis Operator
// findOne or throw exception if result == null
projectRepository.findOne(id) ?: throw NotFoundException()
tryFindProjectList() ?: emptyList()
public Date convertToDatabaseColumn(Instant instant) {
return instant != null ? Date.from(instant) : null;
}
+++ let in Kotlin
// let: return result & use "it" for current object
fun convertToDatabaseColumn(instant: Instant?): Date? {
return instant?.let { Date.from(it) }
}
+++ run
// run: return result & use "this" for current object
fun convertToEntityAttribute(value: Date?): Instant? {
return value?.run { toInstant() }
}
+++ apply
// apply: return self & use "this" for current object
val headers = HttpHeaders().apply {
contentType = MediaType.APPLICATION_JSON
add("ProjectId", project.id)
}
+++ also
// also: return self & use "it" for current object
fun createAndLogProject() {
return generateProject().also { log(it) }
}
val text = "Project ${project.name}: $details"
+++ Structural equality with ==
project == otherProject // calls null-safe equals
project === otherProject // referential equality
+++ When expressions
when {
"Bitcoin" in projectNames -> println("Bad guy!")
projectNames is empty -> println("No Projects")
else -> println("Just normal projects!")
}
+++ Collection creation
var myList = listOf('a', 'b', 'c')
var mySet = setOf(1, 2)
var myMap = mapOf('a' to 5, 'b' to 10)
+++ Ranges
for (i in 1..100)
for (i in 10 downTo 1)
+++ Destructuring
// Java
for (Map.Entry<String, Object> entry : map.entrySet()) {
print("Key: " + entry.getKey() + "Value: " + entry.getValue());
}
// Kotlin
for ((key, value) in map) {
print("Key: $key, Value: $value")
}
projectRepository
.findAll()
.stream()
.map(p -> new ProjectListDTO(p))
.collect(Collectors.toList());
+++ Kotlin
projectRepository
.findAll()
.map { ProjectListDTO(it) }
+++ Implicit Getters/Setters & property access:
class Project {
var name: String
}
val pName = Project().name
+++ Data classes (with equals, hashcode, toString & copy):
data class Project(
val name: String,
val description: String
) {
val fullText: String
get() = "$name - $description"
}
fun create(
name: String,
description: String = "default"
)
+++ Named Arguments
create(
name = "My Project",
description = "Some details"
)
+++ Java (Function, Consumer, Supplier, BiConsumer, …)
public String myFunction(
BiFunction<String, String, String> fn
) {
fn.apply("1", "2") // .get() on Supplier, ...
}
+++ Kotlin
fun myFunction(
fn: (String, String) -> String
) {
fn("1", "2")
}
val customFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS")
fun Date.formatted(): String {
return customFormat.format(this)
}
val dateAsText = Date().formatted()
@[1-5] @[6-7] +++
fun ProjectRepository.findOneOrThrow(id: Long): Project {
return findOne(id)
?: throw NotFoundException("Could not find project $id")
}
inline fun <reified T : Any> createEmptyWrappedResource()
: PagedResources<EmbeddedWrapper> {
val wrappers = EmbeddedWrappers(false)
val emptyWrapper = wrappers.emptyCollectionOf(T::class.java)
val embedded = listOf(emptyWrapper)
return PagedResources(embedded)
}
Java | 460 |
Kotlin | 252 |
Reduction | 46% |
https://github.com/Meshcloud/spring-kotlin-example | |
+++ | |
LoC without data classes |
Java | 232 |
Kotlin | 185 |
Reduction | 21% |
https://github.com/Meshcloud/spring-kotlin-example |