java
Item 16
Item 16 Public 클래스에서는 Public 필드가 아닌 접근자 메서드를 사용하라 public 클래스의 데이터 필드에 직접 접근이 가능하면, 캡슐화의 장점을 제대로 살리지 못함 public으로 열어버리면 API를 수정하지 않는 이상 내부 표현을 바꿀 수 없음 필드는 priavate으로 열고, getter 및 기타 접근 메서드를 제공하면 됨 package-private 혹은 private 클래스의 경우에는 데이터 필드를 노출해도 됨 이 방법을 사용할 경우 코드가 훨씬 깔끔해짐 References 조슈아 블로크 - Effective Java 3/E
read morejava
Item 15
Item 15 클래스와 멤버의 접근 권한을 최소화하라 클래스의 내부 구현 정보를 외부 컴포넌트로부터 잘 숨기는 것이 중요 API를 통해서만 다른 컴포넌트와 소통 가능하게 만들어야 함 이렇게 정보 은닉을 잘 하는 경우, 다음과 같은 이점 존재 개발 속도 증가 관리 비용 감소 재사용성 증가 큰 시스템 제작 난이도 감소 정보 은닉을 위해서는, 클래스와 멤버의 접근성을 좁혀야 함 가장 바깥 클래스 혹은 인터페이스는 package-priavate혹은 public 두 가지 중 하나로 부여 public 으로 부여하는 경우 공개 API가 됨 public 일 필요가 없는 클래스는 최대한 package-private로 좁히자 멤버는 private을 기본으로 설계하자 같은 패키지 내부에서 접근해야 하는 경우에만 package-private로 설정 protected 이상인 경우, 다른 패키지에 공개되므로, 영원히 지원되어야 함 리스코프 치환 원칙 때문에, 상위 클래스보다 하위 클래스에서 접근 범위를 좁게 설정 불가능하므로 조심해야 함 테스트를 위해 클래스, 인터페이스, 멤버의 접근 제어 수준을 어느 정도 수정은 가능 private 을 package-private으로 바꾸는 정도 그러나 이를 공개하는 것은 문제가 됨 public 클래스의 인스턴스 필드는 되도록 public이 아니어야 함 값을 제한할 수도 없고, 스레드 안전하지도 않음 특히 public static final 배열 역시 변경 가능하므로, 설정에 주의해야 함 자바 9에서는 모듈 시스템이 도입되면서, 두 가지 접근 수준이 추가됨 그러나 꼭 필요한 경우가 아니라면 사용하지 않는 쪽이 좋아보임 References 조슈아 블로크 - Effective Java 3/E
read morejava
Item 12
Item 12 toString을 항상 재정의하라 기본적으로 제공되는 toString 메서드는 우리가 작성한 클래스에 적합한 문자열을 반환하지 않음 클래스 이름@16진수 해시 코드를 반환함 이는 우리가 원하는 정보가 아니므로, toString 메서드의 일반 규약에 따르는 유익한 정보를 반환해야 함 toString을 잘 구현해 두면, 사용 및 디버깅이 굉장히 용이함 구현할 때 참고할만한 점 객체가 가진 주요 정보 모두를 반환할 것 의도를 명확하게 밝혀야 함 반환값을 정확하게 어떻게 줄지 포맷을 명시해도 되고 안해도 됨 포맷을 명시하는 경우, 개발자들이 반환값을 명확하게 알 수 있게 되나, 포맷에 얽매이게 됨 명시하지 않는 경우, 추후 수정에 대한 유연성을 가지게 됨 하위 클래스들이 공유해야 할 문자열 표현이 있는 경우, toString을 재정의 해줘야 함 References 조슈아 블로크 - Effective Java 3/E
read morejava
Item 14
Item 14 Comparable을 구현할지 고려하라 Comparable인터페이스 에는 유일한 메서드인 compareTo가 존재 이 메서드는 두 객체의 순서를 비교할 수 있음 Comparable을 구현했다는 뜻은, 객체 간의 순서가 있음을 의미 즉, Comparable이 구현된 객체들의 배열은 Arrays.sort 메서드 사용 가능 Comparable을 구현하면, 이 인터페이스를 활용하는 수많은 제너릭 알고리즘과 컬렉션의 효과를 볼 수 있음 규약 a.compareTo(b)를 하는 경우, 다음 규칙을 만족해야 함 a가 b보다 작은 경우 음의 정수를, 같으면 0을, 크면 양의 정수를 반환해야 함 a.
read morejava
Item11
Item11 equals를 재정의하려거든 hashCode도 재정의하라 equals 메서드는 물리적으로 서로 다른 객체 역시 논리적으로는 같다고 판단할 수 있음 equals 메서드가 두 객체를 같다고 판단한 경우, 두 객체의 hashCode 반환 값 역시 동일해야 함 문제가 생기는 예시 다음 예제에서 Point 객체는 equals만 정의되어 있다고 가정 이 때 처음 생성한 Point 객체와 두 번째 생성한 Point 객체는 논리적으로 동일하긴 함 그러나 hashcode가 다르므로, HashMap에서 두 객체를 비교하지조차 않음 애초에 다른 해시 bucket에 있을 수도 있음 hashCode 메소드만 재정의해주면 쉽게 해결되는 문제 Map<Point, Integer> m = new HashMap<>(); m.
read morejava
Item 09
Item 09 try-finally 보다는 try-with-resources를 사용하라 자바 라이브러리 중에서는 close() 메서드를 이용해 명시적으로 닫아줘야 하는 자원 존재 InputStream, OutputStream, java.sql.Connection 등 자원을 회수하는 한 가지 방법은 try-finally를 이용하는 것 finally에서 자원을 회수 finally는 무조건 실행되므로, 예외가 발생하거나 메서드가 리턴되는 경우에도 무사히 자원 회수가 가능 그러나, 두 개 이상의 자원을 사용하는 경우 finally를 여러번 사용해야 한다는 단점 존재 또한 이렇게 중첩된 경우 두 번째 예외가 첫 번째 예외를 집어 삼키는 경우도 존재함 자바 7에서는 try-with-resource 구문이 등장해서 이런 문제를 해결 사용법 AutoCloseable 인터페이스를 구현하는 자원에 대해서 사용 가능 void close() 메서드 하나만 구현해 둔 인터페이스 대부분의 클래스가 미리 구현해 둠 다음과 같이 사용을 윈하는 자원을 try(자원) 형식으로 사용 close 메소드를 사용할 필요도 없음 catch 도 당연히 사용 가능 예외가 다른 예외를 집어 삼키는 경우도 나타나지 않음 try (BufferedReader br = new BufferedReader(new FileReader(path))) { String s = br.
read morejava
Item 07 + Example
Item 07 + Example 다 쓴 객체 참조를 해제하라 자바에서는 가비지 컬렉터가 존재하고, 이는 다 쓴 객체를 알아서 회수해 감 프로그래머의 생산성을 높임 그러나 이는 메모리 관리를 하지 않아도 된다는 뜻은 아님 더 이상 사용하지 않는 객체가 있어도, 참조를 남겨둔다면, gc의 대상이 되지 않음 Stack 예시 보통 stack을 pop 할때 다음과 같이 구현 public Object pop() { if (size == 0) { throw new EmptyStackException(); } return elements[--size]; } 이 방법을 수행하면, 원래 element[size] 위치에 존재하던 객체는 사용되지 않음 그러나 element 배열에서 객체에 대한 참조 자체는 남아있게 됨 따라서 gc가 객체를 회수해 가지 못하게 됨 다음과 같이 참조를 해제하는 코드를 추가 public Object pop() { if (size == 0) { throw new EmptyStackException(); } Object result = elements[--size]; elements[size] = null; // 객체 대신 null을 넣어 객체에 대한 참조를 해제 return result; } 이 방법을 사용하면 잘못된 객체를 참조하려고 하는 경우, NullPointerException을 통해 확실하게 예외를 던질 수 있음 주의 사항 그러나 이렇게 null 처리를 매번 할 필요는 없음 null 처리는 프로그램을 필요 이상으로 지저분하게 만드므로, 예외적인 경우에만 수행하면 됨 위 stack 예제와 같이 직접 메모리를 관리하는 클래스에서는 수행해 줘야 함 캐시 역시 메모리 누수를 일으킬 수 있음 객체 참조를 캐시에 넣은 후, 오랜 기간 방치될 수 있기 때문 WeakedHashMap을 통해 캐시를 만들면 엔트리가 살아 있는 동안만 참조하고(약한 참조), 다 쓰이면 gc가 수거해 감 Listener 혹은 Callback 역시 메모리 누수의 원인 콜백을 등록하고 해지하지 않으면, 콜백이 계속 쌓이게 됨 콜백을 약한 참조로 설정하면, gc의 수집 대상이 되어 수거해 감 메모리 누수는 겉으로 잘 드러나지 않기 때문에, 늘 예방법을 잘 알아야 함 꼼꼼한 코드 리뷰 및 디버깅 도구를 잘 사용하는 것도 중요 Example 다음과 같은 간단한 역 객체가 존재 public class Item07Station { private static final String HEADER = "아무호선"; private static final String FOOTER = "역"; private String name; private final Integer id; public Item07Station(Integer id) { this.
read morejava
Item 06 + Example
Item 06 + Example 불필요한 객체 생성을 피하라 불필요하게 객체를 생성하는 과정을 줄이는 것이 좋음 만약 똑같은 기능의 객체를 여러번 사용해야 한다면, 매번 생성하기보다 객체 하나를 재사용하는 편이 나을 때가 많음 특히 불변 객체는 재사용이 쉬움 다음과 같은 여러 예시 존재 불필요한 객체 생성 예시 - String 다음 코드는 생성자에 인자로 넘겨진 "bikini" 와 생성된 s가 완전히 똑같음 // 불필요한 객체 생성의 예시 String s = new String("bikini"); 따라서, 불필요한 객체 생성을 수행할 필요 없이 다음과 같이 쓰면 됨 // 다음과 같이 쓰면 됨 String s = "bikini"; 비싼 객체 생성 예시 다음 코드는 매 번 함수가 호출될 때마다 String.
read morejava
Item 05 + Example
Item 05 + Example 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 클래스는 내부적으로 하나 이상의 자원 (다른 클래스)에 의존하는 경우가 많음 이 자원에 따라 사용하는 동작이 달라지는 경우가 존재 가능 이 때는 정적 유틸리티 클래스 혹은 싱글턴을 사용하는 것은 좋은 선택이 아님 또한 클래스가 직접 자원을 만들게 하는 것도 좋은 방법이 아님 (유연성이 떨어짐) 이를 해결하기 위해 의존 객체 주입 방식을 사용하면 됨 대표적인 의존 객체 주입 방식은 인스턴스를 생성할 때, 생성자에 필요한 자원을 넘겨주면 됨 혹은 생성자에 자원의 팩터리를 넘겨주는 방법이 존재 그러나 이렇게 의존성을 주입하는 방식은 코드를 과하게 복잡하게 만들 수 있음 Dagger, Guice, Spring 등의 의존 객체 주입 프레임워크를 활용하면 이 문제를 해결 가능 Example 모든 역은 이름과 id를 가짐 public abstract class Station { int stationId; String stationName; public Station(int stationId, String stationName) { this.
read morejava
Item 03 + Example
Item 03 + Example Private 생성자나 열거 타입으로 싱글턴임을 보증하라 싱글턴이란 인스턴스를 하나만 생성할 수 있는 클래스 여러 HTTP 요청에 응답하는 인스턴스를 매 요청마다 만드는 경우 메모리 낭비가 심각 이런 요청에 응답하는, 상태를 가지지 않는 단 하나의 인스턴스로 처리하는 것이 좋음 싱글턴은 다음과 같은 단점 존재 싱글턴으로 클래스를 만든 경우 이를 사용하는 클라이언트를 테스트하기 힘듦 각 테스트마다 독립적인 인스턴스를 만들 수 없기 때문 싱글턴 인스턴스는 정확히 하나만 존재하기 때문에, mock으로 대체할 수 없음 싱글턴 인스턴스를 만들기 위해서는 private 생성자를 사용하거나 열거 타입을 사용 가능 Private 생성자 - public 필드 사용 public class Demian { // 싱글턴 인스턴스, 이 값을 초기화 할 때 딱 한번만 생성됨 public static final Demian instance = new Demian(); // private 생성자이므로, 외부에서 이 클래스의 인스턴스를 생성 불가능함 private Demain() { .
read more