왜 Kotlin입니까? Java 개발자가 전환하도록 설득 할 수있는 8 가지 기능

2016 년에 공식적으로 출시 된 Kotlin은 특히 Google이 Android 플랫폼에서 Java의 대안으로 Kotlin에 대한 지원을 발표 한 이후로 최근 몇 년 동안 많은 관심을 끌었습니다. Kotlin을 Android에서 선호하는 언어로 만들기로 최근 발표 된 결정에 따라 새로운 프로그래밍 언어를 배울 때가되었는지 궁금 할 것입니다. 이 경우이 기사가 결정하는 데 도움이 될 수 있습니다.

Kotlin의 출시 내역

Kotlin은 2011 년에 발표되었지만 첫 번째 안정적인 릴리스 인 1.0 버전은 2016 년까지 출시되지 않았습니다. 언어는 무료이며 오픈 소스이며, Andrey Breslav가 수석 언어 디자이너로 일하면서 JetBrains가 개발했습니다. Kotlin 1.3.40은 2019 년 6 월에 출시되었습니다.

Kotlin 정보

Kotlin은 객체 지향 및 함수 프로그래밍 구조를 모두 갖춘 현대적인 정적 인 유형의 프로그래밍 언어입니다. JVM을 포함한 여러 플랫폼을 대상으로하며 Java와 완전히 상호 운용됩니다. 여러면에서 Kotlin은 오늘날 설계 되었다면 Java가 어떻게 보일지 모릅니다. 이 기사에서는 Java 개발자가 발견하게 될 것으로 생각되는 Kotlin의 8 가지 기능을 소개합니다.

  1. 깔끔하고 간결한 구문
  2. 단일 유형 시스템 (거의)
  3. 널 안전
  4. 기능 및 기능 프로그래밍
  5. 데이터 클래스
  6. 확장
  7. 연산자 오버로딩
  8. 최상위 객체와 싱글 톤 패턴

안녕하세요, 세계! Kotlin과 자바

목록 1은 필수 "Hello, world!"를 보여줍니다. Kotlin으로 작성된 함수입니다.

목록 1. "Hello, world!" Kotlin에서

 fun main() { println("Hello, world!") } 

간단하지만이 예제는 Java와의 주요 차이점을 보여줍니다.

  1. main최상위 기능입니다. 즉, Kotlin 함수는 클래스 내에 중첩 될 필요가 없습니다.
  2. public static수정자가 없습니다 . Kotlin에는 가시성 수정자가 있지만 기본값은 public이며 생략 할 수 있습니다. Kotlin은 static수정자를 지원하지 않지만 이 경우 main최상위 수준 함수 이므로 필요하지 않습니다 .
  3. Kotlin 1.3부터에 대한 string-of-strings 매개 변수 main는 필요하지 않으며 사용하지 않는 경우 생략 할 수 있습니다. 필요한 경우 args : Array.
  4. 함수에 대한 반환 유형이 지정되지 않았습니다. Java void가를 사용 하는 경우 Kotlin은를 사용 Unit하며 함수의 반환 유형이 Unit이면 생략 할 수 있습니다.
  5. 이 함수에는 세미콜론이 없습니다. Kotlin에서 세미콜론은 선택 사항이므로 줄 바꿈이 중요합니다.

이것은 개요이지만 Kotlin이 Java와 어떻게 다른지 배우고 많은 경우 개선하는 방법에 대해 더 많이 배울 수 있습니다.

1. 더 깔끔하고 간결한 구문

자바는 너무 장황하다는 비판을받는 경우가 많지만, 특히 소스 코드를 더 이해하기 쉽게 만드는 경우 일부 장황함이 친구가 될 수 있습니다. 언어 디자인의 과제는 명확성을 유지하면서 자세한 내용을 줄이는 것입니다. Kotlin은이 과제를 해결하기 위해 먼 길을 가고 있다고 생각합니다.

Listing 1에서 보았 듯이 Kotlin은 세미콜론이 필요하지 않으며 Unit함수 의 반환 유형을 생략 할 수 있습니다. Kotlin을 자바보다 더 깔끔하고 간결한 대안으로 만드는 데 도움이되는 몇 가지 다른 기능을 고려해 보겠습니다.

유형 추론

Kotlin에서는 변수를로 선언 var x : Int = 5하거나 더 짧지 만 명확한 버전을 사용할 수 있습니다 var x = 5. (Java는 이제 var선언을 지원하지만 해당 기능은 Kotlin에 기능이 나타난 지 한참 후에 Java 10까지 나타나지 않았습니다.)

Kotlin에는으로 val선언 된 자바 변수와 유사한 읽기 전용 변수에 대한 선언도 있습니다 final. 즉, 변수를 다시 할당 할 수 없습니다. 목록 2는 예를 제공합니다.

목록 2. Kotlin의 읽기 전용 변수

 val x = 5 ... x = 6 // ERROR: WILL NOT COMPILE 

속성 대 필드

Where Java has fields, Kotlin has properties. Properties are declared and accessed in a manner similar to public fields in Java, but Kotlin provides default implementations of accessor/mutator functions for properties; that is, Kotlin provides get() functions for val properties and both get() and set() functions for var properties. Customized versions of get() and set() can be implemented when necessary.

Most properties in Kotlin will have backing fields, but it is possible to define a computed property, which is essentially a get() function without a backing field. For example, a class representing a person might have a property for dateOfBirth and a computed property for age.

Default versus explicit imports

Java는 package에 정의 된 클래스를 암시 적으로 가져 java.lang오지만 다른 모든 클래스는 명시 적으로 가져와야합니다. 결과적으로 많은 Java 소스 파일은에서 컬렉션 클래스를 가져오고에서 java.utilI / O 클래스를 가져 오는 것으로 시작 java.io합니다. 기본적으로 코 틀린 암시 적으로 수입 kotlin.*자바 가져 오기 대략 비슷하다, java.lang.*하지만 코 틀린 또한 수입 kotlin.io.*, kotlin.collections.*몇 가지 다른 패키지에서와 클래스. 따라서 Kotlin 소스 파일은 일반적으로 특히 컬렉션 및 / 또는 표준 I / O를 사용하는 클래스의 경우 자바 소스 파일보다 명시적인 가져 오기가 덜 필요합니다.

생성자에 대한 'new'호출 없음

Kotlin에서는 new새 개체를 만드는 데 키워드 가 필요하지 않습니다. 생성자를 호출하려면 클래스 이름을 괄호로 묶으면됩니다. 자바 코드

 Student s = new Student(...); // or var s = new Student(...); 

could be written as follows in Kotlin:

 var s = Student(...) 

String templates

Strings can contain template expressions, which are expressions that are evaluated with results inserted into the string. A template expression starts with a dollar sign ($) and consists of either a simple name or an arbitrary expression in curly braces. String templates can shorten string expressions by reducing the need for explicit string concatenation. As an example, the following Java code

 println("Name: " + name + ", Department: " + dept); 

could be replaced by the shorter but equivalent Kotlin code.

 println("Name: $name, Department: $dept") 

Extends and implements

Java programmers know that a class can extend another class and implement one or more interfaces. In Kotlin, there is no syntactic difference between these two similar concepts; Kotlin uses a colon for both. For example, the Java code

 public class Student extends Person implements Comparable 

would be written more simply in Kotlin as follows:

 class Student : Person, Comparable 

No checked exceptions

Kotlin supports exceptions in a manner similar to Java with one big difference–Kotlin does not have checked exceptions. While they were well intentioned, Java's checked exceptions have been widely criticized. You can still throw and catch exceptions, but the Kotlin compiler does not force you to catch any of them.

Destructuring

Think of destructuring as a simple way of breaking up an object into its constituent parts. A destructuring declaration creates multiple variables at once. Listing 3 below provides a couple of examples. For the first example, assume that variable student is an instance of class Student, which is defined in Listing 12 below. The second example is taken directly from the Kotlin documentation.

Listing 3. Destructuring examples

 val (_, lName, fName) = student // extract first and last name from student object // underscore means we don't need student.id for ((key, value) in map) { // do something with the key and the value } 

'if' statements and expressions

In Kotlin, if can be used for control flow as with Java, but it can also be used as an expression. Java's cryptic ternary operator (?:) is replaced by the clearer but somewhat longer if expression. For example, the Java code

 double max = x >= y ? x : y 

would be written in Kotlin as follows:

val max = if (x >= y) then x else y 

Kotlin is slightly more verbose than Java in this instance, but the syntax is arguably more readable.

'when' replaces 'switch'

My least favorite control structure in C-like languages is the switch statement. Kotlin replaces the switch statement with a when statement. Listing 4 is taken straight from the Kotlin documentation. Notice that break statements are not required, and you can easily include ranges of values.

Listing 4. A 'when' statement in Kotlin

 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") } 

Try rewriting Listing 4 as a traditional C/Java switch statement, and you will get an idea of how much better off we are with Kotlin's when statement. Also, similar to if, when can be used as an expression. In that case, the value of the satisfied branch becomes the value of the overall expression.

Switch expressions in Java

Java 12 introduced switch expressions. Similar to Kotlin's when, Java's switch expressions do not require break statements, and they can be used as statements or expressions. See "Loop, switch, or take a break? Deciding and iterating with statements" for more about switch expressions in Java.

2. Single type system (almost)

Java has two separate type systems, primitive types and reference types (a.k.a., objects). There are many reasons why Java includes two separate type systems. Actually that's not true. As outlined in my article A case for keeping primitives in Java, there is really only one reason for primitive types--performance. Similar to Scala, Kotlin has only one type system, in that there is essentially no distinction between primitive types and reference types in Kotlin. Kotlin uses primitive types when possible but will use objects if necessary.

So why the caveat of "almost"? Because Kotlin also has specialized classes to represent arrays of primitive types without the autoboxing overhead: IntArray, DoubleArray, and so forth. On the JVM, DoubleArray is implemented as double[]. Does using DoubleArray really make a difference? Let's see.

Benchmark 1: Matrix multiplication

In making the case for Java primitives, I showed several benchmark results comparing Java primitives, Java wrapper classes, and similar code in other languages. One of the benchmarks was simple matrix multiplication. To compare Kotlin performance to Java, I created two matrix multiplication implementations for Kotlin, one using Array and one using Array . Listing 5 shows the Kotlin implementation using Array.

Listing 5. Matrix multiplication in Kotlin

 fun multiply(a : Array, b : Array) : Array { if (!checkArgs(a, b)) throw Exception("Matrices are not compatible for multiplication") val nRows = a.size val nCols = b[0].size val result = Array(nRows, {_ -> DoubleArray(nCols, {_ -> 0.0})}) for (rowNum in 0 until nRows) { for (colNum in 0 until nCols) { var sum = 0.0 for (i in 0 until a[0].size) sum += a[rowNum][i]*b[i][colNum] result[rowNum][colNum] = sum } } return result } 

다음으로, 나는 자바의 그것과 두 코 틀린 버전의 성능 비교 double와 자바를 Double내 현재 노트북에 네 개의 벤치 마크를 실행. 각 벤치 마크를 실행할 때 "노이즈"가 적기 때문에 모든 버전을 세 번 실행하고 결과를 평균화했습니다. 결과는 표 1에 요약되어 있습니다.

표 1. 행렬 곱셈 벤치 마크의 런타임 성능

시간이 지정된 결과 (초)
자바

( double)

자바

( Double)

Kotlin

( DoubleArray)

Kotlin

( Array)

7.30 29.83 6.81 15.82

I was somewhat surprised by these results, and I draw two takeaways. First, Kotlin performance using DoubleArray is clearly superior to Kotlin performance using Array, which is clearly superior to that of Java using the wrapper class Double. And second, Kotlin performance using DoubleArray is comparable to--and in this example slightly better than--Java performance using the primitive type double.

Clearly Kotlin has done a great job of optimizing away the need for separate type systems--with the exception of the need to use classes like DoubleArray instead of Array.

Benchmark 2: SciMark 2.0

My article on primitives also included a second, more scientific benchmark known as SciMark 2.0, which is a Java benchmark for scientific and numerical computing available from the National Institute of Standards and Technology (NIST). The SciMark benchmark measures performance of several computational routines and reports a composite score in approximate Mflops (millions of floating point operations per second). Thus, larger numbers are better for this benchmark.

IntelliJ IDEA의 도움으로 SciMark 벤치 마크의 Java 버전을 Kotlin으로 변환했습니다. 하게 IntelliJ IDEA는 자동으로 변환 double[]int[]자바에 DoubleArrayIntArray코 틀린한다. 그런 다음 프리미티브를 사용하는 Java 버전을 DoubleArray및을 사용하는 Kotlin 버전 과 비교했습니다 IntArray. 이전과 마찬가지로 두 버전을 세 번 실행하고 결과를 평균화했습니다. 결과는 표 2에 요약되어 있습니다. 다시 한 번 표는 대략 비슷한 결과를 보여줍니다.

표 2. SciMark 벤치 마크의 런타임 성능

성능 (Mflops)
자바 Kotlin
1818.22 1815.78