Stage | Kotlin feature | Java features | Notes |
1 | Calling Java code from Kotlin Getters and Setters Methods returning void Escaping for Java identifiers that are keywords in Kotlin Null-Safety and Platform Types Notation for Platform Types Nullability annotations JSR-305 Support Type qualifier nicknames Type qualifier defaults Compiler configuration Mapped types Java generics in Kotlin Java Arrays Java Varargs Operators Checked Exceptions Object Methods wait()/notify() getClass() clone() finalize() Inheritance from Java classes Accessing static members Java Reflection SAM Conversions Using JNI with Kotlin | ||
1 | Calling Kotlin from Java Properties Package-Level Functions Instance Fields Static Fields Static Methods Visibility KClass Handling signature clashes with @JvmName Overloads Generation Checked Exceptions Null-safety Variant generics Translation of type Nothing | https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html | |
1 | Improving Java Interop: Top-Level Functions and Properties | https://blog.jetbrains.com/kotlin/2015/06/improving-java-interop-top-level-functions-and-properties/ | |
1 | Functions | ||
1 | Interfaces | ||
1 | Classes and Inheritance Classes Constructors Secondary Constructors Creating instances of classes Class Members Inheritance / open class Overriding Methods / open fun Overriding Properties / open val Calling the superclass implementation Overriding Rules Abstract Classes Companion Objects | ||
1 | Nested and Inner Classes Inner classes Anonymous inner classes | ||
1 | Visibility Modifiers Packages top-level Classes and Interfaces private, protected, internal, public Constructors Local declarations Modules | https://kotlinlang.org/docs/reference/visibility-modifiers.html | |
1 | ; | ||
1 | package vlfsoft.iq.kotlin.fromjava | package vlfsoft.iq.kotlin.fromjava; | http://kotlinlang.org/docs/reference/basic-syntax.html#defining-packages |
1 | Default Arguments | https://kotlinlang.org/docs/reference/functions.html#default-arguments | |
1 | Named Arguments | https://kotlinlang.org/docs/reference/functions.html#named-arguments | |
1 | data class ImmutableValueObjectKt(val a: Int) | public class ImmutableValueObject { private final int a; public ImmutableValueObject(final int a) { this.a = a; } public int getA() { return a; } } | https://kotlinlang.org/docs/reference/data-classes.html https://kotlinlang.org/docs/reference/sealed-classes.html#sealed-classes |
1 | class MutableValueObjectKt(var a: Int) | public class MutableValueObject { private int a; public MutableValueObject(final int a) { this.a = a; } public int getA() { return a; } public void setA(final int a) { this.a = a; } } | |
1 | data class MyEntity( @Id @Column(nullable = false) @GeneratedValue(strategy = GenerationType.AUTO) var id: Long = 0, var name: String = “” ) | ||
| |||
2 | Explicit return types | https://kotlinlang.org/docs/reference/functions.html#explicit-return-types | |
2 | fun asList(vararg ts: T) When we call a vararg-function, we can pass arguments one-by-one, e.g. asList(1, 2, 3), or, if we already have an array and want to pass its contents to the function, we use the spread operator (prefix the array with *): val a = arrayOf(1, 2, 3) val list = asList(-1, 0, *a, 4) | void asList(T... ts) | https://kotlinlang.org/docs/reference/functions.html#variable-number-of-arguments-varargs |
2 | fun main(args: Array<String>) { } | public class Application { public static void main(String[] args) { } } | https://blog.jetbrains.com/kotlin/2015/06/improving-java-interop-top-level-functions-and-properties/ |
2 | Single-Expression functions fun sum(a: Int, b: Int) = a + b | public class Function { public static int sum (final int a, final int b) { return a + b; } } | http://kotlinlang.org/docs/reference/basic-syntax.html#defining-functions https://kotlinlang.org/docs/reference/functions.html#single-expression-functions |
2 | Unit-returning functions fun printSum(a: Int, b: Int) { println("sum of $a and $b is ${a + b}") } | void, Void public static void printSum(final int a, final int b) { System.out.printf("sum of %d and %d is %d", a, b, a + b); } | https://kotlinlang.org/docs/reference/functions.html#unit-returning-functions https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html |
2 | val a: Int = 2 val a = 2 | final int a = 2; | http://kotlinlang.org/docs/reference/basic-syntax.html#defining-variables |
2 | var a = 5 | int a = 2; | |
2 | Compile-Time Constants const val PI = 3.14 PI | public class Math { public final static double PI = 3.14; } Math.PI; | https://kotlinlang.org/docs/reference/properties.html#compile-time-constants Naming convention by default: Upper case letters and _ |
2 | // This is an end-of-line comment /* This is a block comment on multiple lines. */ | // This is an end-of-line comment /* This is a block comment on multiple lines. */ | http://kotlinlang.org/docs/reference/basic-syntax.html#comments |
2 | Documenting Kotlin Code Generating the Documentation KDoc Syntax Block Tags Inline Markup Linking to Elements Module and Package Documentation | ||
2 | Inline Markup /** * [printSum] */ |
/** * {@link #printSum(int, int)} */ | http://kotlinlang.org/docs/reference/kotlin-doc.html#inline-markup |
2 | Inline Markup /** * [Stream]<[Entity]> */ |
/** * {@link Stream<Entity>} */ | http://kotlinlang.org/docs/reference/kotlin-doc.html#inline-markup |
2 | println("sum of $a and $b is ${a + b}") | System.out.printf("sum of %d and %d is %d", a, b, a + b); | http://kotlinlang.org/docs/reference/basic-syntax.html#using-string-templates http://kotlinlang.org/docs/reference/basic-types.html#string-templates |
2 | fun max(a: Int, b: Int) = if (a > b) a else b | public static int max(final int a, final int b) { return a > b ? a : b; } | http://kotlinlang.org/docs/reference/control-flow.html#control-flow-if-when-for-while |
2 | Control Flow: if, when, for, while If Expression When Expression Before: fun whenFun1(a: Int) : EnumObjectKt { val value: EnumObjectKt when (a) { 1 -> value = EnumObjectKt.Value1 else -> value = EnumObjectKt.Value2 } return value } After: fun whenFun1(a: Int) = when (a) { 1 -> EnumObjectKt.Value1 else -> EnumObjectKt.Value2 } | public static EnumObject whenFun(final int a) { switch (a) { case 1: return EnumObject.Value1; default: return EnumObject.Value2; } } | http://kotlinlang.org/docs/reference/control-flow.html#control-flow-if-when-for-while http://kotlinlang.org/docs/reference/enum-classes.html#enum-classes |
2 | if (i in 1..10) {} | if (1 <= i && i <= 10) {} | http://kotlinlang.org/docs/reference/control-flow.html#control-flow-if-when-for-while |
2 | for (i in 1..10) … | for (int i = 1; I <= 10; i++) … | http://kotlinlang.org/docs/reference/control-flow.html#control-flow-if-when-for-while https://kotlinlang.org/docs/reference/ranges.html https://kotlinlang.org/docs/reference/control-flow.html#for-loops |
2 | for (item in collection) … | for (ItemType item : collection) … | http://kotlinlang.org/docs/reference/control-flow.html#control-flow-if-when-for-while https://kotlinlang.org/docs/reference/control-flow.html#for-loops |
2 | while (x > 0) … do { … } while (y != null) | while (x > 0) … do { … } while (y != null); | http://kotlinlang.org/docs/reference/control-flow.html#control-flow-if-when-for-while https://kotlinlang.org/docs/reference/control-flow.html#while-loops |
2 | Break and continue in loops | Break and continue in loops | https://kotlinlang.org/docs/reference/control-flow.html#break-and-continue-in-loops |
2 | enum class EnumObjectKt {Value1, Value2} | enum EnumObject {Value1, Value2} | http://kotlinlang.org/docs/reference/enum-classes.html#enum-classes |
2 | if (obj is String) { } if (obj !is String) { // same as !(obj is String) } | if (object instanceof String) { } | http://kotlinlang.org/docs/reference/typecasts.html |
2 | if (x is String) { print(x.length) // x is automatically cast to String } | http://kotlinlang.org/docs/reference/typecasts.html#smart-casts In many cases, one does not need to use explicit cast operators in Kotlin, because the compiler tracks the is-checks and explicit casts for immutable values and inserts (safe) casts automatically when needed: | |
2 | Local functions | https://kotlinlang.org/docs/reference/functions.html#local-functions | |
2 | Higher-Order Functions and Lambdas Higher-Order Functions it: implicit name of a single parameter Underscore for unused variables (since 1.1) Destructuring in Lambdas (since 1.1) Inline Functions Lambda Expressions and Anonymous Functions Function Types Lambda Expression Syntax Anonymous Functions Closures Function Literals with Receiver Note: Most of the items in the feature list should be used on 3 stage. | https://kotlinlang.org/docs/reference/lambdas.html | |
2 | Function Types () -> Unit | @FunctionalInterface public interface Run { void run(); } | https://kotlinlang.org/docs/reference/lambdas.html#function-types |
2 | "Unsafe" cast operator val x: String = y as String | http://kotlinlang.org/docs/reference/typecasts.html#unsafe-cast-operator | |
2 | Properties and Fields Declaring Properties Getters and Setters Backing Fields Backing Properties Compile-Time Constants Late-Initialized Properties Overriding Properties | ||
2 | Object expressions | Anonymous classes | https://kotlinlang.org/docs/reference/object-declarations.html#object-expressions |
2 | Object declarations | Singleton | https://kotlinlang.org/docs/reference/object-declarations.html#object-declarations |
2 | Companion Objects | Singleton | https://kotlinlang.org/docs/reference/object-declarations.html#companion-objects |
2 | Semantic difference between object expressions and declarations | ||
2 | Generics | ||
2 | Java 7's try with resources OutputStreamWriter(r.getOutputStream()).use { it.write('a') } | try (OutputStreamWriter writer = new OutputStreamWriter(…)) { writer.write(‘a’); } | https://kotlinlang.org/docs/reference/idioms.html#java-7s-try-with-resources https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/use.html |
2 | Exceptions Exception Classes Checked Exceptions The Nothing type | https://kotlinlang.org/docs/reference/exceptions.html | |
3 | Auto-generated properties into Single-Expression functions or functions Before: @get:annotation val client: ClientType After: @annotation fun getClient(): ClientType Before: override val client: ClientType @annotation get() = mApplicationContext.getBean(ClientType::class.java) After: @annotation override fun getClient() = mApplicationContext.getBean(DownloadFileWithHttpClientA::class.java) Usage: getCient() | Consider replacing auto-generated properties with Single-Expression functions (see. above) or functions (see. above). Note: Function declaration is more concise than property, but usage is vice-versa. Until auto-conversion is added to Refactor, do manually. 1. Refcator->Rename propertyName into getPropertyName 2. Migrate property syntax into function syntax. | |
3 | Auto-generated functions into Single-Expression functions override fun getClient(): ClientType { return Client() } override fun getClient() = Client() | Auto-conversion doesn’t create Single-Expression functions, even if it’s possible. | |
3 | Remove redundant code like <Type> and it -> in lambdas. | ||
3 | Nullable types and Non-Null Types var a: String = "abc" var a: String? = null | @NotNull String a = "abc"; @Nullable String a = null; | http://kotlinlang.org/docs/reference/null-safety.html#nullable-types-and-non-null-types |
3 | val l = if (b != null) b.length else -1 | int l = b != null ? b.length : -1; | http://kotlinlang.org/docs/reference/null-safety.html#checking-for-null-in-conditions |
3 | Safe Calls person?.department?.head?.name | http://kotlinlang.org/docs/reference/null-safety.html#safe-calls Such a chain returns null if any of the properties in it is null and name value if all properties are not null. | |
3 | safe call operator together with let person?.let { println(it)} // prints person info only if person != null | http://kotlinlang.org/docs/reference/null-safety.html#safe-calls To perform a certain operation only for non-null values, you can use the safe call operator together with let: | |
3 | val l = b?.length ?: -1 is equivalent of val l = if (b != null) b.length else -1 | http://kotlinlang.org/docs/reference/null-safety.html#elvis-operator | |
3 | val l = b!!.length | http://kotlinlang.org/docs/reference/null-safety.html#the--operator return a non-null value of b (e.g., a String in our example) or throw an NPE if b is null: | |
3 | val aInt: Int? = a as? Int | http://kotlinlang.org/docs/reference/null-safety.html#safe-casts safe cast that return null if the attempt was not successful http://kotlinlang.org/docs/reference/typecasts.html#safe-nullable-cast-operator | |
3 | val intList: List<Int> = nullableList.filterNotNull() | http://kotlinlang.org/docs/reference/null-safety.html#collections-of-nullable-type | |
3 | Destructuring Declarations val (name, age) = person for ((a, b) in collection) { ... } data class Result(val result: Int, val status: Status) fun function(...): Result { // computations
return Result(result, status) } // Now, to use this function: val (result, status) = function(...) for ((key, value) in map) { // do something with the key and the value } | http://kotlinlang.org/docs/reference/multi-declarations.html#destructuring-declarations | |
3 | Underscore for unused variable val (_, status) = getResult() | ||
3 | Destructuring in Lambdas map.mapValues { entry -> "${entry.value}!" } map.mapValues { (key, value) -> "$value!" } map.mapValues { (_, value: String) -> "$value!" } | http://kotlinlang.org/docs/reference/multi-declarations.html#destructuring-in-lambdas-since-11 | |
3 | After auto conversion Before: .flatMap<String> { it.myStream } After: .flatMap { it.myStream } | http://kotlinlang.org/docs/reference/lambdas.html | |
After auto conversion Before: .map { (_, _, arg) ->action(arg) } After: .map { action(it.arg) } | http://kotlinlang.org/docs/reference/lambdas.html | ||
3 | typealias NodeSet = Set<Network.Node> typealias MyHandler = (Int, String, Any) -> Unit class A { inner class Inner } class B { inner class Inner } typealias AInner = A.Inner typealias BInner = B.Inner | http://kotlinlang.org/docs/reference/type-aliases.html#type-aliases | |
3 | Sealed Classes | ||
3 | Infix notation | https://kotlinlang.org/docs/reference/functions.html#infix-notation | |
3 | Operator overloading | http://kotlinlang.org/docs/reference/operator-overloading.html | |
3 | Inline Functions | https://kotlinlang.org/docs/reference/functions.html#inline-functions | |
3 | Extensions Extension Functions Extensions are resolved statically Nullable Receiver Extension Properties Companion Object Extensions Scope of Extensions Declaring Extensions as Member Motivation | https://kotlinlang.org/docs/reference/extensions.html | |
3 | Calling multiple methods on an object instance ('with') Before: obj.objMethod1() obj.objMethod2() After: with (obj) { objMethod1() objMethod2() } | obj.objMethod1(); obj.objMethod2(); | https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/with.html |
3 | Builder-style usage of methods that return Unit Before: val obj = Obj() obj.objMethod1() obj.objMethod2() After: val obj = Obj().apply { objMethod1() objMethod2() } | https://kotlinlang.org/docs/reference/idioms.html#builder-style-usage-of-methods-that-return-unit https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/apply.html | |
3 | Before: fun save(aId: Long, …) { val entity = MyEntity().apply { id = aId … } try { mRepository.save (entity) } catch (e: Exception) { throw AppException.getExceptionToPropagate(e) } } After: fun save(aId: Long, …) { MyEntity().run { id = aId … try { mRepository.save (this) } catch (e: Exception) { throw AppException.getExceptionToPropagate(e) } } } | https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/apply.html https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/run.html | |
3 | Suppresses the given compilation warnings in the annotated element. @Suppress("unused") | @SuppressWarnings("unused") | https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-suppress/ Auto-conversion removes @SuppressWarnings("unused") instead of replacing @SuppressWarnings with @Suppress |
3 | Try is an expression Before: override fun getEntity(aId: Long): Optional<MyEntity> { try { return Optional.ofNullable(mRepository.findOne(aId)) } catch (e: Exception) { throw AppException.getExceptionToPropagate(e) } } After: override fun getEntity(aId: Long) = try { Optional.ofNullable(mRepository.findOne(aId)) } catch (e: Exception) { throw AppException.getExceptionToPropagate(e) } | https://kotlinlang.org/docs/reference/exceptions.html#try-is-an-expression | |
3 | Type-Safe Builders and DSL | https://kotlinlang.org/docs/reference/type-safe-builders.html | |
3 | Delegation Class Delegation Before: class (override val type: A.Type, @field:BehavioralPattern.Delegation.Delegate private val mAddress: AddressA) : A { override val name: String @BehavioralPattern.Delegation get() = mAddress.name override val port: Int @BehavioralPattern.Delegation get() = mAddress.port override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || javaClass != other.javaClass) return false val = other as return mAddress == .mAddress } override fun hashCode(): Int { return mAddress.hashCode() } } After: class (override val type: A.Type, @field:BehavioralPattern.Delegation.Delegate private val mAddress: AddressA) : A, AddressA by mAddress | ||
3 | Delegated Properties Standard Delegates Lazy Observable Storing Properties in a Map Local Delegated Properties Property Delegate Requirements Translation Rules Providing a delegate | http://kotlinlang.org/docs/reference/delegated-properties.html | |
3 | Coroutines | https://github.com/Kotlin/kotlinx.coroutines | |
3 | Reflection Function References | https://kotlinlang.org/docs/reference/reflection.html | |
Stage | Problem | Solution/Workaround |
1 | After auto conversion double literals like 0 into 0.toDouble() | Change to 0.0 |
2 | After auto conversion: Spring boot application can’t start - Configuration problem: @Configuration class 'Application' may not be final. Remove the final modifier to continue. Or Spring bean processor doesn’t process nested @Configuration class (f.e. located in @SpringBootTest class). | Note: plugin kotlin-maven-allopen is configured, but error still appear. add open class, open fun, open val to @Configuration class. Change Application.kt from … object Application { private val log = LoggerFactory.getLogger(Application::class.java) @JvmStatic fun main(args: Array<String>) { log.info("Started") val app = SpringApplication(Application::class.java) app.run(*args) } } to … open class Application private val log = LoggerFactory.getLogger(Application::class.java) fun main(args: Array<String>) { log.info("Started") val app = SpringApplication(Application::class.java) app.run(*args) } |
2 | Configuration problem: @Bean method 'getMyBean' must not be private or final; change the method's modifiers to continue | Change @Bean methods in @Configuration classes from internal fun getMyBean ( to open internal fun getMyBean ( |
2 | After auto conversion: private object QualifierName { private val VALUE = "VALUE" } … @Bean @Qualifier(QualifierName.VALUE) | Use Compile-Time Constants const val QualifierName_VALUE = "VALUE" … @Bean @Qualifier(QualifierName_VALUE) |
2 | @SuppressWarnings("unused") doesn’t suppress warning | Ignore warning |
2 | After auto conversion No qualifying bean of type 'Type' available: expected single matching bean but found 2: getMyBean, getMyBean$com_app Bean names that are generated by default in main and test class become different: main: getMyBean$com_app, test: getMyBean | Remove internal modifier to avoid getMyBean$com_app. |
2 | Note: Remove internal modifier everywhere to avoid different problems with names like getMyBean$com_app | |
2 | After auto conversion Incorrect expression Optional.ofNullable(getNullableValue()).map<Long>(Function<Type, Long> { it.getCountry() }).orElse(111L).toInt() | Change stream sequence from when Optional.ofNullable(getNullableValue()).map<Long>(Function<Type, Long> { it.getCountry() }).orElse(111L).toInt() to (with Optional) Optional.ofNullable(getNullableValue()).map{it.country}.orElse(111L)?.toInt() or to (Kotlin null-safety instead of Optional) getNullableValue()?.country ?: 111L |
2 | After auto conversion Incorrect lambda expressions like: .map<Stream<Entity>>(Function<Entity, Stream<Entity>> { Stream.of(it) }) | .map { Stream.of(it) } |
2 | After auto conversion Warning on {@link getProperty} | Change [getProperty] to [property] |
2 | After auto conversion Type getABName(); became val abName: Type and is accessible from Java as getAbName instead of getABName | Migrate code from getABName to getAbName. |
2 | Note: Avoid identifiers that don’t follow Java default naming convention. | |