-
Система типов: nullable-типы
Одной из самых известных особенностей Kotlin является разделение типов на nullable (которые могут принимать
null
в качестве значения) и на not-null типы. Nullable типы объявляются со знаком вопроса, напримерString?
,Int?
или, например,Array<Int?>?
. Основное преимущество -- явно разделять типы, которые могут и не могут приниматьnull
. По статистике большинство исключений, которые возникают в Java являются NullPointerException'ами. Новая система типов существенно помогает решить эту проблему. -
Система типов:
Nothing
В джаве, как и в большинстве современных языков, явно проверяется, что функция по любому пути исполнения возвращает некоторое значение. Например, следующий код на Java:
int foo(int x) { if (x > 0) return 1; // Здесь будет ошибка компиляции -- не возвращается никакое значение }
Однако, есть выражения, которые меняют поток исполнение, например:
int foo(int x) { if (x > 0) return 1; throw new RuntimeException("x must be positive"); // Здесь не будет ошибки, потому что поток управление не может пройти через throw }
Но что, если ты хочешь кидать исключения не с помощью throw, а с помощью специальной функции, например,
error
, которая перед исключением выводит что-то на консоль?void error(String message) { System.err.println(message); throw new RuntimeException(message); } int foo(int x) { if (x > 0) return 1; error("x must be positive"); // Снова ошибка, должен быть return }
В таком случае Java никак не может проверить, что функция
error
никогда не выполнится, поэтому она требует, чтобы послеerror
былreturn
илиthrow
. Однако в Kotlin для этого есть решение: специальный типNothing
. ТипNothing
ненаселен, то есть не существует значения, которое имеет такой тип. Если какое-то значение имеет типNothing
, то оно никогда не завершится. ТипNothing
имеют операторыreturn
,break
,continue
,throw
, а также его можно получить в некоторых других ситуациях. Используя его в Kotlin можно написать функциюerror
с правильным поведением:fun error(message: String): Nothing { System.err.println(message) throw RuntimeException(message) } fun foo(x: Int): Int { if (x > 0) return 1 error("x must be positive") // Никакой ошибки, успешная компиляция }
Также существует множество других красивых применений типа
Nothing
. Вот пример: Пусть есть списокlist: List<String?>
. Хочется в цикле перебрать все значения списка и вывести только те, которые неnull
. Можно это сделать топорным кодом:for (s in list) { if (s != null) println(s) }
Однако, гораздо более удобным и красивым будет следующий способ. Он использует тот факт, что
continue
имеет типNothing
, чтоNothing
является подтипом любого типа, а также специальный оператор Элвиса?:
, который работает следующим образом:a ?: b
эквивалентноa != null ? a : b
. Сам код:for (s in list) { val string = s ?: continue println(string) }
Этот код работает, потому что
continue
можно положить в переменную любого типа, так какNothing
является подтипом любого типа. Однако эффективно при вычисленииcontinue
будет выполнен пропуск итерации цикла, таким образом вstring
попадут только неnullовые значения списка. Существует еще тонна применений типуNothing
, напримерnull
имеет типNothing?
, но их слишком много, чтобы пытаться рассказать все. -
Система типов: вариантность типов
В Java есть способ указывать границы на параметры типов, например так:
void foo(Comparator<? super String> comparator) { ... }
Такая фукнция принимает компаратор для любого типа
T
, для которого верно, чтоString extends T
, то есть супертип (надтип)String
. ДляString
этоCharSequence
,Comparable
,Serializable
иObject
. Такое объявление типа называетсяcall-site variance
, то есть вариантность типа на месте вызова. Однако существуют типы, которые имеют сами по себе ковариантную или контравариантную структуру. Ковариантность означает, что функции типов зависят так же, как и аргументы, то есть еслиA <: B
, тоF<A> <: F<B>
. Здесь оператор<:
означает подтип. В Kotlin есть синтаксис (как в C#) для указания вариантности типа:class ReadOnlyList<out T> { ... } // Ковариантный по T, можно писать list: ReadOnlyList<Object> = ReadOnlyList<String>() class Consumer<in T> { ... } // Контравариантный по T, можно писать consumer: Consumer<String> = Comsumer<Object>()
-
Inline лямбды: non-local return
Анонимные функции (лямбды) и замыкания в Java достаточно слабые -- они имеют значительный вес в рантайме, потому что представляются отдельным классом в памяти, а также они не могут изменять состояние внешних переменных и захватывать нефинальные переменные. Однако в Kotlin функции могут принимать не простые функции (например,
fun foo(f: (String) -> Int)
), а inline функции (fun foo(inline f: (String) -> Int
). Такие функции при компиляции встраиваются в место вызова и могут менять окружающее состояние:var count = 0 list.forEach { item -> // <-- начало лямбды if (item > 0) count++ // Модификация локального состояния }
Однако, гораздо интереснее применение inline-лямбд состоит в возможности выйти из функции, находясь внутри лямбды. Например, следующий код:
fun hasPositive(list: List<Int>): Boolean { list.forEach { if (it > 0) // it -- обозначение для единственного аргумента лямбды, если не объявлено явно return true // Здесь return выходит из функции hasPositive, а не из лямбды // Если требуется выйти из лямбды, то нужно написать return@forEach } return false }
Такое свойство inline-функций делает их незаменимыми, в сочетании с тем, что они не существуют в рантайме, полностью встраиваясь в место вызова.
-
Inline-лямды: reified generics
В Java информация о generic-типах стирается во время исполнения, поэтому подобный код на Java (ровно как и на Kotlin) работать не будет:
<T> T[] create(int size) { return new T[size]; // Generic array creation error }
fun <T> create(size: Int): Array<T?> { return Array<T?>(size) { null } // Cannot use 'T' as reified type parameter error }
Однако у inline функций есть информация о типе, так как они встраиваются в место вызова. Для таких функций параметр типа можно пометить ключевым словом
reified
и тогда он будет доступен в рантайме:inline fun <reified T> create(size: Int): Array<T?> { return Array<T?>(size) { null } // OK }
kotlinopportunities's Introduction
kotlinopportunities's People
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.