기본 요소: 함수 및 변수
안녕하세요 세계!
fun main(args: Array<String>) {
println("Hello, world!")
}
간단한 코드에서 Kotlin의 많은 기능을 볼 수 있습니다.
- 함수를 선언할 때 fun 키워드를 사용하십시오.
- 매개변수 이름 뒤에 매개변수 유형을 씁니다.
- 함수는 최상위 수준에서 정의할 수 있습니다. Java와 달리 클래스에 함수를 넣을 필요가 없습니다.
- 배열은 일반 클래스와 같습니다. Java와 달리 Kotlin에는 배열을 처리하기 위한 모든 구문이 없습니다.
- System.out.println 대신 println을 작성하십시오. Kotlin 표준 라이브러리는 깔끔한 사용을 위해 많은 표준 Java 라이브러리 함수에 대한 래퍼를 제공합니다. println은 그러한 기능 중 하나입니다.
- 최신 프로그래밍 언어의 추세와 마찬가지로 줄 끝에 세미콜론(;)을 넣을 필요가 없습니다.
기능
fun max(a : Int, b : Int) : Int {
return if (a > b) a else b
}
함수 선언은 fun 키워드로 시작합니다. Fun 뒤에는 함수 이름이 옵니다. 예를 들어 max라는 함수가 있는데 함수 이름 뒤에는 괄호 안에 매개변수 목록이 옵니다. 함수의 반환 유형은 매개변수 목록의 닫는 괄호 다음에 오며 괄호와 반환 유형은 콜론(:)으로 구분해야 합니다.
함수를 보다 간결하게 표현할 수 있습니다.
fun max(a : Int, b : Int) : Int = if(a > b) a else b
중괄호를 제거하고 줄 바꿈을 제거하고 표현식 앞에 등호를 추가하여 함수를 보다 간결하게 표현할 수 있습니다.
중괄호로 묶인 함수의 본문 본문이 블록인 함수등호와 표현식으로 구성된 함수 본문이 표현식인 함수그것은이라고.
Kotlin에서 함수는 종종 표현 본문으로 사용됩니다. 간단한 산술 식이나 함수 호출 식 외에도 이러한 함수의 본문 식에는 if, when 및 try와 같은 보다 복잡한 식을 포함하는 경우가 많습니다. 반환 유형을 생략하면 max 함수를 더 간결하게 만들 수 있습니다.
fun max(a : Int, b : Int) = if(a > b) a else b
Kotlin은 정적으로 유형이 지정되는 언어이므로 컴파일 시간에 각 표현식을 입력해야 하지 않나요? 사실 모든 변수나 식에는 유형이 있고 모든 함수에는 고정된 반환 유형이 있어야 합니다. 그러나 표현식 본문이 있는 함수의 경우 사용자가 반환 유형을 작성하지 않아도 컴파일러에서 함수 본문 표현식을 구문 분석하고 표현식의 결과 유형을 함수 반환 유형으로 설정합니다.
실제 프로그램에서 매우 긴 함수에는 종종 여러 개의 반환 문이 포함됩니다. 이러한 경우 반환 유형을 지정했는지 확인하고 return을 사용하여 함수가 반환하는 값의 종류와 반환 위치를 확인합니다.
변하기 쉬운
val question = "삶, 우주, 그리고 모든 것에 대한 궁극적인 질문"
val answer = 42 // 타입 생략
val answer: Int = 42 // 타입 명시
본문이 식인 함수와 마찬가지로 형식이 지정되지 않은 경우 컴파일러는 초기화 식을 구문 분석하고 초기화 식의 형식을 변수 형식에 할당합니다. 여기서 초기화 표현식은 int 유형인 42입니다. 변수도 Int 유형입니다.
val yearsToCompute = 7.5e6 // 부동소수점 상수를 사용한다면 변수 타입은 Double이 된다.
초기화 표현식을 사용하지 않고 변수를 선언하려면 변수 유형을 지정해야 합니다.
val answer : Int
answer = 42
가변 및 불변 변수
- val(값을 의미하는 값에서 파생됨) – 변경할 수 없는 참조를 저장하는 변수입니다. val로 선언된 변수는 초기화 후에 재할당할 수 없습니다. Java 용어로 최종 변수에 해당합니다.
- var (from variable, 의미 변수) – 변경 가능한 참조. 이러한 변수의 값은 변경될 수 있습니다. Java의 일반 변수에 해당합니다.
val 변수는 블록이 실행될 때 정확히 한 번 초기화되어야 합니다. 그러나 블록이 실행될 때 하나의 초기화 문만 실행된다는 것을 컴파일러가 확인할 수 있다면 조건에 따라 val의 값을 여러 가지 다른 값으로 초기화할 수 있다.
val message : String
if(canPerformOperation()) {
message = "Success" // ...연산을 수행한다.
} else {
message = "Failed"
}
val 참조 자체는 변경할 수 없지만 그것이 가리키는 개체의 내부 값은 변경될 수 있습니다.
val languages = arrayListOf("Java")
languages.add("Kotlin")
var 키워드를 사용하여 변수 값을 변경할 수 있지만 변수 유형은 고정되어 변경되지 않습니다.
var answer = 42
answer = "no answer" // 컴파일 오류 발생
한 유형의 변수에 다른 유형의 값을 저장하려면 변환 함수를 사용하여 값을 변수의 유형으로 변환하거나 값을 변수에 할당할 수 있는 유형으로 변환해야 합니다.
더 쉬운 문자열 서식 지정: 문자열 템플릿
fun main(args: Array<String>) {
val name = if (args.size > 0) args(0) else "Kotlin"
println("Hello, $name")
}
문자열 리터럴에서 필요한 곳에 변수를 배치하되 변수 앞에 $를 추가해야 합니다.
문자열에 $ 문자를 삽입하려면 println(“\$x”)과 같이 \를 사용하여 $를 이스케이프해야 합니다. 이 경우 x 값을 인쇄하는 대신 $x를 인쇄하십시오.
클래스 및 속성
// Java
public class Person {
private final String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Java Kotlin 변환기를 사용하여 Person 클래스를 Kotlin으로 변환해 보겠습니다.
class Person(val name: String)
자바를 코틀린으로 변환한 결과 공개 가시성 수식어가 사라진 것을 확인했다. Kotlin의 기본 가시성은 공개이므로 이 경우 수정자를 생략할 수 있습니다.
재산
Java에서는 필드와 접근자를 그룹화하여 속성이라고 하며 속성 개념을 사용하는 많은 프레임워크가 있습니다. Kotlin은 언어의 기본 기능으로 속성을 제공하며 Kotlin 속성은 Java의 필수 접근자를 완전히 대체합니다.
class Person(
val name: String, // 읽기 전용 프로퍼티로, 코틀린은 (비공개) 필드와 필드를 읽는 단순한 (공개) 게터를 만들어 낸다.
var isMarried: Boolean // 쓸 수 있는 프로퍼티로, 코틀린은 (비공개)필드, (공개) 게터, (공개) 세터를 만들어 낸다.
)
Kotlin은 값을 저장하는 전용 필드, 필드에 값을 저장하는 setter 및 필드 값을 읽는 getter로 구성된 간단한 기본 접근자 구현을 제공합니다.
Kotlin 소스 코드 구조: 디렉토리 및 패키지
Kotlin에서는 클래스 가져오기와 함수 가져오기 사이에 차이가 없으며 import 키워드를 사용하여 모든 선언을 가져올 수 있습니다. 최상위 함수는 이름으로 가져올 수 있습니다.
package geometry.example
import geometry.shapes.createRandomRectangle // 이름으로 함수 임포트하기
fun main(args: Array<String>) {
println(createRandomRectangle().isSquare) // "true"가 아주 드물게 출력된다.
}
선택 표현 및 처리: enum 및 when
When은 Java의 스위치를 대체하지만 훨씬 더 강력하며 향후 더 많이 사용되는 프로그래밍 요소로 간주될 수 있습니다.
열거형 클래스 정의
Kotlin에서 enum은 소위 soft 키워드입니다. Java와 마찬가지로 열거형은 값의 열거형이 아닙니다. 열거형 클래스에서 속성이나 메서드를 정의할 수도 있습니다.
enum class Color(val r: Int, val g: Int, val b: Int) { // 상수의 프로퍼티를 정의한다.
RED(255, 0, 0), ORANGE(255, 165, 0), // 각 상수를 생성할 때 그에 대한 프로퍼티 값을 지정한다.
YELLOW(255, 255, 0), GREEN(0, 255, 0), BLUE(0, 0, 255),
INDIGO(75, 0, 130), VIOLET(238, 130, 238); // 여기에 반드시 세미콜론을 사용해야 한다.
fun rgb() = (r * 256 + g) * 256 + b // enum 클래스 안에서 메서드를 정의한다.
}
열거형 클래스 내에서 메서드를 정의할 때 열거형 상수 목록과 메서드 정의 사이에 세미콜론을 포함해야 합니다.
when을 사용하여 열거형 클래스 처리
fun getMnemonic(color: Color) =
when (color) {
Color.RED -> "Richard"
Color.ORANGE -> "Of"
Color.YELLOW -> "York"
Color.GREEN -> "Gave"
Color.BLUE -> "Battle"
Color.INDIGO -> "In"
Color.VIOLET -> "Vain"
}
Java의 Switch와 달리 필요하지 않은 경우 중단합니다. 분기 내에서 일치 패턴으로 여러 값을 사용할 수도 있습니다. 이 경우 값을 쉼표(,)로 구분합니다.
when을 사용하여 열거형 클래스 처리
When in Kotlin은 Java의 스위치보다 훨씬 강력합니다. 분기 조건에 상수만 사용할 수 있는 Java 스위치와 달리 Kotlin은 분기 조건에 임의의 객체를 허용합니다.
fun mix(c1: Color, c2: Color) =
when (setOf(c1, c2)) {
// when 식의 인자로 아무 객체나 사용할 수 있다. when은 이렇게 인자로 받은 객체가 각 분기 조건에 있는
// 객체와 같은지 테스트한다.
setOf(RED, YELLOW) -> ORANGE
setOf(YELLOW, BLUE) -> GREEN
setOf(BLUE, VIOLET) -> INDIGO
else -> throw Exception("Dirty color") // 매치되는 분기 조건이 없으면 이 문장을 실행한다.
}
Kotlin 표준 라이브러리에는 인수로 전달된 여러 개체를 해당 개체를 포함하는 집합인 집합 개체로 변환하는 setof라는 함수가 있습니다. 집계는 각 항목의 순서가 중요하지 않은 항목 모음입니다.
인수 없이 when 사용
이 함수가 호출될 때마다 함수 인수로 지정된 두 색상이 when 분기 조건의 다른 두 색상과 같은지 여부를 비교하기 위해 여러 Set 인스턴스를 만듭니다. 일반적으로 이러한 비효율성은 큰 문제가 아닙니다. 그러나 이 함수가 매우 자주 호출되는 경우 불필요한 가비지 개체의 성장을 방지하기 위해 다시 작성하는 것이 좋습니다. 인수가 없는 when 식을 사용하면 불필요한 개체 생성을 방지할 수 있습니다.
fun mixOptimized(c1: Color, c2: Color) =
when { // when에 아무 인자도 없다.
(c1 == RED && c2 == YELLOW) ||
(c1 == YELLOW && c2 == RED) ->
ORANGE
(c1 == YELLOW && c2 == BLUE) ||
(c1 == BLUE && c2 == YELLOW) ->
GREEN
(c1 == BLUE && c2 == VIOLET) ||
(c1 == VIOLET && c2 == BLUE) ->
INDIGO
else -> throw Exception("Dirty color")
}
추가 개체를 만들지 않는 장점이 있지만 읽기가 어렵습니다.
스마트 캐스트: 유형 검사와 유형 캐스팅의 조합
fun eval(e: Expr): Int {
if (e is Num) {
val n = e as Num
return n.value
}
if (e is Sum) {
return eval(e.right) + eval(e.left)
}
throw IllegalArgumentException("Unknown expression")
}
Kotlin에서는 변수 유형을 확인하는 데 사용됩니다. is 검사는 Java의 instanceof와 유사합니다. 그러나 Java에서 instanceof를 사용하여 변수의 유형을 확인한 후 해당 유형에 속하는 요소에 액세스하려면 변수 유형을 명시적으로 캐스팅해야 합니다. Kotlin에서는 프로그래머 대신 컴파일러가 캐스팅을 수행합니다. 변수가 원하는 유형인지 확인한 후에는 변수를 원하는 유형으로 캐스팅하지 않고도 변수가 처음부터 원하는 유형으로 선언된 것처럼 사용할 수 있습니다. 이것을 스마트캐스트라고 합니다.
리팩토링: if by when 변경
Java와 달리 Kotlin에는 if가 값을 생성하기 때문에 삼항 연산자가 없습니다.
fun eval(e: Expr): Int =
if (e is Num) {
e.value
} else if (e is Sum) {
eval(e.right) + eval(e.left)
} else {
throw IllegalArgumentException("Unknown expression")
}
이전에 논의된 값 같음 검사 이외의 함수에 표현식을 사용할 수 있는 경우.
fun eval(e: Expr): Int =
when (e) {
is Num ->
e.value
is Sum ->
eval(e.right) + eval(e.left)
else ->
throw IllegalArgumentException("Unknown expression")
}
대상 반복: While 및 For 루프
Kotlin의 while 루프는 Java와 유사합니다. for는 Java의 for-each 루프에 해당하는 형식으로만 존재합니다.
숫자에 대한 반복: 범위 및 시퀀스
fun main(args: Array<String>) {
for (i in 100 downTo 1 step 2) {
print(fizzBuzz(i))
}
}
여기서 우리는 증가하는 값의 순서를 단계별로 반복합니다. 증분 값을 사용하여 숫자를 건너뛸 수 있습니다. 증분 값을 음수로 설정하면 정방향 시퀀스 대신 역방향 시퀀스를 생성할 수 있습니다. 이 예에서 100 downTo 1은 역방향 시퀀스를 만듭니다.
범위를 생성하려면 until 함수를 사용할 수 있습니다. 루프 for(x in 0 to size)는 for(x in 0..size-1)과 동일하지만 개념을 더 명확하게 표현합니다.
맵을 반복
import java.util.TreeMap
fun main() {
val binaryReps = TreeMap<Char, String>()
for (c in 'A'..'F') {
val binary = Integer.toBinaryString(c.toInt())
binaryReps(c) = binary // c를 키로 c의 2진 표현을 맵에 넣는다.
}
for ((letter, binary) in binaryReps) {
println("$letter = $binary")
}
}
fun main() {
val list = arrayListOf("10", "11", "1001")
for ((index, element) in list.withIndex()) {
println("$index: $element")
}
}
인덱스를 저장하고 루프에서 매번 해당 변수를 증가시키기 위해 변수를 별도로 선언할 필요가 없습니다.
in을 사용하여 컬렉션 또는 범위의 항목을 검사합니다.
in 연산자를 사용하여 값이 범위에 있는지 여부를 테스트할 수 있습니다. 반대로 !in을 사용하여 값이 범위를 벗어났는지 확인할 수 있습니다.
fun recognize(c: Char) = when (c) {
in '0'..'9' -> "It's a digit!"
in 'a'..'z', in 'A'..'Z' -> "It's a letter!"
else -> "I don't know…"
}
Kotlin의 예외 처리
Kotlin의 예외 처리는 Java 및 기타 언어의 예외 처리와 유사합니다. 함수는 정상적으로 종료될 수 있지만 오류가 발생하면 예외가 발생할 수 있습니다.
val percentage =
if (number in 0..100)
number
else
throw IllegalArgumentException(
"A percentage value must be between 0 and 100: $number")
시도하다, 잡다, 마침내
Java에서와 마찬가지로 try, catch 및 finally 절을 함께 사용하여 예외를 처리합니다. Java 코드와의 주요 차이점은 코드에 throws 절이 포함되어 있지 않다는 점입니다. Java로 함수를 작성할 때 함수 선언 뒤에 throws IOException을 추가해야 합니다. 이는 IOException이 확인된 예외이기 때문입니다. Java에서는 확인된 예외를 명시적으로 처리해야 합니다.
try를 표현식으로 사용
fun readNumber(reader : BufferedReader) {
val number = try {
Integer.parseInt(reader.readLine())
} catch (e: NumberFormatException) {
return
}
println(number)
}
if 및 when과 같은 Kotlin의 try 키워드는 표현식입니다. 따라서 try의 값을 변수에 할당할 수 있습니다.
요약
- 함수를 정의할 때 fun 키워드를 사용하십시오. val 및 var는 각각 읽기 전용 및 수정 가능한 변수를 선언하는 데 사용됩니다.
- 문자열 템플릿을 사용하면 문자열을 연결할 필요가 없으므로 코드가 간소화됩니다. 변수 이름 앞에 $를 붙이거나 표현식을 ${expression}과 같이 ${ }로 묶어서 변수 또는 표현식의 값을 문자열에 삽입할 수 있습니다.
- 값 개체 클래스는 Kotlin에서 매우 간결하게 표현할 수 있습니다.
- 다른 언어에도 존재하는 if는 Kotlin의 표현식이며 값을 생성합니다.
- Kotlin은 Java Switch와 비슷하지만 더 강력합니다.
- 변수의 유형이 검증된 후에는 변수를 변환하지 않고도 검증된 유형의 변수로 사용할 수 있습니다. 이러한 경우 컴파일러는 스마트 캐스트를 사용하여 유형을 자동으로 변환합니다.
- for, while 및 do-while 루프는 Java에서 제공하는 동일한 키워드와 기능이 유사합니다. 그러나 Kotlin의 for는 Java의 for보다 더 편리합니다. 특히 Kotlin의 for는 맵을 반복하거나 컬렉션의 요소 및 인덱스를 반복할 때 더 편리합니다.
- 1..5와 같은 표현식은 범위를 생성합니다. 범위와 시퀀스는 Kotlin에서 동일한 구문을 사용하며 for 루프에 대해 동일한 추상화를 제공합니다. in 또는 !in을 사용하여 값이 범위 내에 있는지 여부를 테스트합니다.
- Kotlin 예외 처리는 Java와 유사합니다. 그러나 Kotlin에서는 함수가 던질 수 있는 예외를 선언할 필요가 없습니다.
![[Java] 팩토리얼 계산하는 코드 [Java] 팩토리얼 계산하는 코드](https://good.dailygagu.kr/wp-content/plugins/contextual-related-posts/default.png)