생각해보기
이펙티브 자바 -8- 본문
일반적인 프로그래밍 원칙
자바 언어의 핵심 요소를 다룬다
지역변수의 범위를 최소화하라
자바에서는 문장을 선언할 수 있는 곳이면 어디서는 변수를 선언 할 수 있다. 따라서 지역변수의 유효 범위를 최소로 줄이면 코드 가독성과 유지보수성은 높아지고 오류 가능성은 낮아진다.
지역변수 범위 최소화 방법
- 지역변수의 범위를 줄이는 가장 강력한 기법은 '가장 처음 쓰일 때 선언하기'이다.
- 거의 모든 지역변수는 선언과 동시에 초기화해야 한다. 초기화에 필요한 정보가 충분하지 않다면 충분해질 때까지 선언을 미뤄야 한다. try-catch문은 이 규칙에서 예외이다.
- 메서드를 작게 유지하고 한 가지 기능에 집중하는 것이다. 메서드를 기능별로 작게 쪼개자.
* 추가 tip
반복문은 변수 범위를 최소화해준다, 따라서 반복 변수의 값을 반복문이 종료된 뒤에도 써야 하는 상황이 아니라면 while문보다 for문을 사용하는 것이 낫다
반복자를 사용해야 하는 상황이면 for-each 문대신 전통적인 for 문을 쓰는 것이 낫다
전통적인 for 문보다는 for-each문을 사용하라
for-each문은 반복자와 인덱스 변수를 사용하지 않으니 코드가 깔끔해지고 오류가 날 일도 없다. 컬렉션과 배열을 모두 처리 할수 있어 어떤 컨테이너를 다루는지 신경 쓰지 않아도 된다
for-each 문을 사용할 수 없는 세가지 상황
- 파괴적인 필터링 : 컬렉션을 순회하면서 선택된 원소를 제거해야 한다면 반복자의 remove 메서드를 호출해야 한다.
- 변형 : 리스트나 배열을 순회하면서 그 원소의 값 일부 혹은 전체를 교체해야 한다면. 반복자나 인덱스를 사용해야 한다
- 병렬 반복 : 여러 컬렉션을 병렬로 순회해야 한다면 각각의 반복자와 인덱스 변수를 사용해 엄격하고 명시적으로 제거 해야 한다.
for-each 문은 컬렉션과 배열은 물론 Iterable 인터페이스를 구현한 객체라면 무엇이든 순회할 수 있다.
정리
전통적인 for문과 비교했을 때 for-each문은 명료하고 유연하고 버그를 예방해준다. for-each문을 사용할 없는 상황을 제외하고, 가능한 for문이 아닌 for-each문을 사용하자
라이브러리를 익히고 사용하라
라이브러리 사용의 장점
- 표준 라이브러리를 사용하면 그 코드를 작성한 전문가의 지식과 여러분 보다 앞서 사용한 다른 프로그래머들의 경험을 활용할 수 있다.
- 핵심적인 일과 크게 상관 없는 문제를 해결하느라 시간을 허비하지 않아도 된다
- 따로 노력을 하지 않아도 성능이 지속해서 개선된다
- 기능이 점점 많아진다
- 우리가 작성한 코드가 많은 사람들에게 낯익은 코드가 되기 때문에 더 읽기 좋고, 유지보수하기 좋고, 재활용하기 쉽다.
적어도 java.lang, java.util, java.io 와 그 하위 패키지들에는 익숙해져야 한다.
정리
라이브러리를 적극 활용하라. 라이브러리 코드 품질은 높고, 점차 개선될 가능성이 크다
* tip 자바 7 부터 무작위 수 추출할 때 Random 보다는 ThreadLocalRandom을 사용하는 것이 좋다. 병렬 환경에서는 SplittableRandom을 사용하는 것이 좋다
정확한 답이 필요하다면 float과 double은 피하라
float과 double은 넓은 범위의 수를 빠르게 정밀한 '근사치'로 계산하도록 설계되었다. 따라서 정확한 결과가 필요할 때는 사용하면 안된다. float과 double 타입은 특히 금융 관련 계산과는 맞지 않는다. (부동소수점 때문)
금융계산에서는 BigDecimal, int 혹은 long을 사용해야 한다.
정리
정확한 답이 필요한 계산에는 float과 double을 피하라. 숫자를 아홉 자리 십진수로 표현할 수 있다면 int를 사용하고, 열 여덟 자리 십진수로 표현할 수 있다면 long을 사용하라. 열여덟 자리를 넘어가면 BigDecimal을 사용하라
박싱된 기본 타입보다는 기본 타입을 사용하라
기본 타입과 박싱된 기본 타입의 차이
- 기본 타입은 값만 가지고 있으나, 박싱된 기본 타입은 값에 더해 식별성이란 속성을 가진다. 따라서 박싱된 두 인스턴스는 값이 같아도 서로 다르다고 식별될 수 있다
- 기본 타입은 언제나 유효하나, 박싱된 기본 타입은 유효하지 않는 값 즉, null을 가질 수 있다
- 기본타입이 박싱된 기본 타입보다 시간과 메모리 사용면에서 효율적이다
박싱된 기본 타입에 == 연산자를 사용하면 오류가 일어난다. (객체 참조를 검사하게 된다)
기본 타입과 박싱된 기본 타입을 혼용한 연산에서는 박싱된 기본 타입의 박싱이 자동을 풀린다
박싱된 기본 타입 사용
- 컬렉션의 원소, 키, 값으로 쓴다. 컬렉션은 기본 타입을 담을 수 없다
- 타입 매개변수(제네릭)으로는 박싱된 기본 타입을 써야 한다
- 리플렉션을 통해 메서드를 호출할 때도 박싱된 기본 타입 사용해야 한다
정리
기본 타입과 박싱된 기본 타입 중 하나를 선택해야 한다면 기본 타입을 사용하라. 기본 타입은 간단하고 빠르다. 또한 박싱된 기본 타입을 써야 한다면 주의를 기울이자
다른 타입이 적절하다면 문자열 사용을 피하라
문자열은 다른 값 타입을 대신하기에 적합하지 않다
- 문자열은 열거 타입을 대신하기 적합하지 않다
- 문자열은 혼합 타입을 대신하기에 적합하지 않다
- 문자열은 권한을 표현하기에 적합하지 않다
정리
더 적합한 데이터 타입이 있거나 새로 작성할 수 있다면 문자열을 사용하지말라. 문자열은 잘못 사용하면 번거롭고, 덜 유연하고, 느리고, 오류 가능성도 크다. 문자열을 잘못 사용하는 흔한 예로는 기본 타입, 열거 타입, 혼합 타입이 있다
문자열 연결은 느리니 주의하라
문자열 연결 연산자 (+)는 여러 문자열을 하나로 합쳐준다. 문자열 연결 연산자로 문자열 n개를 잇는 시간은 n^2에 비례한다. 문자열은 불변이라서 두 문자열을 연결할 경우 양쪽의 내용을 모두 복사해야 해야 하므로 성능 저하는 피할 수 없다
성능을 위해 String 대신 StringBuilder(단일 스레드)/StringBuffer(멀티스레드)를 사용하자
정리
많은 문자열을 연결할 때는 문자열 연결 연산자(+)를 피하자.
객체는 인터페이스를 사용해 참조하라
적합한 인터페이스만 있다면 매개변수뿐 아니라 반환값, 변수, 필드를 전부 인터페이스 타입으로 선언하라
// 나쁜 예
LinkedListHashSet<Son> sonSet = new LinkedListHashSet<>();
// 좋은 예
Set<Son> sonSet = new LinkedListHashSet<>();
인터페이스를 타입으로 사용하면 프로그램이 유연해진다
단, 원래의 클래스가 인터페이스의 일반 규약 이외의 특별한 기능을 제공하며, 주변 코드가 이 기능에 기대어 동작한다면 새로운 클래스도 반드시 같은 기능을 제공해야 한다.
적합한 인터페이스가 없다면 당연히 클래스로 참조해야 한다. 클래스 타입을 직접 사용하는 경우는 인터페이스에 없는 추가 메서드를 꼭 사용해야 하는 경우로 최소화해야 한다.
적합한 인터페이스가 없다면 클래스의 계층구조 중 필요한 기능을 만족하는 가장 덜 구체적인 클래스를 타입으로 사용하자
리플렉션보다는 인터페이스를 사용하라
리플렉션 기능을 이용하면 프로그램에서 임의의 클래스에 접할 수 있다. Class 객체가 주어지면 클래스의 정보를 가져올 수 있고 조작할 수 있다. 강력한 기능이지만 단점도 존재한다
리플렉션 단점
- 컴파일타임 타입 검사가 주는 이점을 하나도 누릴 수 없다.
- 리플렉션을 이용하면 코드가 지저분해지고 장황해진다
- 성능이 떨어진다
리플렉션은 아주 제한된 형태로만 사용해야 그 단점을 피하고 이점만 취할 수 있다. 리플랙션은 인스턴스 생성에만 쓰고, 이렇게 만든 인스턴스는 인터페이스나 상위 클래스로 참조해 사용하자
정리
컴파일 타임에는 알 수 없는 클래스를 사용하는 프로그램을 작성한다면 리플렉션을 사용해야 한다. 단, 되도록 객체 생성에만 사용하고, 생성한 객체를 이용할 때 적절한 인터페이스나 컴파일 타임에 알 수 있는 상위 클래스로 형변환해서 사용해야 한다
네이티브 메서드는 신중히 사용하라
네이티브 메서드란 C나 C++ 같은 네이티브 프로그래밍 언어로 작성한 메서드를 말한다
네이티브 메서드의 주요한 쓰임은 다음과 같다
- 레지스트리 같은 플랫폼 특화 기능을 사용한다
- 네이티브 코드로 작성된 기존 라이브러리를 사용한다
- 성능 개선을 목적으로 성능에 결정적인 영향을 주는 영역만 따로 네이티브 언어로 작성한다
성능 개선할 목적으로 네이티브 메서드를 사용하는 것은 거의 권장하지 않는다.
정리
네이티브 메서드가 성능을 개선해 주는 일은 많지 않다. 네이티브 코드는 최소한만 사용하고 철저히 테스트하라
최적화는 신중히 하라
최적화는 좋은 결과 보다 해로운 결과로 이어지기 쉽다. 성능 때문에 견고한 구조를 희생하지 말자. 빠른 프로그램보다는 좋은 프로그램을 작성하라. 좋은 프로그램이지만 원하는 성능이 나오지 않는다면 아키텍처 자체가 최적화할 수 있는 길을 안내해줄 것이다.
만들고 최적화하는 것이 아닌 설계 단계에서 부터 성능을 반드시 염두에야 한다.
설계 규칙
- 성능을 제한하는 설계를 피하라
- API를 설계할 때 성능에 주는 영향을 고려하라
- 잘 설계된 API는 성능도 좋은 게 보통이다. 그러니 성능을 위해 API를 왜곡하는 것은 좋지 않다
최적화를 하게 된다면 각각의 최적화 시도 전후로 성능을 측정해야 한다
정리
빠른 프로그램을 작성하려 안달하지 말자, 좋은 프로그램을 작성하다 보면 성능을 따라오기 마련이다. 다만 시스템을 설계할 때 성능을 염두해 두어야 한다. 시스템을 구현 했다면 성능을 측정하고 원하는 성능이 나오지 않았을 때만 최적화를 해라. 모든 변경후에는 성능을 측정하라
일반적으로 통용되는 명명 규칙을 따르라
자바 명명 규칙은 크게 철자와 문법, 두 범주로 나뉜다. (자바 언어 명세서[JLS, 6.1])
철자 규칙은 패키지, 클래스, 인터페이스, 메서드, 필드, 타입 변수의 이름을 다룬다. 이 규칙들은 특별한 이유가 없는 한 반드시 따라야 한다
패키지와 모듈 이름은 각 요소를 점(.)으로 구분하여 계층적으로 짓는다. 요소는 모두 소분자 알파벳 혹은 숫자로 이뤄진다. 또한 조직의 인터넷 도메인 이름을 역술으로 사용한다.
패키지 이름의 나머지는 해당 패키지를 설명하는 하나 이상의 요소로 이뤄진다. 각 요소는 일반적으로 8자 이하의 짧은 단어로 한다. (ex utilities 보다는 util 처럼 의미가 통하는 약어를 추천, 여러 단어로 구성된 이름이라면 awt 처럼 약어 추천)
클래스와 인터페이스의 이름은 하나 이상의 단어로 이루어지며, 각 단어는 대문자로 시작한다. 널리 통용되는 줄임말을 제외하고 단어를 줄여 쓰지 않는다.
메서드와 필드 이름은 첫 글자를 소문자로 쓴다. 단 상수 필드는 예외이다. 상수 필드(static final 필드)를 구성하는 단어는 모두 대문자로 쓰며 단어 사이는 밑줄로 구분한다( ex NEGATIVE_INFINITY 등). 지역변수는 약어를 사용해도 좋다.
타입 매개변술 이름은 보통 한 문자로 표현한다.
- T : 임의의 타임
- E : 컬렉션 원소 타입
- K : 맵의 키
- V : 맵의 값
- X : 예외
- R : 매소드 반환 타입
문법 규칙
패키지에 대한 규칙은 따로 없다
객체를 생성할 수 있는 클래스의 이름은 보통 단수 명사나 명사구를 사용한다( ex PriorityQueue)
객체를 생성할 수 없는 클래스는 보통 복수형 명사로 짓는다(ex Collections)
인터페이스 이름은 클래스와 똑같이 짓거나(ex Collection), able 혹은 ible로 끝나는 형용사로 짓는다
어떤 동작을 수행하는 메서드의 이름은 동사나 (목적어를 포함한) 동사구로 짓는다. (ex append)
boolean 값을 반환하는 메서드라면 보통 is 나 has로 시작하고 명사나 명사구, 혹은 형용사로 기능하는 아무 단어나 구로 끝나도록 짓는다. (ex isDigit)
반환 타입의 해당 인스턴스의 속성을 반환하는 메서드의 이름은 보통 명사, 명사구, 혹은 get으로 시작하는 동사구로 짓는다(size, getTime등)
객체의 타입을 바꾸서, 다른 타입의 또 다른 객체를 반환하는 인스턴스 메서드의 이름은 보통 toType 형태로 짓는다.(ex toString)
객체의 내용을 다른 뷰로 보여주는 메서드의 이름은 asType 형태로 짓는다 (ex asList)
객체의 값을 기본 타입 값으로 반환하는 메서드의 이름은 보통 typeValue 형태로 짓는다(ex intValue 등)
정리
표준 명명 규칙을 따르자. 다만 너무 규약대로 하려고 하지 말고 상식이 이끄는 대로 따르자
'자바' 카테고리의 다른 글
이펙티브 자바 -11- (0) | 2022.01.17 |
---|---|
이펙티브 자바 -9- (0) | 2022.01.15 |
이펙티브 자바 -7- (0) | 2022.01.13 |
이펙티브 자바 -6- (0) | 2022.01.12 |
이펙티브 자바 -5- (0) | 2022.01.07 |