- Make your life easier with Kotlin stdlib
- TODO()
- apply()
- use()
- Conclusion
- To go further:
- Nicolas Fränkel
- Kotlin
- Using Kotlin on the SAP Hybris platform
- Making the most out of conferences
- Idioms
- Create DTOs (POJOs/POCOs)
- Default values for function parameters
- Filter a list
- Check the presence of an element in a collection
- String interpolation
- Instance checks
- Read-only list
- Read-only map
- Access a map entry
- Traverse a map or a list of pairs
- Iterate over a range
- Lazy property
- Extension functions
- Create a singleton
- Instantiate an abstract class
- If-not-null shorthand
- If-not-null-else shorthand
- Execute a statement if null
- Get first item of a possibly empty collection
- Execute if not null
- Map nullable value if not null
- Return on when statement
- try-catch expression
- if expression
- Builder-style usage of methods that return Unit
- Single-expression functions
- Call multiple methods on an object instance (with)
- Configure properties of an object (apply)
- Java 7’s try-with-resources
- Generic function that requires the generic type information
- Nullable Boolean
- Swap two variables
- Mark code as incomplete (TODO)
- What’s next?
- Что такое todo kotlin
Make your life easier with Kotlin stdlib
IMHO, Kotlin is not about big killer features — although extension methods and properties could certainly be categorized as such, but about a bunch of small improvements that have deep impact. Most of them are not built-in into the language, but are functions offered as part of the Kotlin standard library. In this post, I’d like to go through a limited set of them, and describe how they can be used to improve the code.
TODO()
It’s quite common to have //TODO comments in a new codebase. For most of us developers, it might even be a reflex. When the flow comes in, don’t stop because of a lack of specification, but write down a reminder to get back to it later. Whatever later means. Even IDEs happily generate code with such comments.
fun computeCustomerNumber(customer: Customer): String // TODO Not specified as of November 27th >
Yet, no problem occurs when the actual code is run. Nothing happens, nothing to really remind us that piece should be implemented. Of course, some code analysis tools might uncover it, but it might already be too late. And it requires the tool to actually be run.
Kotlin provides the TODO() function, that actually throws an exception when it’s called. This way, even running a simple unit test will forcibly point you to the fact there’s something to be done there.
fun computeCustomerNumber(customer: Customer): String TODO("Not specified as of November 27th") >
apply()
Depending on an API specifics, constructing some objects might be rather tedious, and involve a lot of details. To hide those details, the current consensus is generally to create a method out of it. Here’s a snippet to create a combo-box component for the Vaadin web framework:
fun createCountriesCombo(): ComboBoxString> val countries = ComboBoxString>("Countries") countries.setItems("Switzerland", "France", "Germany", "Austria") countries.isEmptySelectionAllowed = false countries.placeholder = "Choose your country" countries.addValueChangeListener val country = countries.value bus.post(CountryChangeEvent(country)) > return countries >
Even then, depending on the amount of properties to set, it’s easy to get lost in the details. apply() is a simple function, defined as:
fun T> T.apply(block: T.() -> Unit): T block(); return this >
It means this function can be called on any type T , and its only argument is a lambda receiver, that returns nothing. As for any lambda receiver, this inside the lambda refers to the object the function is called on. This let us refactor the above snippet into the following:
fun createCountriesCombo(): ComboBoxString> val countries = ComboBoxString>("Country").apply setItems("Switzerland", "France", "Germany", "Austria") isEmptySelectionAllowed = false placeholder = "Choose your country" addValueChangeListener bus.post(CountryChangeEvent(value)) > > >
Even better, the snippet can be now be easily refactored to take advantage of expression body:
fun createCountriesCombo() = ComboBoxString>("Country").apply setItems("Switzerland", "France", "Germany", "Austria") isEmptySelectionAllowed = false placeholder = "Choose your country" addValueChangeListener bus.post(CountryChangeEvent(value)) > >
Icing on the cake, with any IDE worth its salt, folding may be used to display the overview, and unfolding to reveal the details.
use()
Before Java 7, the closing of a connection had to be explicitly done in a finally block:
Connection conn = getConnection(); try // Do stuff with the connection > finally if (conn != null) conn.close(); > >
Java 7 added the try-with-resource syntax. For example, the previous snippet can refactored into this one:
try (Connection conn = getConnection()) // Do stuff with the connection >
The try-with-resource syntax greatly simplifies the code. However, it’s part of the language syntax and thus carries a lot of implicitness:
- The type in the resource statement must implement AutoCloseable .
- There can be multiple resources opened in the same statement. In that case, they are closed in the reversed order they were opened.
- If an exception is thrown in the try block and also during the closing of the resource(s), the latter is suppressed and set to the main exception.
The Kotlin counterpart is handled through the use function, whose signature is:
fun T : Closeable, R> T.use(block: (T) -> R): R
No black magic involved. It’s a simple function, and its source code is available online.
Conclusion
Those are only a sample of what is available. In general, the syntax of languages can be learned in 21 days (or probably even less). However, it takes a lot more time to know the API.
Kotlin is less about the syntax and more about the API.
To go further:
Nicolas Fränkel
Developer Advocate with 15+ years experience consulting for many different customers, in a wide range of contexts (such as telecoms, banking, insurances, large retail and public sector). Usually working on Java/Java EE and Spring technologies, but with focused interests like Rich Internet Applications, Testing, CI/CD and DevOps. Also double as a trainer and triples as a book author.
Kotlin
Using Kotlin on the SAP Hybris platform
Since I discovered Kotlin, I use it in all my personal projects. I’ve become quite fond of the language, and with good reason. However, there’s yet no integration with the Hybris platform — though there’s with Groovy and Scala. This post aims at achieving just that, to be able to use Kotlin on Hybris projects. Generate a new extension The first step on the journey is to create a new extension: ant extgen Choose the yempty packageChoose an adequate name, e.g. ‘kotlinfun’
Nicolas Fränkel
Making the most out of conferences
This week was my last conference of 2017, Voxxed Day Thessaloniki organized by my good friend Patroklos. I started going to conferences some years ago. Going to a conference is an investment, whether in time or in money — or in both. You should me make sure to get the most out of that investment. In this post, I’d like to write down what I do to achieve that. Plan ahead The first thing to do is to get the list of available talks ahead. Some conferences require attendees to register to
Nicolas Fränkel
Idioms
A collection of random and frequently used idioms in Kotlin. If you have a favorite idiom, contribute it by sending a pull request.
Create DTOs (POJOs/POCOs)
provides a Customer class with the following functionality:
- getters (and setters in case of var s) for all properties
- equals()
- hashCode()
- toString()
- copy()
- component1() , component2() , . for all properties (see Data classes)
Default values for function parameters
Filter a list
Or alternatively, even shorter:
Learn the difference between Java and Kotlin filtering.
Check the presence of an element in a collection
String interpolation
Instance checks
Read-only list
Read-only map
Access a map entry
Traverse a map or a list of pairs
k and v can be any convenient names, such as name and age .
Iterate over a range
for (i in 1..100) < . >// closed-ended range: includes 100 for (i in 1.. <100) < . >// open-ended range: does not include 100 for (x in 2..10 step 2) < . >for (x in 10 downTo 1) < . >(1..10).forEach < . >
Lazy property
Extension functions
Create a singleton
Instantiate an abstract class
If-not-null shorthand
If-not-null-else shorthand
val files = File(«Test»).listFiles() // For simple fallback values: println(files?.size ?: «empty») // if files is null, this prints «empty» // To calculate a more complicated fallback value in a code block, use `run` val filesSize = files?.size ?: run < val someSize = getSomeSize() someSize * 2 >println(filesSize)
Execute a statement if null
Get first item of a possibly empty collection
Execute if not null
Map nullable value if not null
val value = . val mapped = value?.let < transformValue(it) >?: defaultValue // defaultValue is returned if the value or the transform result is null.
Return on when statement
fun transform(color: String): Int < return when (color) < "Red" ->0 «Green» -> 1 «Blue» -> 2 else -> throw IllegalArgumentException(«Invalid color param value») > >
try-catch expression
if expression
Builder-style usage of methods that return Unit
Single-expression functions
This can be effectively combined with other idioms, leading to shorter code. For example, with the when expression:
fun transform(color: String): Int = when (color) < "Red" ->0 «Green» -> 1 «Blue» -> 2 else -> throw IllegalArgumentException(«Invalid color param value») >
Call multiple methods on an object instance (with)
Configure properties of an object (apply)
This is useful for configuring properties that aren’t present in the object constructor.
Java 7’s try-with-resources
val stream = Files.newInputStream(Paths.get(«/some/file.txt»)) stream.buffered().reader().use < reader ->println(reader.readText()) >
Generic function that requires the generic type information
// public final class Gson < // . // public
Nullable Boolean
Swap two variables
Mark code as incomplete (TODO)
Kotlin’s standard library has a TODO() function that will always throw a NotImplementedError . Its return type is Nothing so it can be used regardless of expected type. There’s also an overload that accepts a reason parameter:
IntelliJ IDEA’s kotlin plugin understands the semantics of TODO() and automatically adds a code pointer in the TODO tool window.
What’s next?
- Solve Advent of Code puzzles using the idiomatic Kotlin style.
- Learn how to perform typical tasks with strings in Java and Kotlin.
- Learn how to perform typical tasks with collections in Java and Kotlin.
- Learn how to handle nullability in Java and Kotlin.
Что такое todo kotlin
На этом шаге мы рассмотрим назначение этого типа и функцию TODO .
На предыдущих шагах мы познакомились с типом Unit и узнали, что функции с таким типом ничего не возвращают.
Есть другой тип, похожий на Unit . Это тип Nothing ( Ничего ) . Как и Unit , тип Nothing показывает, что функция ничего не возвращает, но на этом их сходство заканчивается. Nothing говорит компилятору, что функция гарантированно не выполнится успешно; функция либо вызовет исключение, либо по какой-нибудь другой причине никогда не вернет управление вызова.
Зачем нужен тип Nothing ? Одним из примеров использования этого типа может служить функция TODO ( надо сделать ) , которая входит в стандартную библиотеку языка Kotlin .
TODO возбуждает исключение — иначе говоря, функция гарантированно завершится ошибкой — она возвращает тип Nothing .
Когда надо использовать TODO ? Ответ кроется в ее названии: оно говорит вам, что » надо сделать » («to do») . Вот, например, следующая функция, которую еще предстоит реализовать, но пока она просто вызывает TODO :
fun shouldReturnAString(): String < TODO("implement the string building functionality here to return a string") >
Разработчик знает, что функция shouldReturnAString() должна вернуть строку (String) , но пока отсутствуют другие функции, необходимые для ее реализации. Обратите внимание, что возвращаемое значение для shouldReturnAString() — это String , но на самом деле функция ничего не возвращает. Из-за возвращаемого значения TODO это абсолютно нормально.
Возвращаемый тип Nothing у TODO показывает компилятору, что функция гарантированно вызовет ошибку, поэтому проверять возвращаемое значение после TODO не имеет смысла, так как shouldReturnAString() ничего не вернет. Компилятор доволен, а разработчик может продолжать разработку, отложив на потом реализацию функции shouldReturnAString() .
Другая полезная при разработке особенность Nothing заключается в возможности добавить код после вызова TODO . В этом случае компилятор выведет предостережение, что этот код недостижим (рисунок 2).
Благодаря возвращаемому типу Nothing компилятор может сделать следующий вывод: он знает, что TODO завершится с ошибкой, поэтому и весь код после TODO не будет выполнен.
На следующем шаге мы рассмотрим функции уровня файла в Java .