본문 바로가기

공부방/Kotlin

3. 코틀린에서 Type을 다루는 방법

1. 기본타입


코틀린에서는 선언된 기본값을 보고 타입을 추론한다.

 

fun main() {
	val number1 = 3   // Int
	var number2 = 3L  // Long
}

 

 

자바: 기본 타입간의 변환은 암시적으로


int는 4byte, long은 8byte로 long이 더 크니까 타입 변환이 가능합니다.
int -> long 암시적으로 변경 가능

 

public class Lec03Main {
	public static void main(String[] args) {

		int number1 = 4;
		long number2 = number1;

		System.out.println(number1 + number2);
	}
}

 

코틀린: 기본 타입간의 변환은 명시적으로


반면 코틀린은 암시적으로 타입 변환이 불가능합니다.

아래와 같은 코드를 작성하게 되면 type mismatch 문제가 발생하게 됩니다.

 

 

코틀린에는 to____ 라는 메서드가 많은데, 이를 이용해서 문제를 해결할 수 있습니다.

 

fun main() {
	val number1: Int
	val number2: Long;

	number1 = 4;
	number2 = number1.toLong();
}

 

변수가 nullable이라면 적절한 처리가 필요합니다.

 

 

Safe call과 Elvis 연산자를 적절하게 섞어서 사용하면 됩니다.

 

fun main() {
	val number1: Int? = 4;
	val number2: Long = number1?.toLong() ?: 0L 
}

 

2. 일반 타입에 대한 타입 캐스팅

 

name과 age를 갖는 person이 있습니다.

 

public class Person {

	private final String name;
	private final int age;

	public Person(String name, int age) {
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public int getAge() {
		return age;
	}
}

 

아래와 같이 object의 type을 확인하고 person 객체인 경우에 추가 로직이 있는 코드는 어떻게 처리할까요?

 

 

public class Lec03Main {
	public static void printAgeIfPerson(Object obj) {
		if (obj instanceof Person) {
			Person person = (Person) obj;
			System.out.println(person.getAge());
		}
	}
}

 

fun pringAgeIfPerson(obj: Any) {
	// instance of
	if (obj is Person) {
		// type 변환
		val person = obj as Person
		println(person.age)
	}
}

 

사실 as Person으로 타입 변환 하는 것은 필요없는 코드입니다.

if 문에서 type check를 하게되면, 코틀린에서 이미 타입을 알게 되기 때문입니다.

 

fun pringAgeIfPerson(obj: Any) {
	// instance of
	if (obj is Person) {		
		println(person.age)
	}
}

 

!is

obj가 Person이 아닌 경우에 대한 처리는 어떻게 할 수 있을까요?

!is 라는 문법이 존재합니다.

 

fun pringAgeIfPerson(obj: Any) {
	// instance of
	if (obj !is Person) {
		// Person이 아닌 경우에 대한 처리
	}
}

 

만약 obj에도 null이 들어올 수 있다면 어떻게 처리해야 할까요?

 

fun main() {
	pringAgeIfPerson(null)
}

fun pringAgeIfPerson(obj: Any?) {
	val person = obj as Person
	println(person.age)
}

 

obj 변수는 Any? 타입으로 null을 받아들일 수 있는 상태입니다.

하지만 person으로 타입 캐스팅을 하는 과정에서는 null 에 대한 처리가 없었고, 이로 인해 person.age를 호출하였을 때 NPE가 발생하게 됩니다.

 

fun main() {
	pringAgeIfPerson(null)
}

fun pringAgeIfPerson(obj: Any?) {
	val person = obj as? Person // person은 Person? 타입이 된다.
	println(person?.age) // Safe call을 이용해서 null인 경우에는 null이 return 됨
}

 

 

 

 

3. Kotlin의 특이한 타입  - Any


  • Java의 Object 역할 (모든 객체의 최상위 타입)
  • 모든 Primitive Type의 최상위 타입도 Any이다.
    • java는 Primitive Type의 최상위 타입은 Object가 아닙니다.
  • Any 자체로는 null을 포함할 수 없어 null을 포함하고 싶다면, Any?로 표현해야합니다.
  • Any에 equals / hashCode / toString 존재.

 

4. Kotlin의 특이한 타입  - Unit


  • Java의 void와 유사한 역할
  • void와 다르게 Unit은 그 자체로 타입 인자로 사용 가능하다.
  • 함수형 프로그래밍에서 Unit은 단 하나의 인스턴스만 갖는 타입을 의미. 즉 코틀린의 Unit은 실제 존재하는 타입이라는 것을 표현

 

5. Kotlin의 특이한 타입  - Nothing


  • 함수가 정상적으로 끝나지 않았다는 사실을 표현하는 역할
  • 무조건 예외를 반환하는 함수 / 무한 루프 함수 등

 

6. String interpolation / String indexing


일반적으로 자바에서 문자열 조작을 할때는 Stringbuilder나 String.format을 사용합니다.

 

public class Lec03Main {
	public static void main(String[] args) {
		Person person = new Person("테스트", 100);
		String log = String.format("사람의 이름은 %s이고 나이는 %s세 입니다", person.getName(), person.getAge());

		StringBuilder builder = new StringBuilder();
		builder.append("사람의 이름은");
		builder.append(person.getName());
		builder.append("이고 나이는");
		builder.append(person.getAge());
		builder.append("세 입니다");
		
	}
}

 

코틀린에서는 어떻게 사용할까요?

 

fun main() {
	val person = Person("테스트", 100) 
	val log = "사람의 이름은 ${person.name}이고 나이는 ${person.age}세 입니다"
}

 

멀티라인 입력하는 경우

 

fun main() {
	pringAgeIfPerson(null)

	val person = Person("테스트", 100)
	val log = "사람의 이름은 ${person.name}이고 나이는 ${person.age}세 입니다"

	val str = """
		ABC
		DEF
		GHI
		${person.name}
	""".trimIndent()
	println(str);
}

 

문자열 출력도 다음과 같이 편리하게 할 수 있다.

 

fun main() {
	val str2 = "ABC"
	println(str[0])
}