Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Develop your next app with Kotlin - AndroidRennes 2017

Develop your next app with Kotlin - AndroidRennes 2017

My slides for Kotlin night meetup @ AndroidRennes

Arnaud GIULIANI

May 16, 2017
Tweet

More Decks by Arnaud GIULIANI

Other Decks in Technology

Transcript

  1. Limits of java - Verbose - Type inference - No

    properties / Lazy / Delegate - Checked exception - NullPointerException - Extensibility - End of lines with ; @ sdeleuze
  2. But Java is great … - Fast - Optimized bytecode

    - Static typing - Simple to learn - Amazing ecosystem
  3. - Conciseness & Smarter API - Null Safety & Immutability

    protection - Type Inference, Static Typing & Smart Casts - Open programming styles - Java Interop Why Kotlin ?
  4. - Fully open source (built by Jetbrains) - Based on

    Java & run on Java 6+ - Modern language features - 1st grade tooling What’s Kotlin ?
  5. - String templates - Properties - Lambdas - Data class

    - Smart cast - Null safety - Lazy property - Default values for function parameters - Extension Functions - No more ; - Single-expression functions - When expression - let, apply, use, with - Collections - Android Extensions Plugin About Kotlin …
  6. Compare with Same conciseness and expressive code, but Kotlin static

    typing and null-safety make a big difference. "Some people say Kotlin has 80% the power of Scala, with 20% of the features" * 
 "Kotlin is a software engineering language in contrast to Scala which is a computing science language." * Swift and Kotlin are VERY similar. Swift is LLVM based and has C interop while Kotlin is JVM based and has Java interop. * Quotes from Kotlin: The Ying and Yang of Programming Languages @ sdeleuze
  7. KOTLIN is not just about writing your app with lesser

    lines. It’s all about writing SAFER & BETTER APPS !
  8. Clearly considered by all the Java community ! https://spring.io/blog/2017/01/04/introducing-kotlin-support-in- spring-framework-5-0

    http://www.javamagazine.mozaicreader.com/ #&pageSet=5&page=0&contentItem=0 (March/April 2017) https://www.thoughtworks.com/radar/languages-and-frameworks/kotlin
  9. Getting started with gradle buildscript { ext.kotlin_version = '<version to

    use>' dependencies { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } apply plugin: "kotlin" // or apply plugin: "kotlin-android" android { sourceSets {
 main.java.srcDirs += 'src/main/kotlin'
 test.java.srcDirs += 'src/test/kotlin'
 } } dependencies { compile « org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" } * You can now use Kotlin in your grade scripts !
  10. Gradle tips for Kotlin # Gradle
 org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX: +HeapDumpOnOutOfMemoryError

    -Dfile.encoding=UTF-8
 org.gradle.parallel=true org.gradle.deamon=true
 
 # Kotlin
 kotlin.incremental=true
 
 # Android Studio 2.2+
 android.enableBuildCache=true In your gradle.properties https://medium.com/keepsafe-engineering/kotlin-vs-java-compilation-speed-e6c174b39b5d#.k44v7axsk
  11. VAR & VAL val : constant value - IMMUTABLE var

    : variable value - MUTABLE val icon1 : String = "sunny"
 icon1 = "cloudy" // error - val cannot be reassigned
 
 var icon2 = "sunny"
 icon2 = "cloudy" USE VAL AS MUCH AS POSSIBLE ! TYPE INFERENCE
  12. Class class DailyForecastModel(val forecastString: String, 
 val icon: String, 


    val temperatureLow: String, 
 val temperatureHigh: String) Optional body Public/Closed by default val forecast = DailyForecastModel("description ...","sunny-icon","5°C","18°C") POJO + - Getter - Setter - Constructors
  13. Properties class DailyForecastModel(val forecastString: String,
 val icon: String,
 val temperatureLow:

    String,
 val temperatureHigh: String) {
 
 val temperatureString = "$temperatureLow°C - $temperatureHigh°C"
 
 } val forecast = ...
 println("temperature is ${forecast.temperatureString}") Property access & string template val property = read only property !
  14. Data Class data class DailyForecastModel(val forecastString: String,
 val icon: String,


    val temperatureLow: String,
 val temperatureHigh: String) POJO + - Getter - Setter - Constructors - toString - hashcode - equals - copy
  15. data class DailyForecastModel(val forecastString: String, 
 val icon: String, 


    val temperatureLow: String, 
 val temperatureHigh: String) Kotlin public class DailyForecastModel {
 
 private String forecast;
 private String icon;
 private String temperatureLow;
 private String temperatureHigh;
 
 /**
 * Business Getter
 */
 public String getTemperatureString() {
 return temperatureLow + "°C - " + temperatureHigh + "°C";
 }
 
 /**
 * Business Getter
 */
 public String getForecastString() {
 return forecast;
 }
 
 
 public DailyForecastModel() {
 }
 
 public DailyForecastModel(String forecast, String icon, String temperatureLow, String temperatureHigh) {
 this.forecast = forecast;
 this.icon = icon;
 this.temperatureLow = temperatureLow;
 this.temperatureHigh = temperatureHigh;
 }
 
 
 public String getForecast() {
 return forecast;
 }
 
 public void setForecast(String forecast) {
 this.forecast = forecast;
 }
 
 public String getIcon() {
 return icon;
 }
 
 public void setIcon(String icon) {
 this.icon = icon;
 }
 
 public String getTemperatureLow() {
 return temperatureLow;
 }
 
 public String getTemperatureHigh() {
 return temperatureHigh;
 }
 
 @Override
 public boolean equals(Object o) {
 if (this == o) return true;
 if (o == null || getClass() != o.getClass()) return false;
 
 DailyForecastModel that = (DailyForecastModel) o;
 
 if (forecast != null ? !forecast.equals(that.forecast) : that.forecast != null)
 return false;
 if (icon != null ? !icon.equals(that.icon) : that.icon != null) return false;
 if (temperatureLow != null ? !temperatureLow.equals(that.temperatureLow) : that.temperatureLow != null)
 return false;
 return temperatureHigh != null ? temperatureHigh.equals(that.temperatureHigh) : that.temperatureHigh == null;
 
 }
 
 @Override
 public int hashCode() {
 int result = forecast != null ? forecast.hashCode() : 0;
 result = 31 * result + (icon != null ? icon.hashCode() : 0);
 result = 31 * result + (temperatureLow != null ? temperatureLow.hashCode() : 0);
 result = 31 * result + (temperatureHigh != null ? temperatureHigh.hashCode() : 0);
 return result;
 }
 
 @Override
 public String toString() {
 return "DailyForecastModel{" +
 "forecast='" + forecast + '\'' +
 ", icon='" + icon + '\'' +
 ", temperatureLow='" + temperatureLow + '\'' +
 ", temperatureHigh='" + temperatureHigh + '\'' +
 '}';
 }
 }
 Java
  16. VAR & VAL val forecast1 = DailyForecastModel("description … »,"sunny-icon","5°C","18°C") var

    forecast2 = DailyForecastModel("description … »,"sunny-icon","5°C","18°C") forecast1 = DailyForecastModel("description … »,"sunny-icon","5°C","18°C") // error : val cannot be reassigned 
 forecast2 = DailyForecastModel("description …","sunny-icon","5°C","18°C")
 Use Immutable Value Objects !
  17. Methods & Functions fun reformat(str: String,
 normalizeCase: Boolean = true,


    upperCaseFirstLetter: Boolean = true,
 wordSeparator: Char = ' ') : String {
 
 } - Parameters are IMMUTABLE (considered as VAL) - Parameter has a NAME & can have DEFAULT VALUE - Return type can be optional (single expression) reformat(str, true, true, '_') // old way to call
 reformat(str, wordSeparator = '_') // using default values & named params
  18. No static, use Object object WeatherSDKUtil {
 
 fun extractLocation(geocode:

    Geocode): Location = ...
 
 fun getDailyForecasts(weather: Weather): List<DailyForecastModel> {
 ...
 }
 } Singleton Class data class DailyForecastModel(val forecastString: String, val icon: String, val temperatureLow: String, val temperatureHigh: String) {
 
 val temperatureString = "$temperatureLow°C - $temperatureHigh°C"
 
 companion object{
 
 fun sunnyDay() = DailyForecastModel("It's a good day today !","sunny","16°C","25°C")
 
 }
 } Companion Object
  19. Null Safety val forecast1 : DailyForecastModel? = DailyForecastModel("description ...","sunny-icon","5°C","18°C")
 val

    forecast2 : DailyForecastModel? = null 
 val forecast : DailyForecastModel = null // Error because type is a non- null type val forecast : DailyForecastModel? = … - Nullable type : accept null value - Type is nullable when followed by ? You must use proper operators with nullable types !
  20. Safe Calls with ?. val forecast : DailyForecastModel? = DailyForecastModel("description

    ...","sunny- icon","5°C","18°C")
 val myIcon: String? = forecast?.icon Nullable Type Operators fun extractLocation(geocode: Geocode): Location? = geocode?.geometry?.location Exploring safely objects val forecast : DailyForecastModel? = DailyForecastModel("description ...","sunny-icon","5°C","18°C")
 
 if (forecast != null){
 // forecast is now type DailyForecastModel
 val icon : String = forecast.icon
 } if-non-null checks & smart casts
  21. Collections val list = listOf("a", "b", « c","aa") val map

    = mapOf("a" to 1, "b" to 2, "c" to 3) list.filter { it.startsWith("a") } Collections operators with lambdas : map, filter, take, flatMap, forEach, firstOrNull, last … - Based on Java Collections, but add some smart API - Mutable / Immutable Collections // range
 for (i in 1..100) { //... } Range expression for for-loop map["a"] = "my value" // direct map access with array style 
 for ((k, v) in map) {
 println("$k -> $v")
 } Smart accessors
  22. InterOp Java/Kotlin data class DailyForecastModel (...){
 companion object{
 fun sunnyDay(){

    //…
 }
 }
 } DailyForecastModel u = new DailyForecastModel(…);
 DailyForecastModel.Companion.sunnyDay(); fun getDailyForecasts(weather : Weather?){
 …
 } WeatherSDKUtilKt.getDailyForecasts(weather) object WeatherSDKUtil{
 fun extractLocation(geocode : Geocode) …
 } WeatherSDKUtil.INSTANCE.extractLocation(geocode)
  23. Default values with Elvis operator ?: val icon: String =

    if (forecast != null) forecast.icon else "sunny"
 val icon: String = forecast?.icon ?: "sunny" Others Nullable Type Operators val icon: String = forecast!!.icon Explicit (dangerous) non-null call with !!. Safe cast with as? val icon: String? = forecast?.icon as? String fun extractLocation(geocode: Geocode): Location? = geocode.results.firstOrNull()?.geometry?.location Collection with nullable types
  24. Advanced Properties Getter & Setter var temperatureString : String
 get()

    = "temperature is $tempData"
 set(value){
 tempData = value
 } Late Initialization class MainApplication : Application() {
 
 override fun onCreate() {
 ...
 instance = this
 }
 
 companion object {
 
 private lateinit var instance: MainApplication
 
 fun get(): Application {
 return instance
 }
 }
 }
  25. When when (x) {
 1 -> print("x == 1")
 2

    -> print("x == 2")
 else -> { // Note the block
 print("x is neither 1 nor 2")
 }
 } Flow Control (replace your switch and if-blocks) when (x) {
 in 1..10 -> print("x is in the range")
 in validNumbers -> print("x is valid")
 !in 10..20 -> print("x is outside the range")
 else -> print("none of the above")
 } Pattern Matching
  26. Lambdas val fab = findViewById(R.id.fab) as FloatingActionButton
 fab.setOnClickListener { view

    -> popLocationDialog(view) } A lambda expression or an anonymous function is a “function literal”, i.e. a function that is not declared, but passed immediately as an expression - A lambda expression is always surrounded by curly braces - parameters are declared before -> (parameter types may be omitted) - body goes after -> (when present) myNumber.split("\n").flatMap { it.split(separator) }
 .map(Integer::parseInt)
 .map(::checkPositiveNumber)
 .filter { it <= 1000 }
 .sum() Method references are not surrounded by parenthesis !
  27. Extensions Functions Extension declaration package fr.ekito.myweatherlibrary.json.weather
 fun Weather.getDailyForecasts(): List<DailyForecastModel> =

    forecast?.simpleforecast?.forecastday.orEmpty()
 .map { f -> DailyForecastModel(f.conditions!!, getWeatherCode(f.icon!!), f.low!!.celsius!!, f.high!!.celsius!!) }
 .filter { f -> !f.icon.startsWith(PREFIX) }
 .take(4) Old style … val forecasts = WeatherSDKUtil.getDailyForecasts(weather) val forecasts = weather.getDailyForecasts() Using extension
  28. Destructuring Declarations In lambdas, Since Kotlin 1.1 map.mapValues { (key,

    value) -> "$value!" } Destructured variables declaration val (_, _, low, high) = DailyForecastModel("description ...","sunny- icon","5°C","18°C")
 
 println("Today we have $low < $high") Works with Map, Data Class, Pair, Triple …
  29. Kotlin’s Android Extensions apply plugin: 'com.android.application' apply plugin: ‘kotlin-android’ apply

    plugin: ‘kotlin-android-extensions’ // the kotlin-android extension ! In your build.gradle
  30. DSL https://github.com/Kotlin/anko verticalLayout { val name = editText() button("Say Hello")

    { onClick { toast("Hello, ${name.text}!") } } } { ("/blog" and accept(TEXT_HTML)).route { GET("/", this@BlogController::findAllView) GET("/{slug}", this@BlogController::findOneView) } ("/api/blog" and accept(APPLICATION_JSON)).route { GET("/", this@BlogController::findAll) GET("/{id}", this@BlogController::findOne) } } https://spring.io/blog/2017/01/04/introducing-kotlin-support-in-spring-framework-5-0
  31. Our feedback - Easy to start on existing project -

    Great learning curve - Good doc & tools support - Don’t use anymore Butterknife, Dagger … - ⚠ Tests Mocks, Realm DB … - Hard to come back to Java https://www.ekito.fr/people/kotlin-in-production-one-year-later/
  32. - Coroutines - JS Support - New language features (type

    aliases …) - Kotlin Lib update - Java 8 Optimization
  33. - Tech Preview ;) - LLVM Compile (no more JVM)

    - Native library integration - MacOS, Linux, Raspberry Pi
  34. Many well-known companies are using Kotlin: Pinterest, Coursera, Netflix, Uber,

    Square, Trello, Basecamp, amongst others well-known banks (such as Goldman Sachs, Wells Fargo, J.P. Morgan, Deutsche Bank, UBS, HSBC, BNP Paribas, Société Générale)