Я хочу рассказать вам о языке программирования Kotlin и о том, почему вы должны рассмотреть его для своего следующего проекта. Раньше я предпочитал Java, но за прошедший год обнаружил, что кодирую на Kotlin при любой возможности, и сейчас я действительно не могу придумать ситуацию, в которой Java был бы лучшим выбором.

Он разработан компанией JetBrains, и тот факт, что именно эти люди стоят в создании такого набора IDE, как IntelliJ и ReSharper, в полной мере отражается и в Kotlin. Он прагматичен и лаконичен, делает кодирование приятным и эффективным занятием.

Хотя Kotlin компилируется как в JavaScript, а скоро и в машинный код, я сосредоточусь на его основной среде - JVM.

Итак, вот несколько причин, по которым вы должны полностью перейти на Kotlin (нумерация случайна, без определенного порядка):

0# Взаимодействие с Java

Kotlin на 100% совместим с Java. Вы можете в буквальном смысле продолжать работать над своими старыми Java-проектами, используя Kotlin. Все ваши любимые Java-фреймворки по-прежнему доступны, и любой фреймворк, который вы напишете на Kotlin, будет легко принят вашим упертым другом, любящим Java.

1# Знакомый синтаксис

Kotlin - это не какой-то необычный язык, рожденный в академических кругах. Его синтаксис знаком любому программисту, пришедшему из области ООП, и может быть более или менее понятен с самого начала. Конечно, есть некоторые отличия от Java, например, переработанные конструкторы или объявления переменных val var. В приведенном ниже сниппете представлена большая часть базового синтаксиса:

class Foo {

    val b: String = "b"     // val means unmodifiable
    var i: Int = 0          // var means modifiable

    fun hello() {
        val str = "Hello"
        print("$str World")
    }

    fun sum(x: Int, y: Int): Int {
        return x + y
    }

    fun maxOf(a: Float, b: Float) = if (a > b) a else b

}

2# Интерполяция строк

Это как если бы в язык была встроена более умная и читабельная версия функции String.format() из Java:

val x = 4
val y = 7
print("sum of $x and $y is ${x + y}")  // sum of 4 and 7 is 11

3# Вывод типов

Kotlin будет выводить ваши типы, если вы посчитаете, что это улучшит читабельность:

val a = "abc"                         // type inferred to String
val b = 4                             // type inferred to Int

val c: Double = 0.7                   // type declared explicitly
val d: List<String> = ArrayList()     // type declared explicitly

4# "Умные" преобразования. (Smart Casts)

Компилятор Kotlin отслеживает вашу логику и по возможности автоматически выполняет приведение типов, что означает избавление от проверок instanceof и явных преобразований:

if (obj is String) {
    print(obj.toUpperCase())     // obj is now known to be a String
}

5# Интуитивные равенства

Вы можете перестать явно вызывать equals(), потому что оператор == теперь проверяет структурное равенство:

val john1 = Person("John")
val john2 = Person("John")
john1 == john2    // true  (structural equality)
john1 === john2   // false (referential equality)

6# Аргументы по умолчанию

Нет необходимости определять несколько одинаковых методов с разными аргументами:

fun build(title: String, width: Int = 800, height: Int = 600) {
    Frame(title, width, height)
}

7# Именованные аргументы

В сочетании с аргументами по умолчанию именованные аргументы избавляют от необходимости использовать строителей (builders):

build("PacMan", 400, 300)                           // equivalent
build(title = "PacMan", width = 400, height = 300)  // equivalent
build(width = 400, height = 300, title = "PacMan")  // equivalent

8# Выражение When

В качестве замены оператору switch используется гораздо более удобное и гибкое выражение when:

when (x) {
    1 -> print("x is 1")
    2 -> print("x is 2")
    3, 4 -> print("x is 3 or 4")
    in 5..10 -> print("x is 5, 6, 7, 8, 9, or 10")
    else -> print("x is out of range")
}

Оно работает как выражение, и как оператор, с аргументом, и без него:

val res: Boolean = when {
    obj == null -> false
    obj is String -> true
    else -> throw IllegalStateException()
}

9# Свойства

К публичным полям может быть добавлено кастомное поведение set и get, что позволит нам остановить загромождение кода бессмысленными геттерами и сеттерами.

class Frame {
    var width: Int = 800
    var height: Int = 600

    val pixels: Int
        get() = width * height
}

10# Класс данных (Data Class)

Это POJO (Plain Old Java Object) с функциями toString(), equals(), hashCode() и copy(), и в отличие от Java он не занимает почти 100 строк кода:

data class Person(val name: String,
                  var email: String,
                  var age: Int)

val john = Person("John", "john@gmail.com", 112)

11# Перегрузка оператора

Предопределенный набор операторов может быть перегружен для улучшения читабельности:

data class Vec(val x: Float, val y: Float) {
    operator fun plus(v: Vec) = Vec(x + v.x, y + v.y)
}

val v = Vec(2f, 3f) + Vec(4f, 1f)

12# Объявления деструктуризации

Некоторые объекты могут быть деструктурированы, что, например, полезно для итерации карт:

for ((key, value) in map) {
    print("Key: $key")
    print("Value: $value")
}

13# Диапазоны

Для улучшения читабельности:

for (i in 1..100) { ... } 
for (i in 0 until 100) { ... }
for (i in 2..10 step 2) { ... } 
for (i in 10 downTo 1) { ... } 
if (x in 1..10) { ... }

14# Функции расширения

Помните, когда вам впервые понадобилось отсортировать List в Java? Вы не могли найти функцию sort() и вам в результате пришлось узнать о Collections.sort(). А позже, когда вам нужно было написать String с заглавной буквы, то это привело к написанию собственной вспомогательной функции, потому что вы не знали о StringUtils.capitalize().

Если бы только существовал способ добавить новые функции в старые классы; тогда ваша IDE смогла бы помочь вам найти нужную функцию при автоматическом дополнении кода. В Kotlin вы можете сделать именно это:

fun String.replaceSpaces(): String {
    return this.replace(' ', '_')
}

val formatted = str.replaceSpaces()

Стандартная библиотека расширяет функциональность оригинальных типов Java, что особенно требовалось для String:

str.removeSuffix(".txt")
str.capitalize()
str.substringAfterLast("/")
str.replaceAfter(":", "classified")

15# Null безопасность

Java - это то, что мы должны назвать почти статически типизированным языком. В нем переменная типа String не гарантированно ссылается на String - она может ссылаться на null. Несмотря на то, что мы привыкли к этому, это сводит на нет безопасность статической проверки типов, и в результате разработчикам Java приходится жить в постоянном страхе перед ошибкой NPE (NullPointerException).

Kotlin решает эту проблему, проводя различие между ненулевыми (non-null) и  обнуляемыми (nullable) типами. Типы по умолчанию являются non-null, и их можно сделать nullable, добавив ? как, например:

var a: String = "abc"
a = null                // compile error

var b: String? = "xyz"
b = null                // no problem

Kotlin заставляет вас защищаться от NPE всякий раз, когда вы обращаетесь к nullable-типу:

val x = b.length        // compile error: b might be null

И хотя это может показаться громоздким, на самом деле все просто благодаря нескольким особенностям Kotlin. У нас все еще есть умное приведение, которое преобразует nullable типы в non-null везде, где это возможно:

if (b == null) return
val x = b.length        // no problem

Мы также можем использовать безопасный вызов ?., который производит проверку на нулевое значение вместо того, чтобы выбрасывать NPE:

val x = b?.length       // type of x is nullable Int

Безопасные вызовы можно объединять в цепочки, чтобы избежать вложенных проверок if-not-null (если-не-ноль), которые мы иногда пишем в других языках, и если нам нужно значение по умолчанию, отличное от null, то используем elvis-оператор ?::

val name = ship?.captain?.name ?: "unknown"

Если ничего из этого вам не подходит, и необходимость в NPE крайне велика, то скажите об этом явно:

val x = b?.length ?: throw NullPointerException()  // same as below
val x = b!!.length                                 // same as above

16# Улучшенные лямбды

Это хорошая система лямбд - она идеально сбалансирована между читабельностью и сложностью, благодаря продуманному дизайну, с простым синтаксисом:

val sum = { x: Int, y: Int -> x + y }   // type: (Int, Int) -> Int
val res = sum(4,7)                      // res == 11

А вот и толковые решения:

  1. Скобки метода могут быть перемещены или опущены, если лямбда идет последней либо является единственным аргументом метода.

  2. Если мы решили не объявлять аргумент одноаргументной лямбды, он будет неявно объявлен под именем it.

Эти факты в совокупности делают следующие три строки эквивалентными:

numbers.filter({ x -> x.isPrime() })
numbers.filter { x -> x.isPrime() }
numbers.filter { it.isPrime() }

И это позволяет нам писать лаконичный функциональный код - только посмотрите на эту красоту:

persons
    .filter { it.age >= 18 }
    .sortedBy { it.name }
    .map { it.email }
    .forEach { print(it) }

Система лямбд Kotlin в сочетании с функциями расширения делает его идеальным для создания DSL. Взгляните на Anko в качестве примера DSL, который призван улучшить разработку Android:

verticalLayout {
    padding = dip(30)
    editText {
        hint = “Name”
        textSize = 24f
    }
    editText {
        hint = “Password”
        textSize = 24f
    }
    button(“Login”) {
        textSize = 26f
    }
}

17# Поддержка IDE

У вас есть несколько вариантов, если вы собираетесь начать работу с Kotlin, но я настоятельно рекомендую использовать IntelliJ, который поставляется в комплекте с Kotlin - его возможности продемонстрируют все преимущество того, что и язык, и IDE разрабатываются одними и теми же людьми.

В качестве небольшого, но показательного примера, вот что всплыло, когда я впервые попытался скопипастить Java-код со Stack Overflow:

IntelliJ заметит, если вы вставите Java-код в файл Kotlin


Завтра состоится открытое занятие «Основы классов и объектов», на котором мы посмотрим на принципы проектирования классов и их реализации в Kotlin. Поймем, как объектно-ориентированное программирование работает изнутри, создадим свои структуры и посмотрим на возможности языка Kotlin. Спроектируем объектную модель данных. Регистрируйтесь по ссылке.

Комментарии (55)


  1. harios
    21.09.2022 13:54
    +10

    Аж 18 плюсов и ни одного минуса? Прям пахнет "объективностью".


    1. SuperTEHb
      21.09.2022 14:15
      +5

      Под такое описание подходит С++, взятый 9 раз. И даже "объективностью" тоже попахивает (от слова "объект").


    1. izogfif
      21.09.2022 15:29
      +1

      Держите один: тернарного оператора (это который ?:) в Котлине нет. Вместо `a = (b == c) ? d: e` нужно писать `a = if (b == c) d else e` (точки с запятыми и фигурные скобки расставить по вкусу).


      1. LordDarklight
        21.09.2022 16:03
        +8

        Совсем некритичный недостаток - тут просто все современные языки делятся на два класса:

        1. Инструкции = выражения - корни растут из функциональной парадигмы

        2. Инструкции ≠ выражения - корни растут из императивной парадигмы

        Ну и бывают гибриды, переходящие от группы 2. к группе 1.

        Тернарный оператор обычно реализован во второй группе языков и редко в первой.

        Kotlin в большей степени относится ко первой группе ЯП

        И отсутствие тернарного оператора не так уж удлиняет код и не лишает его читаемости - зато ключевое слово when очень хорошо заменяет многоуровневый тернарный оператор

        Тут всё лишь дело в привычке - но да - к тернарному оператору в императивных языках привыкли многие - и его, конечно, можно было бы добавить для упрощения перехода с других императивных языков - но это совсем не обязательно - и мне кажется, к концу века тернарный оператор вовсе отомрёт (в том виде, как мы его знаем)


        1. LordDarklight
          22.09.2022 17:16

          Добавка.

          Первый раз тернарный оператор проявился в императивном языке программирования Алгол-60 (1960) и это как раз было выражение вида "res := if o1 then o2 else o3". Но в таком виде в императивных языках он далее почти не фигурировал. Может быть вплоть до императивно-функционального ЯП Scala (2004).

          Что-то подобное именно оператору появилось чуть позже в языке BCPL (1967):  res := (o1 -> o2, o3)

          Ну а самый распространённый синтаксис тернарного оператора появился уже только начиная с языка Си (1972): res := o1 ? o2 : o3

          Но, замечу, что в самом популярном (в 2022 году) языке Python тернарный "оператор" (выражение) только такой: res := if o1 then o2 else o3

          А в Swift, Java, JavaScript применяется Си-подобный тернарный оператор


          1. sshikov
            22.09.2022 19:31

            del


          1. AnthonyMikh
            22.09.2022 19:39
            +3

            Но, замечу, что в самом популярном (в 2022 году) языке Python тернарный "оператор" (выражение) только такой: <...>

            Ну нет же


            res = o2 if o1 else o3


            1. LordDarklight
              23.09.2022 11:18

              Век живи, век учись - спасибо что поправили

              Вот вам - ещё один вариант синтаксиса - уже формально четвёртый в императивных языках - а ведь ещё что-то такое бывает  res = if(o1, o2, o3) - привет от Visual basic .NET - а ещё такое бывает (оооочень редко) res = ?(o1, o2, o3)

              Ну и разные вариации в функциональных ЯП.


              1. LordDarklight
                23.09.2022 14:26
                -1

                Добавка.

                В Kortlin запись "a = if (b == c) d else e" можно интерпретировать так

                1. Сначала срабатывает инфиксная функция else (более приоритетная чем if; захватывает левое и правое выражении) - которая получает на вход два лямбда-выражения - и объединяет их в новое лямбда-выражение - что-то типа { -> Pair<()->Unit,()->Unit>(d, e) } (вернее тут будет, конечно обобщённый тип результата) - т.к. фактически пакует два выражения в кортеж, который затем пакуется в анонимную функцию с замыканием аргументов исходных выражений.

                2. А затем уже применяется функция if с двумя входными параметрами - один булевый, второй (правый) принимающий на вход лямбда-выражение с типом результата функции else (этот тип - лямбда-функция)

                3. Так как это лямбда-функция на конце - то этот аргумент может быть пропущен при вызове, с захватом следующего (справа) блока кода - являющегося результатом функции else (тут я немного луквалю - т.к. у Kotlin тут есть нюансы реализации логики, ограничивающие прямую реализацию такого подхода на языке Kotlin - но компилятор может сделать для себя исключение)

                4. Ну а далее внутри функции if проверяется условие и в зависимости от его результата распаковывается и вызывается то или иное выражение и возвращается его результат.

                Далее привожу примерный код с некоторыми уточнениями и допущениями:

                1. Упаковка в кортеж Pair<()->T,()->T>)(f1,f2) осуществляется встроенной в Kotlin инфиксной функцией f1 to f2 (в коде ниже будет написано "this to f2")

                2. if и else заменены на If и Else соответственно, т.к. являются ключевым словом (компилятор же ключевые слова может обрабатывать как ему будет угодно, но пользовательском коде ключевые слова как идентификаторы запрещены)

                3. Kotlin не подхватывает результат функции Else как лямбда-функцию, которую можно было бы захватить справа - поэтому закомментированная строка не компилируется (но внутри компилятора это может быть реализовано в виде исключения - каких-то логических препятствий для этого нет - всё корректно определено)

                4. Поэтому передаю этот аргумент явно значением второго параметра функции If

                5. По ряду синтаксических нелогичных ограничений языка Kotlin пришлось ввести вспомогательный обобщённый псевдоним типа "Fn = ()->T" (и позже это всё-таки ещё "встанет колом")

                  Вот рабочий код ниже:

                typealias Fn<T> = ()->T 
                fun <T>If(c : Boolean, b : ()->Pair<Fn<T>,Fn<T>>): T
                {
                    if (c) 
                    	return b().first()
                    else 
                    	return b().second()
                }
                infix fun <T>Fn<T>.Else(f2 : Fn<T>) = { ->(this to f2}
                
                fun main() 
                {
                    //val r = If(false) {println("f1"); 1+2}Else{println("f2"); 1-2};
                    val r = If(false,({println("f1"); 1+2}Else{println("f2"); 1-2}));
                    println(r)
                }

                Немного подумав - предлагаю вторую реализацию - уже с неявной передачей упакованных выражений во второй аргумент функции If:

                typealias Fn<T> = ()->T 
                fun <T>If(c : Boolean, b : ()->Pair<Fn<T>,Fn<T>>): T
                {
                    if (c) 
                    	return b().first()
                    else 
                    	return b().second()
                }
                //infix fun <T>Fn<T>.Else(f2 : Fn<T>) = { -> this to f2}
                infix fun <T>Fn<T>.Else(f2 : Fn<T>) = this to f2
                
                
                fun main() {
                    //val r = If(false){({println("f1"); 1+2}Else{println("f2"); 1-2})()};
                    val r = If(false){{println("f1"); 1+2}Else{println("f2"); 1-2}};
                    println(r)
                }

                Вариант с закомментированными строчками (вместо парных незакомментированных) тоже рабочий - но вызов явно выглядит хуже - но, может конфигуратор поступает так - тут другой возвращаемый тип у функции Else - без запаковки в анонимную функцию - которая образуется уже в виде явного Unit блока после вызова функции If - тогда этот блок захватывается компилятором и передаётся в качестве второго (правого) аргумента функции If.

                Вот такое небольшое исследование того, как фактически (с точки зрения внутриязыковой логики) может быть устроен тернарный оператор в Kotlin. Тут, конечно, можно было бы исследовать дальше - например конструкции "val r = if (c1) exp1 else if (c2) exp2 else if (c3) exp3 else exp" а так же рассмотреть более сложный оператор when, а ещё напрямую заглянуть в исходники открытого компилятора Kotlin - но это уже явно потянуло бы на целую большую статью - написать которую я пока не могу.

                Даже если в Kotlin всё устроено иначе, чем предположил я - то всё-равно, надеюсь приведённые мной выкладки будут полезны для понимания различных мощных синтаксических фишек языка, позволяющих быстро писать компактный, производительный и красивый код


      1. sshikov
        21.09.2022 21:26
        +4

        Ну и в скале так же, и чо? Это не более чем непривычно. Хотя еще как посмотреть — если у if есть результат, это как раз наоборот логично, и привыкнуть к этому можно быстро.


      1. InsanusMokrassar
        23.09.2022 07:10

        Это сделано специально, чтобы операция тернарника не сливалась с кодом. Плюс есть компиляторные сложности, но их можно обойти.


        1. izogfif
          24.09.2022 00:11

          Да там многое сделано специально. Специально for (int i = 0; i < n; ++i) удалили, специально классы по умолчанию нерасширяемые, специально static-методы и поля убрали.

          Лично я еще ни одного собственного языка программирования не написал, и уверен, что этому всему была 1000 и одна веская причина, одна другой весче. Но жутко бесит утомляет, когда ты уже лед -дцать гладил кошку и она урчала, а тут только руку поднес, а она тебе внезапно человечьим голосом молвит: "допускается использовать только тыльную сторону руки, и да, не забудьте мизинец оттопырить, иначе я благим матом орать буду вместо урчания".

          Возможно, еще через -дцать лет удастся привыкнуть и не придется сначала по привычке писать код как привык делать в C++, потом в JavaScript, потом Java (куда только кривая дорожка программиста не заводила), а затем спохватываться, удалять и писать "как тут принято".


  1. mayorovp
    21.09.2022 13:59
    +28

    Я хочу рассказать вам о новом языке программирования под названием Kotlin

    Вы шутите или издеваетесь?


    А не, вы просто перевели публикацию 2017го года...


    1. K0styan
      21.09.2022 14:16
      +17

      Что в этом случае можно быть приравнено к "издеваетесь".


    1. sshikov
      21.09.2022 18:58
      +1

      Раньше я предпочитал Java, но за прошедший год обнаружил, что кодирую на Kotlin при любой возможности

      Я бы и про автора оригинала сказал, что он просто имеет узкий кругозор, и не знает например про скалу или груви. Да собственно и котлину уже 11 лет, в 2017 он был далеко не новым уже.

      Я просто думаю, что все вот эти переводы (по качеству это кстати хорошо заметно — чуть нетривиальная тема, начинаются косяки) пишут люди, которые сами никогда близко не стояли ни к котлину, ни к любой другой теме. Ну переводчики это… просто переводчики. Хорошо если не гугло… И какие темы на самом деле интересны и актуальны, они в итоге не понимают. Не думаю что это сознательное издевательство, просто в этом процессе нет обратной связи как таковой. Вы посмотрите хоть на автора этого текста — 1.4к публикаций, и при этом 34 кармы (и 257 комментариев). Никому это качество текстов (из заказчиков автора) не нужно.


      1. Politura
        22.09.2022 05:06
        +1

        Тут не только перевод, статья с медиума, а на этом ресурсе в ТОПе как правило статьи предельно низкого качества с хайповыми заголовками, типа "Почему ты должен...", "X вещей, которые ты обязан делать в языке Y", "ХХХ мертв и вот почему.", и тд., ну а у переводчиков нет знаний оценить качество, переводят из топа и получается то, что получается.


      1. nordligeulv
        22.09.2022 09:37

        А чем Scala интереснее по сравнению с Kotlin? Не подкол, просто вопрос.


        1. sshikov
          22.09.2022 18:53
          +2

          Ну, прежде всего — это субъективное мнение… Я скорее имел в виду не что она интереснее (хотя в ней есть и такое), а что уже очень давно в этой же нише (языков для платформы JVM, если на то пошло) есть куча вариантов, а те кто при этом бездумно предпочитает Java — они зачастую просто не в курсе того, какие у них есть возможности.

          Я бы сказал, что у них есть свои преимущества у обоих. Скала посложнее, но в тоже время мы вот пишем на Spark Shell, это по сути скала + спарк API, и получается как правило так, что эти сложности нам не видны вообще, а есть у нас в наличии более простая и чистая Java, где можно написать val a= «abcd», и никогда не нужно было указывать что это переменная/константа типа String, где можно написать Array(1, 2, ...).map{}, и не думать, что за тип у этой коллекции, и почему у нее вдруг нет .stream()?

          Ну и груви примерно из этой же оперы. Литералы для мапов и списков, ламбды от рождения, DSL на раз-два, и все это уже 17 лет кажется. Синтаксически все проще и удобнее, а семантически доступно все тоже самое.


          1. nordligeulv
            22.09.2022 19:10
            +1

            Благодарю за ответ


  1. scronheim
    21.09.2022 14:10
    +3

    Новом языке?)) он с 2011 года существует. Статья прямиком из прошлого


    1. t38c3j
      21.09.2022 14:32
      +6

      Новый язык для переводчика и школы))


  1. Chuvi
    21.09.2022 14:16
    +2

    почему вы должны рассмотреть его для своего следующего проекта

    я обычно прошивки для разных МК пишу. Мне точно надо зафеячивать туда котлин? С++ уже не в моде?


  1. diakin
    21.09.2022 14:25

    А нельзя было const вместо val ?


    1. Plesser
      21.09.2022 15:05
      +4

      val в kotlin это переменная которая является неизменяемый, но лежащий в ней объект вполне может менять значения своих полей, то есть в отличие const не фиксируется на этапе компиляции


    1. AWE64
      21.09.2022 15:14
      +1

      есть и const val


    1. danial72
      21.09.2022 15:20

      лучше final тогда уж


  1. Revertis
    21.09.2022 14:29

    Да, где минусы? Тот же companion object, например?


    1. LordDarklight
      21.09.2022 15:00

      Не трожьте компаньонов - может синтаксис и не удачный - зато единственный вариант определения статических членов класса. Да и не так уж он ущербен такой синтаксис - просто дело привычки. В некоторых языках вообще нет статических членов классов - нужно только отдельно синглетоны определять для этого. А из компаньонов классов Котлина может ещё со временем раззовётся что-то более толковое!

      Мне вот больше не понравилось, что все члены и классы по умолчанию закрытые - нельзя наследоваться и переопределять! Я понимаю, что это ради производительности. Но уж больно снижает гибкость разработки при использовании сторонних библиотек без исходников.

      Или очень ограниченные кортежи

      Ну и нет таких широких возможностей по раскрытию неограниченных параметров функций, как в Питоне.


  1. hMartin
    21.09.2022 14:30
    +1

    Статья настолько свежая, что несколько пунктов уже завезли или в процессе завоза)


  1. t38c3j
    21.09.2022 14:46
    +22

    Меня забавляет что школа онлайн образования продвигая курсы, переводит статьи, вместо того чтоб со своими ведущими экспертами как написано на сайте, сообща написать новую техническую статью


  1. Pastoral
    21.09.2022 14:51

    Переводя статью 2017 года автор решил тонко обратить взор читателей на историю социа-демократического движения? Тогда при чём тут Хабр?


  1. hard2018
    21.09.2022 14:55
    -3

    Что насчёт переносимости? Если я хочу запустить веб на основе приложения или наоборот. Здесь, наверное, java лучше. Или проекты на java не переносятся.


    1. Sigest
      22.09.2022 07:56
      +1

      Что имеется в виду про переносимость? Взаимодействие с джавой работает в большинстве случаев хорошо. Есть косяки конечно, у меня как-то не получилось в котлине отнаследоваться от джава класса, кажется причина была в том, что котлин имплиситно вставляет гетеры/сеттеры и override джавовского гетера ломался, но точно не помню. Если под переносимостью понимается конвертация джава классов в котлин, то в Idea это выполняется одним кликом мыши. Не идеально конвертится, но руками потом можно поправить. Ну и с каждым разом команда Jetbrains эту конвертацию улучшает. Хотя перечитал ваш вопрос еще раз, какой-то бред написан, но раз уж настрочил я ответ, то запощу его


  1. codecity
    21.09.2022 15:10

    В C# почти все эти фишки добавили в новые версии языка - не нужно никуда переходить. Возможно и в Java добавят - так что бегать туда-сюда смысла нет, лучше подождать.


  1. igrishaev
    21.09.2022 15:32
    +10

    Очень жаль, что у компаний нет кармы. Иначе ее бы быстро спустили в минуса за подобный треш.


  1. SerJook
    21.09.2022 15:36
    -1

    Какие реальные преимущества Kotlin перед Java, если отбросить синтаксический сахар?
    Другими словами, что можно написать на Kotlin, чего нельзя на Java?


    1. LordDarklight
      21.09.2022 16:15
      +3

      Что можно написать на Java, что нельзя написать на С++ или С, а что можно написать на них, чего нельзя написать на Asm

      В современных ЯП в рамках одной парадигмы (хотя они сейчас как раз-таки становятся мультипарадигменными) всё так или иначе определяется синтаксическим сахаром и моделью выделения памяти и контроля ссылок - но если с памятью всё, в первую очередь, определяется средой выполнения и компилятором, то в рамках одного движка остаётся только удобство написания программ и удобство их тестирования и отладки - что, в итоге, и определят скорость и качество кодирования алгоритмов, и отчасти их производительность и надёжность (как составляющие качества). Так же есть некоторые современные тренды - ЯП развиваются - люди их изучают у ЯП идёт конкуренция за программиста - поэтому ЯП частенько тырят разные синтаксические фичи друг у друга - что приводит к их некоторой унификации и образованию некоторого обобщённого слоя общих семантических подходов. И чем консервативнее ЯП - тем больше он удаляется от этого слоя и тем более становится не интересным!

      И ещё - сейчас императивные типизированные ЯП делятся на две группы

      1. Левая типизация как у Java , или Dart, или С++, или C#, или Perl / PHP

      2. Правая типизация как у Kotlin или Rust, или Go, или TypeScript, или Pascal

      И у каждого подхода есть сторонники и противники (вот тут есть на хабре небольшой анализ). Но в целом сейчас тенденция в современных ЯП к переходу к правосторонней типизации. Вот такой заменой и является Kotlin для Java. Ну и в Kotlin ещё завезли более продвинутую модель ООП (в первую очередь со свойствами и с делегатами свойств) и "рефлексию" - вот, кстати, расширенных метаданных в Java библиотеках нет, и тут много взаимовытекающих ограничений.


      1. LordDarklight
        21.09.2022 16:50

        (не уложился в таймаут редактирования написанного комментария - добавка к моему комментарию)

        ...взаимовытекающих ограничений (например отсутствие значений по умолчанию у функций; или при использовании дженериков)

        С дженерик определениями тоже - куда удобнее при правосторонней типизации (дженерик определение слева, а его использование справа - читаем слева на право).

        Так что я всецело за правостороннюю типизацию.

        А ещё за правосторонние директивы и аннотации (ну или на выбор - по удобству слева или справа - оба варианта можно сделать допустимыми одновременно).

        И вообще на эту тему давно хочу написать свою статью!

        Но пока ЯП Kotlin нет в даже в 20-ке самых популярных языков программирования, по версии Tiobe, в 2022 году. Java на почётном 3-тьем месте. А вот, на первое неожиданно вырвался Python. А на втором - неожиданно находится язык Си. Даже второй прямой конкурент (после Java, в области клиент-серверной и мобильной разработке) как Swift находится на 16 месте. А Kotlin оф язык мобильной Android разработки и мультиплатформенный, а Swift - практически только инфраструктура Apple


        1. Pastoral
          21.09.2022 21:48

          Есть и другие рейтинги, равно как и более менее взвешенный подход к ним. Эппл, естественно, побеждает везде где участвует, но и Котлин не выглядит настолько безнадёжно насколько это кажется только по Tiobe.

          Мне, по наивности конечно, кажется, что сейчас инициатива у Эппл которая фактически предлагает писать на Swift для Мака, iPad и бэкенда и забыть про всё остальное, с упором на «всё». На что конкуренты отвечают кроссплатформенностью, которая вынуждает их а) включать и платформы Эппл, так что Эппл в эту игру выиграть может а проиграть нет, и б) грызться между собой, так что как только Rust допускают в ядро Линукс, так Гугол кидается лепить Carbon.

          И преимущество в этих условиях будет иметь не тот язык который лучше (кстати, даже вынужденная кроссплатформенность снимает аргумент «для каждой задачи свой», который я всегда считал придумкой маркетологов, ибо задача одна - записать обнаруженное способом понятным и человеку и машине), а тот, у которого лучше инструментарий. В случае Котлин это означает - подождём выхода Kotlin Multiplatform на релиз.


    1. sshikov
      21.09.2022 19:03
      -1

      Оставаясь в рамках JVM, ничего нового вы не напишете конечно, что нельзя было бы на Java. Но котлин умеет в разные среды исполнения компилить (например в JS). Пожалуй только этим принципиально отличается.


    1. Left2
      22.09.2022 15:46
      +1

      Попиши на Джаве асинхронный код. С CompletableFuture и цепочками .then(). И так чтобы условий там в цепочках было побольше, циклов и т.п. Очень, очень быстро захочется нормальных корутин, и очень сложно будет вернуться назад на чистую Джаву. Это самое главное преимущество, не считая приятных мелочей вида null-safety, extension functions и т.п.


      1. BugM
        23.09.2022 00:15
        -2

        Подождите до легких потоков. Все эти фьютуры не нужны в 99% процентов случаев. Хватит обычного потока. Он удобнее прям со всех сторон.

        Котлиновские корутины это абсолютное зло для любого развесистого проекта. Раздебажить гонку в таком коде занимает какое-то неприличное время. А посадить баг с гонкой легче легкого.


  1. n43jl
    21.09.2022 16:19
    +1

    мне понравилось вот такое рассуждение о перспективах Котлина против джавы: https://www.reddit.com/r/java/comments/ndwz92/can_i_get_some_reasons_to_use_java_instead_of/


  1. JavaFox
    21.09.2022 22:54
    +5

    Все хорошо, только судя по всему после бурного успеха, Jetbrains стали типичной корпо и вместо того что бы фиксить баги в своем софте или добавлять важные фичи за которые любили раньше их ide , то сейчас с каждым новым выпуском добавляют всякую фигню, типо нейросеть теперь дописывает код за вас, совместное писание кода и т.д. А пофиксить баг, что в котлине во время дебага suspend функции нельзя нормальной пройтись по callstack и тебя будет кидать в .class файлы, а не в .kt или .java ? А добавить элементарную функцию в rider и resharper, раз вы поддерживаете blazor, возможность видеть только изолированные для данного компонента стили? Всегда все любили jetbrains за то что делалось программистами для программистов


  1. steff
    21.09.2022 23:04

    Взгляните на Anko в качестве примера DSL, который призван улучшить разработку Android

    Смотрим: ⚠️ Anko is deprecated. Please see this page for more information.


  1. numb
    22.09.2022 09:33
    +1

    почему вы должны рассмотреть его для своего следующего проекта

    А я только только Rust начал изучать(


  1. tolik_anabolik
    22.09.2022 09:35
    +1

    Некоторые пункты, приведенные как фичи котлина, уже реализованы в современных версиях java. Некоторые пункты, приведенные как плюсы, выглядят сомнительными, а местами это вовсе вкусовщина.

    persons
        .filter { it.age >= 18 }
        .sortedBy { it.name }
        .map { it.email }
        .forEach { print(it) }

    Называть подобный код более читаемым и поддерживаемым очень спорно. Более того, почему-то здесь не упомянуто про неочевидный return из лямбд, который в отличие от java делает возврат из окружающей функции. А чтобы выйти из лямбды придется вбивать возврат с меткой return@label. И такой код они называют читаемым, спорно, но поверим.

    Другой момент с null-safe. При работе с БД у вас многие поля будут nullable. И тогда привет огород из элвисов: ?. ?. ?. Может и нечастый кейс, но точно нередкий.

    Самая важное в этом всем. Котлин завязан на инфру java, но при этом развивается своим путем и добавляет свои фичи. И чтобы профессионально использовать среду вам придется хорошо разбираться и в java и в котлине.


    1. sshikov
      22.09.2022 18:56

      >Называть подобный код более читаемым и поддерживаемым очень спорно.
      Где-то дело вкуса, да. Но в тоже время — это и котлин, и чистый груви, прямо вот без изменений. Ну разве что названия методов могут быть чуть другими — груви старше. И у такого стиля есть свои поклонники (и преимущества). Например, оно лучше компонуется.


      1. LordDarklight
        23.09.2022 15:43

        У Groovy и Kotlin несколько разная модель типизации. Ну и Kotlin это не только JVM

        Но большое влияние Groovy, Scala, C# на Kotlin не оспоримо!


        1. sshikov
          23.09.2022 18:30

          Ну да. Про то что это не только JVM, я уже где-то тут написал — кто-то поставил минус, без аргументов. И да, они все конечно разные. Я про другое чуть-чуть — что задолго до котлина (скала же 2004 год вроде?) у тех кто был не полностью удовлетворен Java (а она тогда развивалась не в пример медленнее, чем сейчас) была куча возможностей. У них был выбор. Даже JYthon вполне пригоден к применению, а уж тогда и подавно был. Кложа, опять же. Есть варианты на любой вкус, и давно. И когда автор в 2017 говорит: «Ой, я тут котлин обнаружил», мне кажется он просто был нелюбопытен предыдущие годы )))


  1. Left2
    22.09.2022 10:41
    +5

    Ко-ру-ти-ны. Даже если бы были только они и интероп с джавой - УЖЕ нужно бы было переходить. А тут - нашелся пункт для свистоперделок типа when (которые приятные и удобные - но все же МЕЛОЧИ) - а для самого главного - корутин и асинхронности на их основе - не нашлось.


  1. Bakuard
    22.09.2022 20:23
    +1

    Пункты 3,4,8,10,13 — есть и в Java, причем некоторые из этих пунктов присутствуют в языке давно. Пункты 5 и 11 — я бы не стал торопиться называть преимуществами. Создаётся впечатление, что последняя версия Java, с которой знаком автор, это в лучшем случае восьмая.


    1. sshikov
      23.09.2022 18:31

      Это статья 2017 года. Где-то так оно и было на тот момент.


  1. BlackJet
    23.09.2022 14:42

    А как насчет dart? )


    1. BugM
      24.09.2022 00:37

      То, что мертво, умереть не может