From Java to Kotlin — Basic Syntax Reference
Hello, my name is David, and this is the second installment in my small series on learning a new programming language based on a language you already know. Last week, I covered learning Python for those familiar with Java. Today, I’ll be helping people with a Java background who’ve decided to take on Kotlin.
Core Concepts
The core concepts I’ll be covering concerning the two languages, similar to my previous article, include:
- Major Differences
- Data Types
- Comments
- Variable Declaration and Initialization
- Type Conversion
- Operators and Operations
- Control Flow
- Functions
- Standard I/O
- Arrays
Cheat Sheet
I’ve created a single page cheat sheet to act as a quick reference for this whole article. You can find it here.
Let’s get started.
Major Differences
Before I start, please take note: Kotlin was designed to be compatible with Java, down to the bytecode level, and because of this, the two are very, very, similar. Kotlin, however, was designed to address the design flaws of Java and add more modern language features, so learning Kotlin will be less about what you can do just like you could do in Java but instead about what you can do better than you did in Java. With that in mind, let’s get to the differences:
- Kotlin uses type inference. This means that you don’t have to declare the types of your variables, but you still can if you want, and you will sometimes need to.
- Kotlin supports top-level functions and variables. Unlike Java, everything doesn’t have to be contained in a class.
- The root class of the Kotlin hierarchy is the
Any
class, just like theObject
class for Java. It also features anequals()
, atoString()
, andhashCode()
method. It contains additional methods and properties and well, which are not relevant to this discussion. - One of the most notable features of Kotlin, when compared with Java, is null-safety: all variables must be declared nullable before they can be assigned the value
null
. Failure to do so will result in a compile-time exception instead of a runtime exception. More on this later. static
members aren’t present in Kotlin, rather, there are alternatives including top-level functions,companion objects
and others.- Semicolons are optional.
More on the differences here.
Data Types
Java features primitive types like int
, long
, and double
that are not classes, but have corresponding wrapper classes like Integer
, Long
, and Double
respectively. Kotlin only has primitives that are classes, and they include Byte
, Short
, Int
, Long
, Float
, Double
, Char
, and Boolean
. They all correspond to their respective types in Java. The String
class has the same name for both languages.
Comments
In addition to the types of comments Java supports, Kotlin also supports nested multiline comments:
/*New nested comment that won't be terminated by the old comment
/*Original comment for this code*/
fun display() {
println("Kotlin")
}
*/
Variable Declaration and Initialization
Java
import java.util.Scanner;class Program {
public static final int COUNT = 10; // 2
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String firstName; // 1, 3
String lastName = null; // 4
System.out.print("First Name: ");
firstName = scanner.nextLine();
System.out.print("Input Last Name(y/n)?: ");
final String lastNameInput = scanner.nextLine(); // 1
if(lastNameInput.equals("y")) {
System.out.print("Last Name: ");
lastName = scanner.nextLine();
}
final String username =
firstName + (lastName == null? "":lastName);
System.out.println("Username is: " + username);
scanner.close();
}
}
Kotlin
const val COUNT = 10 // 2
class Program {
fun main() {
var firstName : String // 1, 3
var lastName : String? = null // 4
print("First Name: ")
firstName = readLine()
print("Input Last Name(y/n)?: ")
val lastNameInput = readLine()!! // 1, 3, 5
if(lastNameInput.equals("y")) {
print("Last Name: ")
lastName = readLine()
}
val username = firstName + (lastName?: "") // 6
println("Username is $username")
}
}
- Variables are declared with the Kotlin keyword
var
. Constants are declared with the keywordval
, similar to thefinal
keyword in Java. - Constants whose value must be known at compile-time i.e. compile-time constants can have the
const
modifier added to their declaration, similar tostatic final
constants in Java. - Since Kotlin uses type inference, it’s optional to declare the type of a variable if it’s initialized at the time it is declared. Its type, must, however, be specified if the declaration and initialization are separate.
- A little talk on null-safety: objects that can be
null
must be declared nullable by giving them a nullable type. This is done by suffixing the type with a?
. In this example, the nullable stringlastName
must be given the typeString?
, or the code won’t compile. - Objects with a nullable type can be converted to their non-nullable counterpart types in a few ways. One of those ways include suffixing the variable with a
!!
. This is done on thereadLine()
function which returns a to convert theString?
type object it returns to aString
. Note that if the nullable value was trulynull
when you used this operator, it will result in aKotlinNullPointerException
, which basically defeats the purpose of null safety, so take care to use this operator only when you’re sure the variable will not benull
. - Another way to convert a nullable type object to a non-null type object is by giving the variable a default non-null value using the Elvis operator. It’s similar to the ternary operator in Java, but it’s only used for nullable types.
- The
new
keyword doesn’t exist in Kotlin. Objects are constructed without it.
//Java
Program p = new Program();
//Kotlin
val p = Program();
Type Conversion
- The normal rules of implicit type conversion hold.
- For explicit type conversion, the primitive number types include the following methods:
toByte()
,toShort()
,toInt()
,toLong()
,toFloat()
,toDouble()
,toChar()
. - Strings also have conversion functions of the form
toX()
whereX
is the type to be converted to andtoXOrNull()
which returnsX
as a null type when the conversion fails. - For objects, type casts are done using the
as
(“unsafe”) andas?
(“safe” cast) operators. The difference between these two is that the safe cast operator will not throw an exception if the object being cast was truly null:
var y : String? = "Not Null"
var x : String = y as String
y = null
// var z : String? = y as String ERROR
var z : String? = y as? String // Safe
var a : String? = y as String? // Alternative way
Operators and Operations
- The
&&
,||
, and!
operators are the same in Java and Kotlin. - The bitwise operators have no special characters but all map to named functions. From Java to Kotlin:
&
maps toand
,|
maps toor
,^
maps toxor
,>>
maps toshr
(shift right),<<
maps toshl
(shift left),>>>
maps toushr
, and~
maps toinv
. Examples:
5 and 6 // 4
4.inv() // -5
- All arithmetic unary operators, binary operators, comparison operators, assignment(e.g
i++
) operators and equality operators are the same in both languages. They all have named function counterparts. instanceof
in Java corresponds tois
in Kotlin.- In addition, Kotlin also has the range (
a..b
,a
andb
inclusive) and membership (in
) operators. +
is still used for String concatenation, but you can also use$
with curly braces for String templates:
var num = 3
var str = "This is number $num" // No braces required for a single variable
var strCurly = "This is num plus 3: ${num+3}" // Use curly braces when the expression is more complex
Control Flow
while
anddo-while
loops are the same in both languages.break
andcontinue
are the same in both languages.switch-case
is replaced by the more powerfulwhen
statement.- All forms of the
if
statement are treated as expressions that have values rather than normal statements which have no values:
val num : Int = if(x < y) {
3
} else {
6
}
if
statements used this way must have anelse
block.- Note that this is the alternative for the Java ternary operator (
?:
). More than one statement can be in theif
expression, but the last statement has to have the value being assigned.
val num : Int = if(x < y) {
println("Y is Greater")
3
} else if (x > y) {
println("X is Greater")
6
} else {
println("X and Y are equal")
9
}
- In general in Kotlin, when a set of statements is used as an expression, the last line(s) must hold the value of the expression.
- The
when
statement in Kotlin works likeswitch
in Java, but with some more features: when
can be used to check object identity with theis
operator:
val x = "String"
when(x) {
is Int -> {
println("x is numeric")
}
is String -> {
println("x is a String")
}
else -> {
println("x is an object")
}
}
when
can also be used to test for membership of a sequence using thein
or!in
operator:
nums = arrayOf(1, 2, 3, 4, 5)
x = 6
when(x) {
in nums -> {
println("X is small")
}
in 11..15 -> {
println("X is large")
}
else -> {
println("X is moderate")
}
}
when
statements can be used as expressions, but you have to include theelse
branch, just like theif
statement.for-each
loops are the only kind offor
loop in Kotlin. There’s no standard “counter” loop, but you can use ranges for counter behavior:
for (i in 0..10) // 0 inclusive to 10 inclusive
...
for (i in 0 until 10) // 0 to 9 i.e. 0 inclusive to 10 exclusive
...
for (s : String in words)
...
for (i in nums.indices)
Functions
Java
class Program {
...
public static void main(String[] args) {...} // 1, 4
...
private static int sum(int a, int b) {...} // 1, 2, 3
...
public float average(int... nums) {...} // 5
...
private String name; // 7
public void setName(String name) {...} // 7
public String getName() {...} // 7
...
public void printWord() { printWord("apple") } // 4, 6
public void printWord(String word) {...} // 4, 6
}
Kotlin
fun main() {...} // 1, 4
class Program {
...
companion object { // 1
fun sum(a : Int, b: Int) : Int {...} // 2, 3
}
...
fun average(vararg nums : Int) : Float {...} // 5
...
var name // 7
public get() {...} // 7
public set(value) {...} // 7
...
fun printWord(word : String = "apple") : Unit {...} // 4, 6
- As stated earlier, Kotlin supports top-level functions.
main
itself is a top-level function in Kotlin. This eliminates the need for thestatic
modifier from Java, but a way to achieve this kind of behaviour is throughcompanion object
s. Every class can have at most onecompanion object
. - Functions are declared with the
fun
keyword followed by the function name and parameter list. The return type comes after the parameter list and is preceded by a colon. - Function parameters are of the form
<name> : <type>
, similar to Kotlin variables. - The return type
void
in Java is the same asUnit
in Kotlin. It’s optional to specify this return type in Kotlin, however. - Variable-length arguments are declared with the
vararg
keyword in Kotlin instead of the...
operator from Java. - Kotlin supports default values for function parameters, therefore there’s no need for function overloading.
- Data members, or, fields of Kotlin classes are treated as properties. Properties discourage the use of “getter and setter” methods, and are instead declared
public
with a customget
andset
function. Theget
andset
functions are optional for each field, and must be declared immediately after their field if they are declared. - You can also used named parameters in Kotlin to specify parameter values in any order:
val summation = Program.sum(b = 3, a = 2)
Standard I/O
Java
import java.util.Scanner; // 1
...
Scanner scanner = new Scanner(System.in); // 1
System.out.print("Same Line") // 2
System.out.println("New Line") // 2
String s = scanner.nextLine(); // 3
Kotlin
print("Same Line") // 2
println("New Line") // 2
var s = readLine()!! // 3
- Java treats it’s most basic input and output like streams:
System.out
is aPrintStream
andSystem.in
is anInputStream
. Kotlin’s basic input and output functions, however, don’t work with streams and are therefore less verbose. - The
print()
andprintln()
functions are the same in both languages. The main difference in syntax being theSystem.out
object from Java preceding the method names. - Kotlin’s
readLine()
function is the main way to collect input line by line. There are no functions to read forInt
orBoolean
objects like Java’sScanner
class has.
Arrays
Java
int[] nums = new int[32]; // 1
for(int i = 0; i < 32; i++) {nums[i] = i * 2;} // 2
for(int i = 0; i < nums.length; i++) { // 4
System.out.println("I: " + nums[i]);
}
for(int i : nums) {System.out.println(i);}
Kotlin
var nums = Array<Int>(32) { i -> i * 2 } // 1, 3
for(i in nums.indices) { println("I: ${nums[i]}") } // 2, 5
for(i in 0 until nums.size) { println("I: ${nums.get(i)}") } // 4
- Kotlin’s arrays are also objects and are of type
Array
. This means you declare and initialize them like regular Kotlin objects. - The standard
[]
index operator is overloaded with the methodsget
andset
in Kotlin. You can use arrays either way. - Kotlin
Array
s can take a lambda function in their constructor to initialize each member based on theInt
parameter. - You use
size
in Kotlin instead oflength
to find out the number of elements in anArray
. - You can iterate through the indices of an
Array
using theindices
property to achieve the behavior of a counter loop.
Conclusion
Learning the similarities in syntax is only the start to learning a brand new language. I hope I’ve been able to help you get a firm grip on the basics as you move on to the advanced concepts in Kotlin, including coroutines, data classes, sealed classes, and much more. Thank you for your time.
Further Reading
- Kotlin features vs. Java features: https://kotlinlang.org/docs/reference/comparison-to-java.html
- Scope Functions: https://kotlinlang.org/docs/reference/scope-functions.html
- Coroutines: https://kotlinlang.org/docs/reference/coroutines-overview.html
- Data Classes : https://kotlinlang.org/docs/reference/data-classes.html
- Android with Kotlin: https://developer.android.com/kotlin, https://kotlinlang.org/docs/reference/android-overview.html