제네릭을 사용하기 시작하면 수많은 컴파일러 경고들을 마주치게 된다. 이러한 경고들을 가능한 많이 제거하는 것이 좋다. 경고들을 모두 제거한다면, 그 코드는 타입 안정성이 보장되기 때문이다. 다행히 대부분의 비검사 경고는 쉽게 제거할 수 있다. 대부분의 개발자들이 IDE를 통해 코드를 작성하고 컴파일하는데, IDE는 코드상에 컴파일 경고가 날 수 있는 부분을 컴파일 전에 미리 알려준다. // 비검사 경고 발생 Set some = new HashSet(); // 타입 매개변수 추론이 어렵다. 위의 코드는 가장 간단한 예시로, 자바 7부터 지원하는 다이아몬드 연산자를 추가하면 간단히 경고가 제거된다. Set some = new HashSet(); // 컴파일러가 타입 매개변수를 추론해준다. 경고를 제거할 수 ..
로 타입(Raw Type)은 제네릭 타입에서 타입 매개변수를 전혀 사용하지 않을 때를 말한다. 예를 들면 List list = new ArrayList(); 와 같은 형태를 가진다. 타입 매개변수? List 에서 에 해당하는 매개변수를 타입 매개변수라 한다. ex) List에서는 String이 타입 매개변수에 해당한다. 로 타입의 문제점 타입 안전성과 표현력을 확보할 수 없다. // 컬렉션의 로 타입 private final Collection stamps = ..... ; // Stamp 인스턴스만 취급한다. // 실수로 Stamp가 아닌 Coin을 넣는다. stamp.add(new Coin(..)) 위의 코드는 아무 오류없이 컴파일되고 실행된다. 컬렉션이 동전을 다시 꺼내기 전까지는 오류를 알아챌 방..
기술 블로그를 운영하면서 댓글에도 Github 이슈처럼 마크다운 문법을 사용할 수 있었으면 좋겠다는 생각을 했다. 그래서 찾아보니 utterances라는 오픈소스 앱이 있길래 바로 적용해보았다! utterances 적용해보기 1. 댓글 관리용 repository 만들기 먼저 github에 신규 repository를 생성한다. 보통 blog-comments라는 이름으로 많이 사용한다. 2. utterances.json 파일 생성하기 origins에 블로그 도메인 주소를 입력한다. // utterances.json { "origins": [ "http://jjingho.tistory.com", "https://jjingho.tistory.com" ] } 3. utterances app 추가하기 github...
문제점 소스 파일 하나에 여러 개의 톱레벨 클래스를 선언하더라도 컴파일에는 문제가 없다. 하지만 이는 심각한 위험을 감수해야 하는 행위이다. 소스 파일 하나에 여러개의 톱레벨 클래스를 선언함으로 컴파일 에러는 발생하지 않지만 예상치 못한 결과가 나타날 수 있다. 컴파일러에 어느 소스 파일을 먼저 건네느냐에 따라 동작이 달라지기 때문이다. 예시 아래와 같이 Utensil.java 파일에 Utensil과 Dessert 클래스가 함께 존재한다고 가정해보자. // Utensil.java class Utensil { static final String NAME = "pan"; } class Dessert { static final String NAME = "cake"; 그러던 중 우연히 위와 똑같은 클래스를 담은..
중첩 클래스란 다른 클래스 안에 정의된 클래스를 말한다. 중첩 클래스는 자신을 감싼 바깥 클래스에서만 쓰여야 하며, 그 외의 쓰임새가 있다면 톱 레벨 클래스로 만들어야 한다. 중첩 클래스의 종류 1. 정적 멤버 클래스 2. (비정적) 멤버 클래스 3. 익명 클래스 4. 지역 클래스 이 중 첫번째, 정적 멤버 클래스를 제외한 나머지를 내부 클래스(inner class)라고 한다. 정적 멤버 클래스 정적 멤버 클래스는 바깥 클래스의 private 멤버에도 접근할 수 있다는 점을 제외하고 일반 클래스와 똑같다. 정적 멤버 클래스는 보통 바깥 클래스와 함께 쓰일 때 유용한 public 도우미 클래스로 쓰인다. private 정적 멤버 클래스는 바깥 클래스가 표현하는 객체의 구성요소를 나타낼 때 사용된다. 공개된..
두 가지 이상의 의미를 표현할 수 있으며, 그중 현재 표현하는 의미를 태그 값으로 알려주는 클래스를 태그 달린 클래스라고 한다. 태그란? 클래스가 어떠한 타입인지에 대한 정보를 담고 있는 멤버 변수(필드)를 의미한다. 태그 달린 클래스는 많은 단점을 가지고 있다. 태그 달린 클래스의 단점 1. 쓸대없는 코드들이 많다. 태그에 대한 선언이 필요하기 때문에 열거형 타입 선언, 태그 필드, switch 문 등 쓸데없는 코드들이 많아진다. 태그에 따른 메서드의 행동이 달라져야 하기 때문에 switch 문이 많아져 가독성이 떨어진다. 2. 메모리를 많이 사용한다. 다른 행동을 위한 코드도 정의되기 때문에 메모리도 많이 사용하게 된다. 3. 불필요한 초기화가 필요하다. 필드를 final로 선언하려면 해당 태그에서 ..
클래스가 어떤 인터페이스를 구현한다는 것은 자신의 인스턴스로 무엇을 할 수 있는지를 클라이언트에게 말해주는 것이다. 인터페이스는 오직 이 용도로만 사용해야 한다. 메서드 없이 상수 필드만 가득한 상수 인터페이스를 사용하지 말자. 상수 인터페이스는 인터페이스를 잘못 사용한 안티 패턴이다. 클래스 내부에서 사용하는 상수는 외부 인터페이스가 아니라 내부 구현에 해당한다. 따라서 상수 인터페이스를 구현하는 것은 내부 구현을 외부로 노출하는 행위이다. 이는 사용자에게 혼란을 주고 클라이언트 코드가 내부 구현에 해당하는 상수에 종속적이게 될 수 있다. 만약 상수를 공개하고 싶다면 인스턴스화할 수 없는 유틸리티 클래스를 통해 공개하자. 혹은 그 클래스나 인터페이스에 강하게 연관된 상수라면 그 클래스나 인터페이스 자체..
자바 8 이전에는 기존 구현체를 깨트리지 않고 인터페이스에 메서드를 추가할 방법이 없었다. 자바 8부터 디폴트 메서드를 제공하여 메서드를 추가할 수 있도록 됐지만, 위험이 완전히 사라진 것은 아니다. 생각할 수 있는 모든 상황에서 불변식을 해치지 않는 디폴트 메서드를 작성하기란 어렵다. 자바 8부터 Collection에 새로 추가된 removeIf() 메서드는 Predicate 결과에 따라 원소를 제거하는 메서드이다. 범용적인 코드이지만, 모든 Collection의 구현체와 잘 어우러지는 것은 아니다. 아파치의 SynchronizedCollection 클래스는 지금도 활발히 관리되고 있지만 removeIf 메서드를 재정의하지 않는다. 그 이유는 만약 removeIf의 디폴트 구현을 물려받는다면 모든 메서..
자바가 제공하는 다중 구현 메커니즘은 인터페이스와 추상 클래스가 있다. 자바 8부터는 인터페이스도 디폴트 메서드를 제공하게 되어 인터페이스와 추상 클래스 모두 인스턴스 메서드를 구현 형태로 제공할 수 있게 되었다. 그렇다면 이 둘의 차이점이 무엇일까? 인터페이스와 추상 클래스의 가장 큰 차이는 추상 클래스를 상속받아 구현하는 클래스는 반드시 추상 클래스의 하위 클래스가 되어야 한다는 점이다. 단일 상속만 가능한 자바에서 추상 클래스의 하위 클래스는 다른 클래스를 확장할 수 없기 때문에 새로운 타입을 정의하는데 커다란 제약을 가지게 되는 셈이다. 반면에 인터페이스는 선언한 메서드를 모두 정의하고 그 일반 규약을 잘 지킨 클래스라면 다른 어떤 클래스를 상속했든 같은 타입으로 취급된다. 인터페이스의 장점 1...