Эффективная Java в Kotlin, устаревшие элементы благодаря Kotlin (элементы 3, 4, 16, 40, 61 из 3-го издания)
Kotlin - это огромное улучшение по сравнению с Java. Он был разработан, когда основные недостатки Java были уже известны, поэтому многие из них можно было решить раз и навсегда. Давайте обсудим некоторые моменты из Эффективной книги Java Джошуа Блоха, которые больше не применимы, поскольку мы используем Kotlin.
Правило 3: принудительное применение свойства singleton с помощью частного конструктора или типа перечисления
Смысл этого пункта в том, чтобы гарантировать, что у одиночных экземпляров не будет более одного экземпляра. В книге показано несколько хороших примеров того, как это сделать. Это не применимо в Kotlin, потому что у нас есть встроенная поддержка одноэлементного шаблона, называемого объявлением объекта:
object ThisIsSingleton { val prop = 10 fun method() = 20 } // Usage print(ThisIsSingleton.prop) // 10 print(ThisIsSingleton.method()) // 20
Это не только проще в использовании и декларировании, но и совершенно безопасно. Фактически, Kotlin под капотом использует первый описанный в Эффективном шаблоне Java для правильного объявления синглтона.
Правило 4: Обеспечьте невозможность создания экземпляров с помощью частного конструктора
Смысл этого элемента в том, что Java не допускает функций верхнего уровня, поэтому все такие функции помещаются как статические члены в классы util:
// Java class StringUtils { public static String trim(s: String) { /*...*/ } }
В Kotlin это не имеет смысла, потому что дает нам лучшие альтернативы. Прямой эквивалент - функция верхнего уровня:
fun trim(s: String): String { /*...*/}
Хотя в этом случае мы бы предпочли определить функцию расширения верхнего уровня:
fun String.trim(): String { /*...*/}
Оба скомпилированы в JVM в статический метод в классе, который не может быть инициализирован.
Другой альтернативой является объявление объекта:
object StringUtils { fun trim(s: String): String { /*...*/} }
Объявление объекта можно инициализировать, но мы можем использовать это специально разработанное поведение:
interface CarFactory { val prize: Int fun makeCar(): Car } object Fiat126PFactory: CarFactory { override val prize: Int = 500 override fun makeCar(): Car = TODO() } object OpelAstraFactory: CarFactory { override val prize: Int = 2_500 override fun makeCar(): Car = TODO() } object FerrariFactory: CarFactory { override val prize: Int = 500_000 override fun makeCar(): Car = TODO() } val factories = listOf( Fiat126PFactory, OpelAstraFactory, FerrariFactory ) val cheapestCar = factories.minBy { it.prize }?.makeCar()
Правило 16. В общедоступных классах используйте методы доступа, а не общедоступные поля
Это наиболее явное улучшение по сравнению с Java. Что ж, в Java у нас были поля, а в Kotlin - свойства. Они выглядят почти одинаково, но ключевое отличие в том, что для свойств Kotlin мы всегда можем установить пользовательский сеттер. Значит, они инкапсулированы. Чтобы разрешить это в Java, нам нужно использовать field, getter и setter. Давайте посмотрим на это на нескольких примерах. Следуя за свойством Котлина:
var name: String = "Marcin Moskala"
является эквивалентом следующего поля Java и методов доступа:
// Java @NotNull private String name = "Marcin Moskala"; @NotNull public String getName() { return name; } public void setName(@NotNull String name) { Intrinsics.checkParameterIsNotNull(var0, "<set-?>"); this.name = name; }
Каждое использование свойства фактически использует сеттеры и геттеры. Мы всегда можем установить собственные сеттеры и геттеры:
var name: String = "Marcin Moskala" get() = field.trim() set(value) { if(value.isNotEmpty()) field = value }
который будет компилироваться примерно так:
// Java @NotNull private String name = "Marcin Moskala"; @NotNull public String getName() { return StringsKt.trim(name).toString(); } public void setName(@NotNull String value) { if (value.length() > 0) { name = value; } }
На этом этапе Kotlin обеспечивает поведение, предложенное Effective Java, и его трудно обойти. Мы всегда можем изменить метод установки и получения свойств, не изменяя использование в Kotlin.
Пункт 40: постоянно используйте аннотацию Override
В отличие от аннотации Java Override
, в Kotlin требуется модификатор override
. Это вершина того, что предлагает книга.
Пункт 61: предпочитайте примитивные типы упакованным примитивам
Вы когда-нибудь видели примитивный шрифт в Котлине? Я часто вижу их, когда читаю скомпилированный код Kotlin. Дело в том, что каждый тип в Kotlin действует как коробочный тип, но, когда это возможно, компилятор Kotlin использует скрытые примитивы. Это означает, что Kotlin Int
- это int
, когда это возможно, и Integer
, когда требуются некоторые характеристики ООП (например, допускание значения NULL или использование для универсального). Можно было бы, вероятно, подумать о конкретном Int
использовании, позволяющем компилятору использовать примитивы под капотом, но я считаю, что это абсолютно ужасная идея. Потенциальное улучшение производительности и памяти будет незначительным, а хаос, внесенный в код, будет существенным. Я могу придумать единственный разумный случай, когда нам нужно работать с набором примитивов. Я описал это вместе со случаями использования Integer
вместо int
в другой статье. А пока просто помните, что вам не нужно беспокоиться о примитивах в Kotlin, потому что компилятор Kotlin сделает за вас тяжелую работу и оптимизирует ваш код.
Резюме
Kotlin упрощает хорошее программирование благодаря введенным функциям. Вот почему некоторые элементы Effective Java устарели, и нам больше не нужно о них беспокоиться. Есть также много элементов, которые все еще так или иначе актуальны, но Kotlin упростил их применение или представил больше возможностей. В следующей части мы обсудим другие предметы из книги. Также есть мой набор эффективных правил Kotlin. Я представлю их все в книге ниже, но я также поделился некоторыми из них в отдельных статьях.
Эффективный Котлин
Эта статья является частью серии «Эффективный Котлин», связанной с книгой, которую я собираюсь опубликовать. Вы найдете там набор лучших практик для удобочитаемости, масштабируемости и производительности в Kotlin:
Он будет охватывать гораздо более широкий круг тем и углубляться в каждую из них. Он также будет включать в себя лучшие практики, опубликованные командой Kotlin и Google, опыт членов команды Kotlin, с которой мы сотрудничаем, и темы, затронутые в серии Эффективная Java в Kotlin. Чтобы поддержать это и ускорить публикацию, воспользуйтесь этой ссылкой и подпишитесь.
Вам нужна мастерская Kotlin? Посетите наш сайт, чтобы узнать, что мы можем для вас сделать.
Чтобы быть в курсе отличных новостей на Kt. Академия , подписывайтесь на рассылку новостей , следите за Twitter и следите за новостями.
Чтобы сослаться на меня в Twitter, используйте @MarcinMoskala. Используйте ссылку ниже, чтобы подписаться на рассылку новостей: