목록Kotlin/이펙티브 코틀린 (52)
안드로이드 개발자 노트
연산자 오버로딩은 굉장히 강력한 기능이지만, 위험할 수 있습니다. 예를 들어 팩토리얼을 구하는 함수를 생각해 봅시다. fun Int.factorial(): Int = (1..this).product() fun Iterable.product(): Int = fold(1) { acc, i -> acc * i } 이 함수는 Int로 정의되어 있으므로, 편리하게 사용할 수 있습니다. print(10 * 6.factorial()) // 7200 팩토리얼은 ! 기호를 사용해 표기합니다. 다음과 같이 연산자 오버로딩을 활용하면, 만들어낼 수 있습니다. operator fun Int.not() = factorial() print(10 * !6) // 7200 하지만 함수의 이름이 not이므로 논리연산에 맞게 사용해야지..
"개발자가 코드를 작성하는 데는 1분 걸리지만, 이를 읽는 데는 10분이 걸린다" 프로그래밍은 쓰기보다 읽기가 중요하다는 의미입니다. 항상 가독성을 생각하면서 코드를 작성해야 합니다. 인식 부하 감소 // 구현 A if (person != null && person.isAdult) { view.showPerson(person) } else { view.showError() } // 구현 B person?.takeIf { it.isAdult } ?.let(view::showPerson) ?: view.showError() 구현 A와 구현 B는 비교조차 할 수 없을 정도로 A가 훨씬 가독성이 좋은 코드입니다. 가독성이란 코드를 읽고 얼마나 빠르게 이해할 수 있는지를 의미하며, 이는 얼마나 많은 관용구(구조,..
코드를 안전하게 만드는 가장 궁극적인 방법은 다양한 종류의 테스트를 하는 것입니다. 이러한 종류의 테스트는 사용자의 관점에서 애플리케이션 외부적으로 제대로 작동하는지 확인하는 것이 목표입니다. 단위 테스트는 개발자가 만들고 있는 요소가 제대로 동작하는지를 빠르게 피드백해주므로 개발하는 동안에 큰 도움이 됩니다. 단위 테스트는 일반적으로 다음과 같은 내용을 확인합니다. 일반적인 유스 케이스: 요소가 사용될 거라고 예상되는 일반적인 방법을 테스트한다. 일반적인 오류 케이스와 잠재적인 문제: 제대로 동작하지 않을 거라고 예상되는 일반적인 부분, 과거에 문제가 발생했던 부분 등을 테스트한다. 에지 케이스와 잘못된 아규먼트: Int의 경우 Int.MAX_VALUE를 사용하는 경우, nullable의 경우 'nul..
close 메서드를 사용해서 명시적으로 닫아야 하는 리소스가 있습니다. InputStream과 OutputStream java.sql.Connection java.io.Reader(FileReader, BufferedReader, CSSParser) java.new.Socket과 java.util.Scanner 이러한 리소스들은 AutoCloseable을 상속받는 Closeable 인터페이스를 구현하고 있습니다. // Closeable public interface Closeable extends AutoCloseable { void close() throws IOException; } // AutoCloseable public interface AutoCloseable { void close() thr..
프로퍼티가 null이라는 것은 값이 설정되지 않았거나, 제거되었다는 것을 나타냅니다. 함수가 null을 리턴한다는 것은 함수에 따라서 여러 의미를 가질 수 있습니다. String.toIntOrNull()은 String을 Int로 적절하게 변환할 수 없을 경우 null을 리턴한다. Iterable.firstOrNull(() -> Boolean)은 주어진 조건에 맞는 요소가 없을 경우 null을 리턴한다. 기본적으로 nullable 타입은 세 가지 방법으로 처리합니다. ?. , 스마트 캐스팅, Elvis 연산자 등을 활용해서 안전하게 처리한다. 오류를 throw한다. 함수 또는 프로퍼티를 리펙터링해서 nullable 타입이 나오지 않게 바꾼다. null을 안전하게 처리하기 null을 안전하게 처리하는 방법 ..
함수가 원하는 결과를 만들어 낼 수 없을 때가 있습니다. 서버로부터 데이터를 읽어 들이려고 했는데, 인터넷 연결 문제로 읽어 들이지 못한 경우 조건에 맞는 첫 번째 요소를 찾으려 했는데, 조건에 맞는 요소가 없는 경우 텍스트를 파싱해서 객체를 만들려고 했는데, 텍스트의 형식이 맞지 않는 경우 이러한 상황을 처리하는 메커니즘은 두 가지가 있습니다. null 또는 '실패를 나타내는 sealed 클래스'를 리턴한다. 예외를 throw한다. 여기서 예외는 정보를 전달하는 방법으로 사용해서는 안되며, 이유를 정리하면 다음과 같습니다. 예외가 전파되는 과정을 제대로 추적하지 못한다. 코틀린의 모든 예외는 unchecked(반드시 처리하게 강제되는 예외)이다. 예외는 예외적인 상황을 처리하기 위해서 만들어졌으므로 명..
require, check, assert 함수를 사용하면, 대부분의 코틀린 오류를 처리할 수 있습니다. 하지만 이외에도 예측하지 못한 상황을 나타내야 하는 경우가 있습니다. 예를 들어 JSON 형식을 파싱하는 라이브러리를 구현한다고 가정하고 입력된 JSON 파일의 형식에 문제가 있다면, JSONParsingException 등을 발생시키는 것이 좋을 것입니다. inline fun String.readObject(): T { //... if (incorrectSign) { throw JsonParsingException() } //... return result } 표준 라이브러리에는 이를 나타내는 적절한 오류가 없으므로, 사용자 정의 오류를 사용했습니다. 하지만 가능하다면, 직접 오류를 정의하는 것보다는..
확실한 형태로 동작해야 하는 코드가 있다면, 예외를 활용해 제한을 걸어두는 것이 좋습니다. require 블록: 아규먼트를 제한할 수 있다. check 블록: 상태와 관련된 동작을 제한할 수 있다. assert 블록: 어떤 것이 true인지 확인할 수 있다. assert 블록은 테스트 모드에서만 작동한다. return 또는 throw와 함께 활용하는 Elvis 연산자 제한을 걸어 주면 다양한 장점이 발생합니다. 제한을 걸면 문서를 읽지 않은 개발자도 문제를 확인할 수 있다. 문제가 있을 경우에 함수가 예상하지 못한 동작을 하지 않고 예외를 throw한다. 예상하지 못한 동작을 하는 것은 throw하는 것보다 굉장히 위험하며, 상태를 관리하는 것이 굉장히 힘들다. 코드가 어느 정도 자체적으로 검사된다. 따..
코틀린의 타입 추론(type inference)은 널리 알려진 코틀린의 특징이며 자바도 자바10부터는 타입 추론을 도입했습니다. inferred 타입은 정확하게 오른쪽에 있는 피연산자에 맞게 설정되며 슈퍼클래스 또는 인터페이스로는 설정되지 않습니다. open class Animal class Zebra: Animal() fun main() { var animal = Zebra() animal = Animal() // 오류: Type mismatch } fun main() { var animal: Animal = Zebra() animal = Animal() // 성공 } 직접 라이브러리 또는 모둘을 조작할 수 없는 경우에는 간단하게 해결할 수 없습니다. 이러한 경우에서 inferred 타입을 노출하면 위..
널 안정성(null-safety)은 코틀린의 주요 기능 중 하나입니다. null-safety 메커니즘이 없는 자바, C등의 프로그래밍 언어와 코틀린을 연결해서 사용할 때는 널 포인터 예외(Null-Pointer Exception, NPE)가 발생할 수 있습니다. @Nullable 어노테이션이나 @NotNull 어노테이션이 붙어있다면 코틀린에서 활용할때는 String?과 String으로 변경하면 됩니다. 자바에서 모든 것이 null일 수 있으므로 최대한 안전하게 접근한다면, 이를 nullable로 가정하고 다루어야 합니다. 하지만 메서드가 null을 리턴하지 않을 것이 확실한 경우 not-null 단정을 나타내는 !!를 붙입니다. / 자바 public class UserRepo{ public List ge..