Привет, студент JavaRush, пока тебя целиком и полностью не поглотила Java, я хотел бы расширить твой кругозор и обратить внимание на набирающий популярность язык Kotlin!
Kotlin — достаточно молодой язык, разработанный компанией JetBrains. Да-да, именно той самой компанией, которая разработала нашу любимую IDE: IntelliJ IDEA. Kotlin является JVM языком и полностью совместим с Java, то есть из Kotlin-кода можно без проблем обращаться к привычным Java-библиотекам, Да что там к библиотекам: Kotlin и Java классы могут уживаться в одном package!
Kotlin настолько пришелся по душе сообществу программистов, что Google признал его официальным языком разработки под Android, а в последнее время Kotlin начал набирать популярность и в энтерпрайз-проектах.
В данной статье я хотел бы привести несколько сравнительных примеров кода, написанного на Kotlin и на Java, и сделать некоторые выводы. Поехали!
Начнем по традиции с "Hello World"

// Java
public class Application {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
// Kotlin
class Application
fun main(vararg args: String) {
println("Hello World!")
}
Глядя на пример Kotlin, можно сразу отметить следующее:
- не нужно писать точку с запятой в конце строки;
- все методы описываются ключевым словом fun;
- чтобы вывести строку достаточно всего одного слова — println()!
// Java (до 10)
final Application application = new Application();
// Kotlin
val application = Application()
Отличия Kotlin:
- не требуется объявлять тип переменной, если он понятен по экземпляру;
- вместо типа переменной — val (неизменяемая) или var (изменяемая);
- для создания экземпляра не нужно писать ключевое слово new!
// Java
public int sum(int a, int b) {
return (a + b);
}
// Kotlin
fun sum(a: Int, b: Int): Int {
return (a + b)
}
Отличия Kotlin:
- если из метода нужно что-то вернуть, в сигнатуру добавляется ": Int", где Int — возвращаемый тип;
- описание параметров метода: сначала имя переменной, затем тип;
- так как тело метода состоит всего из одной строки, можно опустить return:
fun sum(a: Int, b: Int): Int = (a+b)
// Java
public int sum(int a, int b) {
int result = (a + b);
System.out.printf("Сумма %d и %d равна %d\n", a, b, result);
return result;
}
// Kotlin
fun sum(a: Int, b: Int): Int {
val result = (a + b)
println("Сумма $a и $b равна $result")
return result
}
Kotlin поддерживает интерполяцию строк, достаточно использовать символ "$" вначале переменной. Такая запись значительно повышает чистоту и читабельность кода.
Сравнение экземпляров
// Java
object1.equals(object2)
// Kotlin
object1 == object2
В Kotlin сравнение "==
" для объектных типов транслируется в equals
! А для сравнения ссылок используется "===
".
Исключения
// Java
public List<String> getFileContent(String file) throws IOException {
Path path = Paths.get(file);
return Files.readAllLines(path);
}
// Kotlin
fun getFileContent(file: String): List<String> {
val path = Paths.get(file)
return Files.readAllLines(path)
}
В Kotlin нет checked-исключений, теперь не нужно бесконечно прокидывать исключение через всё приложение или городить многоуровневые try-catch
.
Null Safety
// Java
public class Data {
String value;
String render() {
if (value == null) {
return "Value: undefined";
} else {
return "Value:" + value.toUpperCase();
}
}
}
// Kotlin
class Data {
var value: String? = null
fun render(): String =
"Value: ${value?.toUpperCase() ?: "undefined"}"
}
В Kotlin озаботились проблемой NPE и ввели ряд требований:
- все поля класса и переменные обязательно должны быть проинициализированы;
- в поле или переменную можно записать "null", но тогда ты обязан явно сказать, что твоя переменная Nullable (написать знак "?");
- элвис-оператор "?:" работает следующим образом: если слева Null, возьми то, что указано справа. В случае с нашим примером, когда переменная value не проинициализирована, возьмется значение "undefined".
// Java
public class Data {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
class App {
void execute() {
Data data = new Data()
data.setValue("Foo")
}
}
// Kotlin
class Data {
var value: String = ""
}
class App {
fun execute() {
val data = Data()
data.value = "Foo" // Под капотом выполнится data.set("Foo")
}
}
В Kotlin достаточно просто описать поле и всё: у него уже есть неявные геттеры и сеттеры (привет lombok), которые при желании в любой момент можно переопределить. При этом читаем и модифицируем значение поля просто обращаясь непосредственно к нему, а под капотом вызывается get()|set()
.
Циклы
// Java
void example() {
for(int i = 1; i <= 10; i++) {
System.out.println(i);
}
for(String line : "a,b,c".split(",")) {
System.out.println(line);
}
}
// Kotlin
fun example() {
for(i in 1..10) {
println(i)
}
for(line in "a,b,c".split(",")) {
println(line)
}
}
Kotlin предоставил удобный и единообразный синтаксис обхода последовательностей: ты просто используешь слева переменную, справа последовательность, а между ними — ключевое слово "in", тип определяется автоматически по содержимому.
Синглтон
// Java
public class Singleton {
private static Singleton ourInstance = new Singleton();
public static Singleton getInstance() {
return ourInstance;
}
private Singleton() {
}
}
class App {
void execute() {
Singleton singleton = Singleton.getInstance()
}
}
// Kotlin
object Singleton {}
class App {
fun execute() {
val singleton = Singleton
}
}
Знакомый всем паттерн "одиночка" достаточно часто используется на практике, поэтому в Kotlin решили создать отдельное ключевое слово "object", которое пишется вместо "class" и означает, что класс является синглтоном, при использовании даже не нужно звать конструктор или какие-либо другие методы!
Именованные параметры методов и дефолтные значения
// Java
void setStatus(String code) {
setStatus(code, "");
}
void setStatus(String code, String desc) {
this.code = code;
this.desc = desc;
}
// Kotlin
fun setStatus(code: String, desc: String = "") {
this.code = code;
this.desc = desc;
}
fun execute() {
setStatus("200")
setStatus(code = "200", desc = "Ok")
}
Случается такое, что не все параметры в методе или конструкторе должны быть обязательными, и в Java мы привыкли создавать набор методов или конструкторов под всевозможную комбинацию параметров. В Kotlin ввели дефолтные параметры, что позволяет объявить 1 метод и передавать в него необходимый набор параметров по ситуации.
Стримы
// Java
String getFirst(List<String> strings, String alpha) {
return strings.stream()
.filter(x -> x.startsWith(alpha))
.findFirst()
.orElse("");
}
// Kotlin
fun getFirst(strings: List<String>, alpha: String): String {
return strings.first { it.startsWith(alpha) }
}
Появившиеся stream в Java 8 стали неотъемлемым функционалом при работе с коллекциями. В Kotlin стримы сделали еще более удобными и функциональными: у каждой коллекции уже есть набор удобных частоиспользуемых методов для работы с данными. Кроме того, обрати внимание на лямбда выражение внутри метода first: если функциональный литерал имеет ровно один параметр, его объявление можно удалить (вместе с ->), и обращаться к нему по имени it.
Пора бы закругляться...
Я продемонстрировал лишь малую, базовую часть функционала, но, я уверен, тебе уже захотелось попробовать Kotlin!
По своему опыту я могу сделать следующие выводы:
- Java разработчику очень легко освоить синтаксис Kotlin и начать писать код;
- у Kotlin полная совместимость с Java, и его уже можно пробовать в своих действующих проектах, например, в тестах;
- код на Kotlin чище и читабельнее, не нужно писать кучу бойлерплэйта;
- в IDEA есть автоматический конвертер Java в Kotlin, вы можете брать готовый Java-код и автоматически конвертировать его в Kotlin;
- новый проект нужно писать на Kotlin, так как с инфраструктурной точки зрения — это та же Java, а по использованию — лучше и удобнее!
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ