안드로이드는 자바를 잘 쓰다가 왜 코틀린을 채택했을까?쉬운 언어라서? 함수형 프로그래밍이 유행이니깐? 우린 이 질문에 대해 근본적으로 생각해본적이 있을까이 책에서 조금 더 근본적인 걸 이야기해보고 코틀린을 어떻게 하면 잘 다룰지 같이 고민해보는 시리즈를 시작해볼까 한다
변성(variance)은 파라미터화한 타입이 서로 어떤 하위 타입 관계에 있는지 결정하는 방식을 뜻한다.공변성(covariance)은 Red가 Color의 하위 타입일 때 Matcher<Red>가 Matcher<Color>의 하위 타입이라는 뜻이다.이런 경우
앞서서 언급했던 순수 함수를 기억하는가?순수 함수가 되기 위한 필요한 조건들이 있다.함수 외부의 어떤 것도 변이시켜서는 안 된다. 내부에서 상태를 변이시키더라도 그 상태를 외부에서 관찰할 수 없어야 한다.인자를 변이시켜서는 안 된다.예외나 오류를 던져서는 안 된다.항상
간간히 올라올 이펙티브 코틀린을 읽고 정리하는 게시글은 간결하게만 적을 예정이다. (물론 내 입장에서만 간결할수도)그러므로 내용이 더 궁금하거나 공부하고 싶다면 해당 책을 구매 후 직접 읽고 인사이트를 얻는 게 나을 것이다!코틀린은 읽고 쓸 수 있는 프로퍼티(read-
이펙티브 코틀린에서는 변수와 프로퍼티의 스코프를 최소화하라고 한다.프로퍼티보단 지역 변수가 좋다.최대한 좁은 스콥을 갖는 변수를 사용한다. (반복문 내부에서만 변수가 사용된다면 반복문 내부에서 변수를 선언해서 쓸 것 등)왜냐하면 스콥을 최소화해야지 프로그램을 추적하고
코틀린의 타입 추론 (type inference)은 JVM 세계에서 가장 널리 알려진 코틀린의 특징이다. (물론 자바도 자바 10부터 코틀린을 따라 도입하긴 했지만 코틀린과 비교하면 제약이 있다)다만, 타입 추론을 사용할 때는 몇 가지 위험한 부분들이 있다. 그래서 이
코틀린의 널 안정성은 코틀린의 주요 기능 중 하나이다. 이 기능 덕분에 코틀린을 쓰면 NPE가 날 일이 없는데, 자바, C 등의 프로그래밍 언어와 코틀린을 같이 쓸 땐 이 예외가 발생할 수 있다.Q) 그럼 우린 이를 방지할 수 있나?있긴 하다! 바로 어노테이션을 사용하
코틀린에서는 코드의 동작에 제한을 걸 수 있는데, 다음과 같이 쓸 수 있다 require 블록: 아큐먼트를 제한할 수 있다. check 블록: 상태와 관련된 동작을 제한할 수 있다. assert 블록: 어떤 것이 true인지 확인할 수 있다. assert 블록은
앞서 5장에서 이야기하는 거처럼 require, check, assert 함수를 사용하면, 대부분의 코틀린 오류를 처리할 수 있다.하지만 이외에도 예측하지 못한 상황을 나타내야 하는 경우가 있다. 이렇게 기본적으로 입력된 Json 파일의 형식에 문제가 있다면, Json
함수가 원하는 결과를 만들어 낼 수 없을 경우가 있다.서버로부터 데이터를 읽어 들이려고 했는데, 인터넷 연결 문제로 읽어 들이지 못한 경우조건에 맞는 첫 번째 요소를 찾으려 했는데, 조건에 맞는 요소가 없는 경우텍스트를 파싱해서 객체를 만들려고 했는데, 텍스트의 형식이
코틀린에는 Null로 반환해서 처리할 수 있는 함수들이 있다String.toIntOrNull()Iterable<T>.firstOrNull()이렇게 null을 반환하게 하고 null을 처리하는 몇 가지 방법들이 코틀린에 있는데 아래와 같다.?., 스마트 캐스팅, E
InputStream, OutputStreamjava.sql.Connectionjava.io.Reader(FileReader, BufferedReader, CSSParser)java.new.Socket, java.util.Scanner이 친구들은 더 이상 필요하지 않을
사실 코드를 안전하게 만드는 가장 궁극적인 방법은 다양한 종류의 테스트를 하는 것이다. 해당 코드가 올바르게 작동한다는 걸 보증하고 개발 시점에서의 빠른 피드백이 필요하면 단위 테스트를 하자.그럼 단위 테스트로 어떤 걸 테스트 하나? 일반적으로 다음과 같은 케이스들을
개발자들은 코드 작성 1분 읽기에 10분이 걸린다는 말이 있다. 그만큼 읽기가 중요하다. 물론 가독성은 사람마다 다르게 느껴질텐데, 일반적으로 사람의 '경험'과 '인식에 대한 과학'으로 만들어진 규칙이 있다.구현 A구현 B딱 봤을때 읽기 편한건 무엇이라고 보는가? A다
연산자 오버로딩은 말그래도 연산자로 쓰이고 있는 친구들을 오버로딩해서 정의해서 사용하는 방식이다.이는 굉장히 강력하지만 위험할 수 있다.만약 factorial을 정의해서 쓴다하면 아래와 같이 정의하고 싶을 수도 있다과연 될까? 안 된다.이 함수 이름이 not() 이므로
Boolean 이 true, false 값을 갖는 거처럼 Unit도 Unit 또는 null 값을 가질 수 있다.간혼 Boolean 대신 Unit?을 사용하기도 한다.이 코드를 다음처럼 사용할 수 있다쓸 때는 멋있을 수도 있어도 읽을 때는 혼란을 야기한다.Unit?으로
무언가를 더 자세하게 설명하기 위해서 긴 코드를 사용할 때가 있다. 대표적으로 함수와 프로퍼티를 지역 또는 톱레벨 변수가 아닌 다른 리시버로부터 가져온다는 것을 타나낼 때가 있다. 비슷하게 확장 리시버(확장 메서드에서의 this)를 명시적으로 참조하게 할수도 있다.명시
코틀린은 명석하게도 수준 높은 타입 추론 시스템을 갖고 있다. 이는 개발시간을 줄여줄 뿐만 아니라 코드도 짧아져서 가독성이 향상된다. 하지만 유형이 명확하지 않을 때는 남용하지 않는게 좋다. 위와 같이 선언할 경우 이 친구가 어떤 데이터인지 알 수 있을까? 우리가
코틀린의 프로퍼티는 자바의 필드와 비슷해보이지만 사실 전혀 다른 개념이다물론 둘 다 데이터를 저장한다는 점은 같다. 그치만 코틀린의 프로퍼티는 사용자 정의 게터/세터를 가질 수 있다fiedl라는 식별자를 확인할 수 있는데 val을 사용해서 읽기 전용 프로퍼티를 만들 때
코드에서 아규먼트의 의미가 명확하지 않은 경우가 있다.joinToString()에 대해 알고 있다면 "|"이 구분자라는 걸 알 것이다. 하지만 모른다면 접두사로 생각할 수도 있다.파라미터가 불명확한 경우에는 이를 직접 지정해서 명확하게 만들 수 있다. 아래 코드처럼 이
코틀린 문서의 코딩 컨벤션을 보면 알 수 있는 거처럼 코틀린은 잘 정리된 코딩 컨벤션을 갖고 있다.물론 이 컨벤션이 모든 프로젝트에 최적인 것은 아니어도 지키면 좋다.어떤 프로젝트를 접해도 쉽게 이해 가능다른 외부 개발자도 프로젝트 코드 이해 가능다른 개발자도 코드 작
대망의 3장 재사용성이다3장의 재사용성의 첫 막을 여는 주제는 "반복하여 사용하지 말라"실제로 이펙티브 코틀린 저자가 생각하는 프로그래밍의 가장 큰 규칙은 "프로젝트에서 이미 있던 코드를 복사해서 붙여넣고 있다면, 무언가가 잘못된 것이다" 이다.그리고 이걸 knowle
많은 개발자는 같은 알고리즘을 여러 번 반복해서 구현한다. 여기서 말하는 알고리즘은 수학적 연산, 수집 처리처럼 별도의 모듈 또는 라이브러리로 분리할 수 있는 부분을 말한다.복잡한 알고리즘도 있겠지만 아래처럼 숫자를 특정 범위에 맞추는 간단한 알고리즘도 있을 수 있다.
코틀린은 코드 재사용과 관련해서 프로퍼티 위임이라는 새로운 기능을 제공한다.프로퍼티 위임을 사용하면 일반적인 프로퍼티의 행위를 추출해서 재사용할 수 있다.ex) lazy일반적으로 대부분의 언어(자바 스크립트 등)에서는 필요할 때마다 이를 복잡하게 구현해야 하지만, 코틀
아규먼트로 함수에 값을 전달할 수 있는 것처럼 타입 아규먼트를 사용하면 함수에 타입을 전달할 수 있다.타입 아규먼트를 사용하는 함수(즉, 타입 파라미터를 갖는 함수)를 제네릭 함수라고 부른다. 대표적인 예로는 stdlib의 filter()가 있다. filter() 는
이 코드처럼 프로퍼티와 파라미터가 같은 이름을 가질 수 있다. 이렇게 되면 지역 파라미터가 외부 스코프에 있는 프로퍼티를 가리는데 이걸 Shadowing(섀도잉)이라 한다. 또한 개발자들도 문제가 있을 경우 한 번에 찾기 쉽기 때문에 경고도 발생시키지 않는다.이 현상은
다음과 같은 제네릭 클래스가 있다고 하자위 코드에서 타입 파라미터 T는 variance 한정자(out 또는 in)가 없으므로, 기본적으로 invariant(불공변성)이다. invariant라는 것은 제네릭 타입으로 만들어지는 타입들이 서로 관련성이 없단 의미다.예를 들
기업이 한 플랫폼만을 대상으로 애플리케이션을 만드는 경우는 없다. 여러 플랫폼에서 서비스와 제품이 돌아가기 때문인데 이 들은 다른 플랫폼이어도 비슷한 비즈니스 로직을 쓰이는 경우가 있다. 따라서 소스를 공유할 수 있다면 큰 이득이 발생할 것이다많은 회사가 웹 개발을 기
OOP에서는 추상화, 캡슐화, 상속 등의 주요 개념이 존재하며 추상화는 프로그래밍 세계에서 가장 중요한 개념 중 하나이다.추상화복잡한 자료, 모듈 시스템 등으로부터 핵심적인 개념 또는 기능을 간추려내는것, 복잡성을 숨기기 위해 사용되는 단순한 형식이며 대표적인 예로 인
추상화를 통해 변화로부터 코드를 보호하는 행위가 어떤 자유를 가져오는 살펴보자리터럴은 아무것도 설명하지 않는다. 그래서 반복적으로 코드에 등장할 때 가독성 측면이나 유지보수 측면에서 자유롭지 못한다.위 예시처럼 숫자 7은 비밀번호의 최소 길이를 나타내는 거겠지만 이해하
프로그래밍에서는 안정적이고 표준적인 API(Application Programming Interface)를 선호한다.API가 변경되고 개발자가 이를 업데이트했다면 여러 코드를 수정으로 업데이트해야한다.이 때, 많은 요소가 이 API에 의존하고 있다면 큰 문제가 된다.
API 설계자가 안전하지 않다고 하거나 API 설계자가 안전하다고 해도 신뢰할 수 없다면 해당 API는 불안정하다.그리고 당연하게도 이 불안정한 API를 과도하게 사용하는 것은 위험하다. 어쩔수 없이 활용해야한다면 이 API를 로직과 직접 결합시키지 않는 것이 좋다.
간결한 API를 선호하는 여러가지 이유가 있다작은 인터페이스는 배우고 유지보수하기 쉬움변경을 가할 때는 기존의 것을 숨기는 것보다 새로운 것을 노출하는 것이 쉬움외부에서 사용하고 있는 요소들은 변경하기 어렵고 (사용하고 있는 모든 부분이 영향을 받기 때문에), 가시성과
메시지 출력 방법을 자유롭게 바꿀 수 있게 함수로 추출했다. 하지만 문서화가 잘 돼 있지 않다. 다른 개발자는 이 코드를 읽고 당연히 토스트를 출력할 거라 생각할 수 있다. 하지만 showMessage라는 이름은 토스트가 아닌 다른 타입으로도 메시지를 출력할 수 있게
규약은 개발자들의 단순한 합의. 그러나 위반할 수도 있다.ex) 리플렉션 활용무언가를 할 수 있다는 건 그것을 해도 괜찮다는 의미는 아니다. 현재 코드는 private 프로퍼티와 private 함수의 이름과 같은 세부적인 정보에 매우 크게 의존하고 있다. 이러한 이름은
클라이언트가 클래스의 인스턴스를 만들게 하는 가장 일반적인 방법은 기본 생성자를 사용하는 방법이다. 생성자가 객체를 만들 수 있는 유일한 방법은 아니며 굉장히 다양한 생성 패턴이 만들어져 있다.예를 들어 다음 코드의 톱레벨 함수는 MyLinkedList 클래스의 인스턴
객체를 정의하고 생성하는 방법 중 가장 기본적인 방법은 기본 생성자를 사용하는 것이다.일반적으로 이를 활용해서 객체를 만드는 것이 좋다. 기본 생성자로 객체를 만들 때는 객체의 초기 상태를 나타내는 아규먼트를 전달한다. 일단 데이터를 표현하는 가장 기본적인 데이터는 아
DSL은 복잡한 객체, 계층구조를 갖고있는 객체를 정의할 때 굉장히 유용하다.코틀린 테스트를 활용해 테스트 케이스를 정의했다.Gradle 설정을 정의할때에도 Gradle Dsl이 사용된다.DSL을 활용하면 복잡하고 계층적인 자료구조를 쉽게 만들수 있다.이미 존해나는것도
상속은 관계가 명확하지 않을 때 사용하면 여러 가지 문제가 발생할 수 있다. 그래서 단순하게 코드 추출 또는 재사용을 위해 사용할 때는 컴포지션을 사용하자. 그럼 상속으로 어떤 문제들이 발생할 수 있을까? 간단한 행위 재사용 만약 프로그레스바를 로직 전 후로 출
데이터를 한꺼번에 전달해야 할 때 data class를 쓰는데, class 앞에 data 한정자를 붙이면 몇 가지 함수가 자동으로 생성된다.toStringequals와 hashCodecopycompoentN(compoent1, component 2 등)toString
대부분의 프로그래밍 언어에는 함수 타입이라는 개념이 없다. 그래서 메서드가 하나만 있는 인터페이스를 활용하는데 이러한 인터페이스를 SAM(Single-Abstract Method)라고 부른다ex)함수가 SAM을 받는다면 이러한 인터페이스를 구현한 객체를 전달받는다는 의
큰 규모의 프로젝트에서는 상수 '모드'를 가진 클래스를 꽤 많이 볼 수 있다. 이런 상수 모드를 Tag라고 부르며, 태그를 포함한 클래스를 태그 클래스라고 한다.근데 이 태그 클래스는 여러 문제가 있는데 이 문제는 서로 다른 책임을 한 클래스에 태그로 구분해서 넣는다는
코틀린의 Any에는 잘 설정된 규약들을 가진 메서드들이 있다.equalshashCodetoString이 메서드들은 자바 때부터 정의되어 있던 메서드라 코틀린에서 중요한 위치에 있고 중요한 내용이므로 equals부터 하나씩 다뤄본다.코틀린에는 두 가지 동등성이 있다.구조
앞서 Any의 오버라이드 가능 메서드 중 equals를 이야기했다면 이번엔 hashCode를 이야기해보자왜 이 hashCode가 필요할까?배열 또는 링크드 리스트를 기반으로 만들어진 컬렉션은 요소가 포함되어 있는지 확인하는 성능이 좋지 않다. 수백 만 개의 텍스트를 선
compareTo 메서드는 Any 클래스에 있는 메서드가 아니다. 부등식으로 변환되는 연산자다.참고로 compareTo 메서드는 Comparable<T> 인터페이스에도 들어 있다.어떤 객체가 이 인터페이스를 구현하고 있거나 compareTo라는 연산자 메서드를 갖
확장 함수를 추가할 때 어떤 클래스의 내부로 추가하는 것이 좋지 않다. (즉, 멤버로 추가하는 것이 좋지 않다.)예를 들면 다음과 같은 함수는컴파일되면, 다음과 같이 변합니다.이렇게 단순하게 변환되는 것이므로, 확장 함수를 클래스 멤버로 정의할 수도 있고 인터페이스 내
코틀린 표준 라이브러리 함수에 간혹 inline 한정자가 붙어 있는 모습을 볼 수 있다. 왜 붙였을까?ex) repeatinline 한정자의 역할은 컴파일 시점에 함수를 호출하는 부분을 함수의 본문으로 대체하는 것이다. 예를 들면 아래와 같다.가 컴파일 시점에는 대체된
인라인으로 만들 수 있는 것은 하나의 값을 보유하는 객체도 만들 수 있다. 코틀린 1.3부터 도입됐는데 해당 객체를 사용하는 위치가 해당 프로퍼티로 교체된다.이런 inline 클래스는 타입만 맞다면 값을 곧바로 집어 넣는 것도 허용된다. 그리고 inline 클래스의 메
자바는 가비지 컬렉터가 객체 해제와 관련된 모든 작업을 한다. 하지만 그렇다고 메모리 관리를 무시하면 메모리 누수가 발생해서 상황에 따라 OOM이 발생한다. 그래서 요 아이템 주제처럼 사용하지 않는 객체의 레퍼런스를 유지하면 안 된다라는 규칙 정도는 지켜주자.안드로이드
Iterable과 Sequence 차이를 잘 모를 수 있다. 왜냐면 둘은 정의가 같다.하지만 이 둘은 완전히 다른 목적으로 설계되어서 완전히 다른 형태로 동작한다.시퀀스는 lazy(지연) 처리된다. 따라서 시퀀스 처리 함수들을 사용하면 데코레이터 패턴으로 꾸며진 새로운
모든 컬렉션 처리 메서드는 비용이 많이 든다. 표준 컬렉션 처리는 내부적으로 요소들을 활용해 반복을 도는데 내부적으로 계산을 위해 추가적인 컬렉션도 만들어 사용한다.따라서 적절한 메서드를 활용해서 컬렉션 처리 단계 수를 적절하게 줄이는게 좋다ex)보통 첫번째처럼 비효율
코틀린에서 최적화를 위해 내부적으로는 primitive(기본 자료형)을 사용할 수 있다.기본 자료형은 아래의 특징이 있다.가볍다 \- 일반적인 객체와 다르게 추가적으로 포함되는 것들이 없기 때문에빠르다 \- 값에 접근할 때 추가 비용이 들지 않아서 그래서 대규모
immutable 컬렉션보다 mutable 컬렉션이 좋은 점은 성능적인 측면에서 더 빠르다.왜냐면 immutable에 요소를 추가하려면 새로운 컬렉션을 만들면서까지 추가해야 한다.컬렉션을 복제하는 처리는 비용이 굉장히 많이 드는 처리이다. 그래서 복제 처리를 하지 않는
클래스의 메서드를 정의할 때는 멤버로 정의할 것인지 확장 함수로 정의할 것인지 결정해야 한다.물론 두 가지 방법은 비슷하다. 호출하는 방법도, 리플렉션으로 레퍼런싱 하는 방법도 똑같다.그래서 어떤 방식이 우월하다 할 수 없고 상황에 맞게 사용해야 한다.일단 멤버와 확장