Рубрики
Без рубрики

От Явы до Котлина за 20 минут ⚡️

Каково это – быть разработчиком Java, чтобы начать программировать в Kotlin? Я не помнил, я… С тегами java, kotlin, android, новички.

Каково это – быть разработчиком Java, чтобы начать программировать в Kotlin?

Я не помнил, для меня это было много лет назад!

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

Время рассказа!

  • Покажи мне код!
  • Моб-программирование
  • Инструменты > Kotlin > Настройка Kotlin в проекте
  • Сообщите Java, что @ParametersAreNonnullByDefault
  • PinGuesser: Преобразование файла Java в файл Kotlin
  • PinGuesserTest: Преобразование файла Java в файл Kotlin и ручные исправления
  • Используйте стандартную библиотеку Kotlin
  • Заменить stream() API на Kotlin stdlib
  • Сделайте val, а не var
  • Быстро терпит неудачу
  • Функциональный стиль
  • List.fold()
  • Куда Мы Пойдем Дальше?

Покажи мне код!

Чтобы следовать дальше, ознакомьтесь с кодом.

У вас должен быть установлен IntelliJ Community Edition . Это бесплатно!

Например, в macOS это $ brew install intellij-idea-ce

Код находится здесь, и вы можете увидеть все изменения, описанные ниже в этом pull-запросе

jmfayard/из-java-в-kotlin

jmfayard/из-java-в-kotlin

Итак, детектив, один из наших коллег успешно наблюдал за нашей целью, грабителем Робби. Мы последовали за ним на секретный склад, где, как мы предполагаем, должны были найти все украденные вещи. Дверь на этот склад заперта на электронный кодовый замок. К сожалению, наш шпион не уверен насчет ПИН-кода, который он видел, когда Робби вводил его.

Клавиатура имеет следующую компоновку:

┌───┬───┬───┐
│ 1 │ 2 │ 3 │
├───┼───┼───┤
│ 4 │ 5 │ 6 │
├───┼───┼───┤
│ 7 │ 8 │ 9 │
└───┼───┼───┘
    │ 0 │
    └───┘

Он отметил PIN-код 1357, но он также сказал, что возможно, что каждая из цифр, которые он видел, на самом деле может быть другой соседней цифрой (по горизонтали или вертикали, но не по диагонали). Например. вместо 1 это также может быть 2 или 4. И вместо 5 это также может быть…

Но сначала некоторый контекст

Моб-программирование

Мои коллеги Сара и Питер и я участвовали в сеансе Программирования мобов

Цель состояла в том, чтобы решить ката наблюдаемой БУЛАВКИ , где ненадежный шпион сообщает, что он видел БУЛАВКУ 1357 используется, но на самом деле, он не совсем уверен, каждая цифра может быть вместо нее одной из соседних по раскладке клавиатуры. Это может быть 1357 но также, например 2357 или 1368.

Проект представлял собой Java-проект, созданный с помощью Maven. Он содержит два файла: PinGuesser.java и PinGuesserTest.java . Он компилирует и запускает модульные тесты за считанные секунды, а не за минуты, как во многих приложениях для Android. Это улучшает работу разработчиков, ИМХО.

Мы использовали Код IntelliJ Со мной , чтобы поделиться кодом.

У нас все шло хорошо, и мы решили Ката на Java, а затем реорганизовали его до удовлетворительного состояния.

  • Сара : Есть ли что-нибудь еще, что мы могли бы улучшить?
  • Питер : Я не знаю, по-моему, выглядит неплохо.
  • Я : Что ж, у нас осталось 20 минут, почему бы не переписать все это на Kotlin?
  • Сара : О, я слышал о Kotlin, но у меня еще не было возможности им воспользоваться. Но через 20 минут, как ты думаешь, мы сможем это сделать?
  • Я : Давайте начнем и посмотрим, к чему это нас приведет!

Инструменты > Kotlin > Настройка Kotlin в проекте

  • Питер : Хорошо, итак, я никогда в жизни не занимался Kotlin, скажите мне, что делать.
  • Me : Есть команда IntelliJ, которая называется Преобразовать файл Java в файл Kotlin . Это отличная отправная точка!
  • Питер : Давайте попробуем.
  • Питер : IntelliJ говорит мне, что Kotlin не настроен, это имеет смысл.
  • Питер : Как мне настроить Kotlin в Maven?
  • Я : Я не знаю, я всегда использовал Gradle.
  • Я : Просто позвольте IntelliJ сделать это!
  • Me : Кстати, он будет делать то же самое, что и Tools > Kotlin > Configure Kotlin в проекте
  • Питер : Давайте сделаем это
  • Питер : Похоже, это сработало. В файле есть обновления pom.xml
  • Питер : первый коммит

Сообщите Java, что @ParametersAreNonnullByDefault

  • Me : Прежде чем мы попробуем конвертер Java в Kotlin, есть кое-что, о чем мы хотим позаботиться.
  • Я : Как вы знаете, Kotlin интегрировал возможность обнуления в систему типов, в то время как Java по умолчанию этого не делает.
  • Я : Поэтому конвертер будет разрешать нули везде, что технически правильно, но не то, что вы хотите.
  • Сара : Но в Java есть аннотации, чтобы указать, является ли что-то обнуляемым или нет, верно?
  • Я : Точно! И единственное, что мы хотим, – это сообщить, что по умолчанию все не равно нулю. Удобно, что именно так это работает и в Kotlin.
diff --git a/pom.xml b/pom.xml
     
+        
+            com.google.code.findbugs
+            jsr305
+            3.0.2
+        

+++ b/src/main/java/pin/package-info.java
@@ -0,0 +1,4 @@
+@ParametersAreNonnullByDefault
+package pin;
+
+import javax.annotation.ParametersAreNonnullByDefault;

PinGuesser: Преобразование файла Java в файл Kotlin

  • Питер : Наверное, я сейчас открою PinGuesser.java и просто перезапустите конвертер Преобразовать файл Java в файл Kotlin
  • Я : Правильный
  • Питер : Кажется, что… это сработало? Есть файл Есть файл
  • Я
  • : Но откуда вы знаете, что это сработало? Сара
  • : Вы должны запустить модульные тесты Питер
  • Питер : Он все еще весь зеленый. Удивительно, я написал свой первый в истории код Kotlin, и в нем нет ошибок!
  • Сара : Хорошая работа!
  • Питер : А как насчет тестов? Разве мы не должны преобразовать и их тоже?
  • Я : Тебе это не нужно. Java и Kotlin могут мирно сосуществовать в одной и той же кодовой базе.
  • Сара : Хорошо, но это выглядит забавно, я тоже хочу попробовать!
  • Питер : Сначала позвольте мне совершить

PinGuesserTest: Преобразование файла Java в файл Kotlin и ручные исправления

  • Сара : Поэтому я открываю PinGuesserTest.java и запустите команду. Как это называется?
  • Peter : Преобразовать файл Java в файл Kotlin
  • Сара : Поехали!
  • Сара : Теперь у меня есть PinGuesserTest.kt . Однако в нем есть некоторые ошибки
  • Питер : Может быть, применить это предложение для оптимизации импорта?
  • Сара : Хорошо.
  • Сара : Это сработало.
  • Я: как вы видите, это не идеально, но это потрясающий инструмент обучения: вы начинаете с того, что вы уже знаете (на Java), и видите, как это преобразуется в то, что вы хотите выучить (на Kotlin)
  • Сара : Позвольте мне управлять устройством тесты
  • Сара : У меня есть несколько странных ошибок JUnit
  • Я : Хорошо, я это понимаю. В Java есть статические методы, в то время как в Kotlin есть концепция сопутствующего объекта { … }
  • Me : Его методы выглядят как статические методы, но немного отличаются. Здесь JUnit действительно хочет статические методы, и нам нужна аннотация, чтобы сделать его счастливым
-        fun testSingleDigitParameters(): Stream {
+        @JvmStatic fun testSingleDigitParameters(): Stream {
             return Stream.of(
                 Arguments.of("1", java.util.Set.of("1", "2", "4")),
                 Arguments.of("2", java.util.Set.of("1", "2", "3", "5")),
@@ -61,7 +58,7 @@ internal class PinGuesserTest {
             )
         }

-        fun invalidParams(): Stream {
+        @JvmStatic  fun invalidParams(): Stream {
             return Stream.of(
                 Arguments.of("   "),
                 Arguments.of("A"),
  • Сара : Модульные тесты теперь работают!
  • Сара : Проект сейчас на 100% находится в Котлине
  • Сара : совершить

Используйте стандартную библиотеку Kotlin

  • Питер : Что будет дальше?
  • Я : Можно создать Список , Установить |/и Map традиционным способом Java, но стандартная библиотека Kotlin содержит множество небольших утилит для упрощения этого, это было бы моим первым изменением. Позволь мне сделать это:
  • Я : так выглядит лучше. Модульные тесты все еще зеленые?
  • Я : Они есть, давайте зафиксируем

Заменить stream() API на Kotlin stdlib

  • Me : Что-то еще, содержащееся в стандартной библиотеке Kotlin, – это функции, найденные в функциональных языках программирования, таких как .map () , .фильтр () , .плоская карта () и многое другое.
  • Сара : Немного похоже на Java Stream API, который мы используем?
  • Я : Да, вот так, но менее многословно и более эффективно под капотом!
-    fun combineSolutions(pins1: Set, pins2: Set): Set {
-        return pins1.stream()
-            .flatMap { pin1: String ->
-                pins2
-                    .stream()
-                    .map { pin2: String -> pin1 + pin2 }
-            .collect(Collectors.toSet())
-    }

+    fun combineSolutions(pins1: Set, pins2: Set): Set =
+        pins1.flatMap { pin1 ->
+            pins2.map { pin2 ->
+                "$pin1$pin2"
+             }
+        }.toSet()
  • Сара : Модульные тесты все еще зеленые.
  • Сара : совершить

Сделайте val, а не var

  • Я : Далее, в идиоматическом стиле Kotlin, мы склонны использовать val property вместо var property большую часть времени.
  • Питер : В чем разница?
  • Me : свойство val доступно только для чтения, у него нет установщика, это похоже на конечное поле в Java
  • Питер : Я понимаю. Итак, я просто меняю свойство var на значение val?
  • Я : В значительной степени так.
  • Питер : Достаточно просто
  • Питер : совершить

Быстро терпит неудачу

  • Сара : Существует ли идиоматический способ проверки параметров функции?
  • Сара : ПИН-код должен быть чем-то вроде 7294 со всеми символами, являющимися цифрами
  • Я : Да, вы используете require(условие) { "сообщение об ошибке" } для этого
  • Сара : Как бы это выглядело здесь?
fun getPINs(observedPin: String): Set {
    require(observedPin.all { it in '0'..'9' }) { "PIN $observedPin is invalid" }
    // rest goes here
}

Функциональный стиль

  • Сара : Что будет дальше?
  • Я : Я хотел бы освободить функции
  • Питер : Что вы имеете в виду?
  • Я : Слушай, у нас есть это Pinguescere класс, но что именно он делает?
  • Me : Он ничего не делает, это тупое пространство имен.
  • Я : Это существительное это мешает нам получить прямой доступ к глаголам , которые выполняют реальную работу.
  • Я : Один из моих любимых языков программирования всех времен – |/Исполнение в королевстве существительных Стива Йегге. Сара
  • : Я знаю эту тираду, чистый гений! Сара
  • : Как нам освободить глаголы/функции? Me
  • : Мы удаляем класс и используем функции верхнего уровня
diff --git a/src/main/java/pin/PinGuesser.kt b/src/main/java/pin/PinGuesser.kt
index 17a20b3..38e457c 100644
--- a/src/main/java/pin/PinGuesser.kt
+++ b/src/main/java/pin/PinGuesser.kt
@@ -1,9 +1,5 @@
 package pin

-import java.util.stream.Collectors
-
-class PinGuesser {
-    companion object {
         val mapPins = mapOf(
             "1" to setOf("1", "2", "4"),
             "2" to setOf("1", "2", "3", "5"),
@@ -16,7 +12,6 @@ class PinGuesser {
             "9" to setOf("6", "8", "9"),
             "0" to setOf("0", "8"),
         )
-    }

     fun getPINs(observedPin: String): Set {
         for (c in observedPin.toCharArray()) {
@@ -38,5 +33,4 @@ class PinGuesser {
             pins2.map { pin2 ->
                 "$pin1$pin2"
             }
-        }.toSet()
-}


--- a/src/test/java/PinGuesserTest.kt
+++ b/src/test/java/PinGuesserTest.kt
class PinGuesserTest {
-    val pinGuesser = PinGuesser()

     @ParameterizedTest
     @MethodSource("testSingleDigitParameters")
     fun testSingleDigit(observedPin: String?, expected: Set?) {
-        val actual = pinGuesser.getPINs(observedPin!!)
+        val actual = getPINs(observedPin!!)
         Assertions.assertEquals(expected, actual)
     }

List.fold()

  • Питер : Мы можем сделать шаг назад? Что это дает нам, чтобы сделать код более приятным, как это? В конце концов, клиенту все равно.
  • Я : Ну, я вас не знаю, но часто я на самом деле не понимаю код, над которым я должен работать. Я склонен усердно работать, чтобы упростить это, и в какой-то момент это укладывается у меня в голове, и решение становится очевидным.
  • Питер : Как бы это выглядело здесь?
  • Me : Теперь, когда код написан на красивом функциональном идиоматическом Kotlin, я понимаю, что программа может быть решена с помощью одной функциональной конструкции: List.fold()
  • Сара : Покажи мне код
  • Я : совершить
fun getPINs(observedPin: String): Set {
    require(observedPin.all { it in mapPins }) { "PIN $observedPin is invalid" }

    return  observedPin.fold(initial = setOf("")) { acc: Set, c: Char ->
        val pinsForChar: Set = mapPins[c]!!
        combineSolutions(acc, pinsForChar)
    }
}

fun combineSolutions(pins1: Set, pins2: Set): Set =
    pins1.flatMap { pin1 ->
        pins2.map { pin2 ->
            "$pin1$pin2"
        }
    }.toSet()

Куда Мы Пойдем Дальше?

Я надеюсь, что вам понравилась эта статья.

Если вы хотите связаться с нами, вы можете сделать это через https://jmfayard.dev/

Код доступен по адресу https://github.com/jmfayard/from-java-to-kotlin

Начните с ветки java и сравните с веткой kotlin . Смотрите этот запрос на вытягивание

Если вам интересно узнать больше о Kotlin, я написал об этом здесь

Как изучить Kotlin: браузер против IDE, книги против учебников, для новичков и Разработчики Java

Жан-Мишель Файяр 🇫🇷 🇩🇪 🇬🇧 🇪🇸 🇨🇴 ・ 15 декабря 19 ・ 6 минут чтения

Оригинал: “https://dev.to/jmfayard/from-java-to-kotlin-in-20-minutes-d9f”