does that in practice → Boilerplate code • Convention for naming getters/setters • Not enforced / may not be respected • Getting/setting values = method calls :-( • Not using ‘=‘ • Step-by-step debugging is unnecessarily complex • Have to write equals() / hashCode() • Not immutable
NewTopic(topicName, topicParameters.getNumPartitions(), topicParameters.getReplicationFactor()); Duplicated type Method calls… just to get values Parsers no longer need semicolons (this is 2017)
• make the code concise + readable • make the code safer than pure Java • Made for 100% interoperability with Java • Migrate one class at a time • Statically typed • Compiles faster than Scala (troll)
IDE: mature support in IntelliJ IDEA (who cares about Eclipse) • Official programming language on Android • Extended support for Kotlin in Spring 5 • (To write more idiomatic code)
adminClientFactory: KafkaAdminClientFactory) { fun describeCluster(region: String, cluster: String): ClusterDto { … } } Function name: Type Constructor with 1 parameter
"us-east-1" val cluster: String = "engine" val adminClient = KafkaDescribeClient(adminClientFactory) • Defining a variable (you don’t really need that) var something = 12 something = 42 No `new` keyword
in a file (in a package, no class) fun nodeToDto(node: Node): NodeDto { return NodeDto(node.id(), node.host(), node.port(), node.rack()) } • Import the functions of the class import com.….dto.* • Call the function nodeToDto(controller)
== → equals() Note that the `==` operator in Kotlin code is translated into a call to [equals] when objects on both sides of the operator are not null. • … meaning it’s safe, and `o == null` still works
AclParameters( val operation: AclOperation, val user: String, val hostname: String?, val groupId: String?) • Create an instance (no `new`) val aclParams = AclParameters(AclOperation.READ, "u1", "h1", “g1") • equals() / hashCode() / toString() → generated • From Java = POJO with a constructor + getters • For Jackson: there’s a module
= aclBindings.stream() .filter(aclBinding -> aclBinding.entry().principal().equals(filterUser)) .collect(Collectors.toList()); • The same in Kotlin val userAclBindings = aclBindings.filter { it.entry().principal() == filterUser } Type inference No stream(), no Collector Implicit argument Replaces equals()
the type with ‘?’ to declare a nullable var/param var s: String? = null • Need to test for nulls before being able to use the value return s.length Error:(37, 17) Kotlin: Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String? if (s !=null) { return s.length }
not declared as nullable private fun getTag(instance: Instance, tagKey: String): String { val tag = instance.tags .filter { it.key.equals(tagKey, ignoreCase = true) } .map { it.value } .firstOrNull() return tag } Error:(40, 16) Kotlin: Type mismatch: inferred type is String? but String was expected • Safe: private fun getTag(instance: Instance, tagKey: String): String { val tag = instance.tags .filter { it.key.equals(tagKey, ignoreCase = true) } .map { it.value } .firstOrNull() if (tag == null) { throw RuntimeException("Tag [${tagKey}] not found") } return tag } • (Or just call first() in this case) tag is of type String? tag is of type String
withAdminClient(func: (AdminClient) -> R): R { val adminClient = adminClientFactory.createAdminClient() return adminClient.use { func(adminClient) } } A function with one param of type AdminClient Call it… as a function (Bye bye functional interfaces)
Resolved statically / locally • Example fun AmazonEC2.findInstances(request: DescribeInstancesRequest): ArrayList<Instance> { val allInstances = ArrayList<Instance>() var token: String? do { val result = this.describeInstances(request) val instances = result.reservations.flatMap { it.instances } allInstances.addAll(instances) token = result.nextToken request.nextToken = token } while (token != null) return allInstances } ec2.findInstances(request) Class to extend Method