프로그래밍 노트/Effective 시리즈

메서드 이름을 신중히 짓자 항상 표준 명명 규칙을 따라야 한다. 이해할 수 있고, 같은 패키지에 속한 다른 이름들과 일관되게 짓는 게 최우선 그다음 목표는 개발자 커뮤니티에서 널리 받아들여지는 이름 사용(긴 이름은 피하자!) 편의 메서드를 너무 많이 만들지 말자 모든 메서드는 각각 자신의 소임을 다해야 한다. 메서드가 많은 클래스는 익히고, 사용하고, 문서화하고, 테스트하고, 유지보수하기 어렵다. (인터페이스도 마찬가지) 매개변수 목록은 짧게 유지하자 매개변수는 4개 이하가 좋다. 일단 4개가 넘어가면 매개변수를 전부 기억하기가 쉽지 않다. 같은 타입의 매개변수 여러개가 연달아 나오는 경우는 특히 해롭다. 사용자가 매개변수 순서를 기억하기 어려울뿐더러, 실수로 순서를 바꿔 입력해도 그대로 컴파일되고 실행..
자바개발자라면 한번씩 필수로 알아두어야 하는 부분이다. (Naming Rule, Naming Convention 이라고도 한다.) 자바의 명명 규칙은 크게 철자 와 문법 두 범주로 나뉜다. 철자 규칙 은 패키지, 클래스, 메서드, 필드 타입 변수의 이름을 다룬다. 이 규칙들은 특별한 이유가 없는 한 반드시 따라야 한다. 철자 규칙 패키지(package) 패키지와 모듈이름은 각 요소를 점(.)으로 구분하여 계층적으로 짓는다. 요소들은 모두 소문자 알파벳 혹은 (드물게)숫자로 이뤄진다. 조직 바깥에서도 사용될 패키지라면 조직의 인터넷 도메인 이름을 역순으로 사용한다. (edu.cmu, com.google) 패키지 이름은 나머지 해당 패키지를 설명하는 하나 이상의 요소로 이뤄진다. (일반적으로 8자 이하의 짧..
우리는 "오류는 가능한 한 빨리 (발생한 곳에서) 잡아야한다" 는 원칙을 지키기위해 노력해야한다. 오류를 발생한 즉시 잡지 못하면 해당 오류를 감지하기 어려워지고, 감지하더라도 오류의 발생 지점을 찾기 어려워진다. 메서드 몸체가 실행되기 전에 매개변수를 확인한다면 잘못된 값이 넘어왔을때 즉각적이고 깔끔한 방식으로 예외를 던질 수 있다. 매개변수 검사를 제대로 하지 못하였을 때 발생하는 문제가 몇 가지 있는데 메서드가 수행되는 중간에 모호한 예외를 던지며 실패할 수 있다. 더 나쁜 상황은 메서드가 잘 수행되지만 잘못된 결과를 반환할 때이며, 더 나쁜 상황은 메서드는 문제없이 수행됐지만, 어떤 객체를 이상한 상태로 만들어놓아서 미래의 알 수 없는 시점에 이 메서드와는 관련 없는 오류를 낼 때다. public..
private final List cheesesInStock = ...; /** * @return 매장 안의 모든 치즈 목록을 반환한다. * 단, 재고가 하나도 없다면 null을 반환한다. */ public List getCheese(){ return cheesesInStock.isEmpty() ? null : new ArrayList(cheesesInStock); } 위의 코드의 문제점은 null을 반환한다는 것이다. 재고가 없다고 해서 특별히 취급할 이유는 없는대도 말이다.. 만약에 재고가 없을 경우 null을 반환하는 것을 고집한다면, 이 메소드를 사용하는 모든 클라이언트는 아래와 같은 방어 코드를 넣어줘야 한다. List cheeses = shop.getCheese(); if(cheeses != ..
다량의 데이터 처리 작업을 돕고자 자바8에 스트림 API가 추가되었다. 이 API가 제공하는 추상 개념 중 핵심은 두 가지다. 스트림(stream)은 데이터 원소의 유한 혹은 무한 시퀀스(sequence)를 뜻한다. 스트림 파이프라인(stream pipleline)은 이 원소들로 수행하는 연산 단계를 표현하는 개념이다. 스트림 파이프라인 은 소스 스트림에서 시작해 종단 연산(terminal operation)으로 끝나며, 그 사이에 하나 이상의 중간 연산(intermediate operation)이 있을 수 있다. 각 중간 연산은 스트림을 어떠한 방식으로 변환(transform)한다. (중간 연산들은 모두 한 스트림을 다른 스트림으로 변환한다.) 또한 스트림 파이프라인은 지연 평가(lazy evaluat..
자바가 람다를 지원하면서 API를 작성하는 모범 사례도 크게 바뀌었다. 상위 클래스의 기본 메서드를 재정의해 원하는 동작을 구현하는 템플릿 매서드 패턴의 매력이 줄었다. ⇒ 함수 객체를 받는 정적 팩터리나 생성자를 제공 LinkedHashMap을 생각해보자. LinkedHashMap의 protected 메서드인 removeEldestEntry 를 재정의하면 캐시로 LinkedHashMap을 사용할 수 있다. 맵에 새로운 키를 추가하는 put 메서드는 이 메서드를 호출하여 true가 반환되면 맵에서 가장 오래된 원소를 제거하게 로직을 추가하면 된다. public class MyLinkedHashMap extends LinkedHashMap { @Override protected boolean removeE..
람다가 익명 클래스보다 나은 점 중 가장 큰 특징은 간결함이다. 그런데 람다보다도 더 간결하게 만드는 방법이 있으니 바로 메서드 참조(method reference)이다. 아래 코드는 키가 맵안에 없다면 키와 숫자 1을 매핑하고, 이미 있다면 기존 매핑 값을 증가시킨다. map.merge(key, 1, (count, incr) -> count + incr); 깔끔해 보이지만, 매개변수인 count와 incr은 크게 하는일 없이 공간을 꽤 차지한다. (두 인수의 합을 단순히 반환하는 역할을 한다.) 자바8의 Integer 클래스는 이 람다와 같은 기능이 같은 정적 메서드 sum을 제공하기 시작했다. 따라서 위의 코드는 아래코드로 변경할 수 있다. map.merge(key, 1, Integer::sum); ..
자바8에는 추상 메서드 하나짜리 인터페이스는 특별한 의미를 인정받아 특별한 대우를 받게 되었다. 함수형 인터페이스라 부르는 이 인터페이스들의 인스턴스를 람다식(lamda expression)을 사용해 만들 수 있게 된 것이다. Collections.sort(words, new Comparator(){ public int compare(String s1, String s2){ return Integer.compare(s1.length, s2.length()); } }); Collections.sort(words, (s1, s2) -> Integer.compare(s1.length(), s2.length()); 컴파일러가 문맥을 살펴 타입을 추론해준다. 타입을 명시해야 코드가 더 명확할 때만 제외하고는, 람..
객체 생성을 막을 때는 private 생성자를 사용하라때로 정적 메서드나 필드만 모은 클래스를 만들고 싶을 때가 있다.자바의 기본 자료형 값(primitive value) 또는 배열에 적용되는 메서드를 한군데 모아둘 때 유용하다. (java.lang.Math 나 java.lang.Array)특정 인터페이스를 구현하는 객체를 만드는 팩터리 메서드 등의 정적 메서드를 모아놓을 때도 사용할 수 있다. (java.util.Collections) 이런 유틸리티 클래스(utility class)들은 객체를 만들 목적의 클래스가 아니기 때문에 private 생성자를 클래스에 넣어 객체 생성을 방지해야 한다.(생성자를 생략하면 컴파일러는 자동으로 인자 없는 기본 생성자를 생성한다.)
private 생성자나 enum 자료형은 싱글턴 패턴을 따르도록 설계하라 싱글턴은 객체를 하나만 만들 수 있는 클래스이다. JDK1.5 이전에서 싱글턴을 구현하는 방법은 2가지가 존재한다. 하나는 생성자는 private로 선언하고, 싱글턴 객체는 정적(static) 멤버를 통해 이용하는 방법 public class corn{ public static final Corn INSTANCE = new Corn(); private Corn() {... } public void run() { ... } }​ 두번 째는 public으로 선언된 정적 팩터리 메서드를 이용하는 방법이다. public class Corn{ private static final Corn INSTANCE = new Corn(); privat..
깡냉쓰
'프로그래밍 노트/Effective 시리즈' 카테고리의 글 목록 (2 Page)