* 복붙의 오류로 2번째 while에서 i2가 아닌 i를 씀.
* 그래서 i2가 비어있다고 착각하는 경우도 있다.
* 만약 for문이었으면 컴파일 단계에서 오류가 나기 때문에 잡을수 있었다.
* 또 for문이 좋은거는 아래같은 코드를 복붙해도 오류 없이 복붙 가능
```java
for(int i = 0 ; i< n; i ++)
메서드를 작게 유지하고 한 가지 기능에 집중
58. 전통적인 for 문보다는 for-each문을 사용해라
for(Iterator<Element> i = c.iterator(); i.hasNext();) {
Element e = i.next(); ...
// e로 무언가 한다.
}
for (int i = 0; i< a.length; i++) {
// a[i] 로 무언가를 함
}
둘다 while 보다는 낫지만 가장 좋은방법은 아님.
for-each를 사용하면, 속도도 그대로이고, 버그찾기도 쉬움.
for (Element e : elements) {
// e로 무언가를 한다.
예시에서 2중 for문으로 i.next() 를 잘못 사용하는 바람에 i*j 가 아닌 회수만큼 호출하고, NoSuchElementException 을 던짐
java 8 부터 Collection의 removeIf 를 사용해 명시적으로 순회하는일을 피할 수 있음
변형 - 리스트나 배열을 순회하면서 그 일부 혹은 전체를 교체해야한다면, 배열의 인덱스를 사용해야함
병렬 반복 - 여러 컬렉션을 병렬로 순회해야 하는 경우
59. 라이브러리를 익히고 사용해라
표준 라이브러리를 사용하면 그 코드를 전문가의 지식으로 편리하게 사용 가능
예시로 random 메서드를 제작, 완벽한 랜덤이 아님.
하지만 해당 문제를 해결하기 위해 Random.nextInt(int) 를 라이브러리에서 만들어 두었음
자바7부터는 ThreadLocalRandom 으로 대체하면 대부분 잘 동작
핵심적인 일과 관련없는 일에 시간낭비하지 않을 수 있다.
노력하지 않아도 성능이 지속적으로 개선
기능도 다양하게 많음
다른사람이 내 코드를 봐도 낯익은 코드로 보임
60. 정확한 답이 필요하다면 float와 double은 피해라
이진 부동소수점 연산에 쓰이며, 넓은 범위의 수를 빠르게 근사치로 계산하도록 섥몌되어 있음
특히 금융관련 계산과 맞지 않음
System.out.println(1.00-9*0.10); => 0.0999999999999998 로 나옴
BigDecimal, int 또는 long 을 사용해라.
BigDecimal 의 단점은 느리고, 쓰기 불편함
int,long 을 쓴다면 다룰수는 있지만 소수점은 직접관리가 필요.
61. 박싱된 기본 타입보다는 기본 타입을 사용하라
기본타입 : int, double, boolean
참조타입 String, List
박싱된 기본 타입 : Integer, Double, Boolean
기본타입과 박싱된 기본 타입의 차이
기본 타입은 값만 가지고 있으나 박싱된 기본 타입은 식별성 속성을 갖는다.(같아도 다르다고 식별)
== 의 연산자를 사용하면 오류가 발생해서, compare 메서드를 사용해야함
null 을 가질 수 있다
Integer 와 int 를 비교할때 i == 42 로 비교하게 되면 Integer 가 풀리며, 기본값이 null 로 비교, 따라서 npe 발생
기본타입이 메모리 사용면에서 더 효율적이다.
62. 다른 타입이 적절하다면 문자열 사용을 피해라
문자열은 다른 값 타입을 대신하기 적합하지 않음
파일, 네트워크, 키보드 입력으로 받을때 진짜 문자열만 문자열로 받는게 좋음
수치라면 int, float, BigInteger, 질문의 답이라면 열거타입이나 boolean 으로 변환해야함
문자열은 열거 타입을 대신하기에 적합하지 않음
상수를 열거할때는 문자열보다 열거 타입이 훨씬 좋음
문자열은 혼합 타입을 대신하기에 적합하지 않음
className + "#" + i.next();
문자열 파싱해야해서 느리고, 귀찮고 오류가능성도 높음
문자열은 권한을 표현하기에 적합하지 않음
의도치 않은 자원 공유가 이뤄질 수 있음
63. 문자열 연결은 느리니 주의하라
문자열 (+) 연산자는 문자열들을 하나로 합춰줘서 편리하지만 n^2 시간이 걸림.
문자열은 불변이라 양쪽의 내용을 모두 복사해야함.
String 대신 StringBuilder 를 사용하자.
64. 객체는 인터페이스를 사용해 참조해라.
적합한 인터페이스만 있다면 매개변수뿐 아니라 반환값, 변수, 필드를 전부 인터페이스 타입으로 선언해라.
인터페이스를 타입으로 사용하는 습관을 길러두면 프로그램이 훨씬 유연해진다.
LinkedHashSet<Son> sonSet = new LinkedHashSet<>();
Set sonSet = new HashSet<>();
* 단 주의해야할점
* 원래 `LinkedHashSet` 을 사용했고, 이것의 순서 보장을 이용해서 다른코드에 이용되었다면 바꾸면 안된다.
* 선언 타입과 구현 타입을 동시에 바꿀 수 있으니, 변수를 구현타입으로 선언해도 괜찮을 수 있지만, 컴파일 안되는 경우 존재
* 기존 타입에서만 사용하는 메서드를 사용했거나, 기존 타입을 사용하는 메서드에 그 인스턴스를 넘기면 새로운 코드에서는 컴파일 불가
* 변수를 인터페이스 타입으로 선언하면 이런일 발생 X
* 적합한 인터페이스가 없다면 당연히 클래스로 참조해야 함.
## 65. 리플렉션보다는 인터페이스를 사용하라
* 리플렉션을 이용하면 임의의 클래스에 접근 해서 생성자, 메서드, 필드를 조작 가능
* 컴파일 당시에 존재하지 않던 클래스도 이용 가능
* 하지만 단점들이 존재
* 컴파일타임 타입 검사가 주는 이점 누릴 수 없음
* 리플렉션을 이용하면 코드가 더러워짐
* 성능 저하
## 66. 네이티브 메서드는 신중히 사용
* 네이티브 인터페이스 : 자바 프로그램이 네이티브 메서드(c나 c++ 언어로 작성된 메서드) 를 호출하는 기술
* 네이티브 메서드 주요 쓰이는곳
1. 레지스트리 같은 플랫폼 특화 기능 사용
2. 네이티브 고드로 작성된 기존 라이브러리 사용, 레거시 데이터를 사용하는 레거시 라이브러리
3. 성능 개선을 목적으로 성능에 결정적인 영향을 주는 영역만 따로 네이티브 언어로 작성
* 자바가 발전하면서 하부 플랫폼의 기능을 점차 흡수하고, 네이티브 메서드 사용할 필요가 점점 줄어드는중.
* 하지만 대체할만한 자바 라이브러리가 없는 네이티브 라이브러리를 사용할때만 쓴다.
* `성능 개선을 목적으로는 권장하지 않음` => 자바3 라면 다르지만 jvm 발전 속도가 빨라서 대부분 자바로 해결 가능
* 정말 고 성능의 다중 정밀 연산이 필요하면 gnu 다중 정밀 연산 라이브러리 GMP 사용을 고려
* 네이티브 메서드의 심각한 단점
* 안정성이 떨어져서 애플리케이션 메모리 훼손 오류로 안전하지 않음
* 자바보다 플랫폼을 많이 타서 이식성이 낮고 디버깅 어려움
* 주의하지 않으면 오히려 속도 저하
* GC가 네이티브 메모리는 자동회수 못하고, 추적도 불가.
* 자바코드, 네이티브 넘나들때마다 비용 추가
* 접착코드를 작성하는것도 너무 귀찮고, 가독성 떨어짐
## 67. 최적화는 신중히 하라
* 성능때문에 견고한 구조를 희생하지 말자.
* 빠른프로그램보다 좋은 프로그램을 작성하자.
* 성능이 나오지 않는다면 그 아키텍처 자체가 최적화할 수 있는 길을 안내해준다.
* 성능을 무시하라는 뜻은 아님. 구현상의 문제는 나중에 최적화해서 해결 가능, 아키텍처의 결함이 성능을 제한하는 상황이라면 시스템 전체를 다시 작성하지 않고는 해결 불가능
* 성능을 제한하는 설계를 피해라.
* 완성 후 변경하기 가장 어려운것은 컴포넌트끼리, 외부 시스템과의 소통방식.
* api, 네트워크 프로토콜, 영구 저장용 데이터 포맷이 대표적
* 이런건 변경하기 어렵거나 불가능하고, 시스템 성능을 심각하게 제한함.
* api를 설계할 때 성능에 주는 영향을 고려
* public 을 가변으로 만들면 불필요한 방어적 복사를 수없이 유발.
* 컴포지션으로 해결할 수 있음에도 상속 방식으로 설계된 public 클래스는 상위 클래스에 종속, 그 성능의 제약도 물려받음
* 인터페이스도 있는데 굳이 구현타입을 사용하는건 좋지 않음.
* 나중에 더 빠른 구현체가 나와도 사용 못함
* 성능을 위해 api를 왜곡하는 건 좋지 않음.
* 왜곡된 api와 이를 지원하는 데 따르는 고통은 영원히 계속.
정리)
* 빠른 프로그램은 중요 ㄴㄴ 좋은 프로그램을 작성하다 보면 성능은 따라옴
* 시스템을 설계할 때(api,네트워크 프로토콜, 영구 저장용 데이터)는 성능을 염두해야함
* 시스템 구현을 완료했다면 성능을 측정하고 충분히 빠르다면 그것으로 끝.
* 프로파일러를 사용해 문제의 원인이 되는 지점을 찾아 최적화를 수행.
* 어떤 알고리즘을 사용했는지 살펴보고, 알고리즘이 문제였다면 다른 저수준 최적화는 소용 ㄴㄴ
* 만족할때 까지 반복하고 모든 변경 후에 성능 측정
## 68 일반적으로 통용되는 명명규칙을 따르라
정리 )
* 표준 명명규칙이 자연스럽게 베어나오도록 하자..
* 철자 규칙은 직관적이라 모호한게 적지만, 문법 규칙은 더 복잡하고 느슨함.
* "오랫동안 따라온 규칙과 충돌한다면 그 규칙을 맹종해서는 안됨"
* 상식이 이끈느대로 행동 ㄱㄱ
9장. 일반적인 프로그래밍 원칙
아이템 57 지역변수 범위를 최소화
가장 처음 쓰일 때 선언
거의 모든 지역변수는 선언과 동시에 초기화
try-catch
는 예외, 초기화 하는 표현식에 검사 예외가 가능하다면, try에서 초기화 해야함Iterator i2 = c2.iterator();
while(i.hasNaxt()) { // 버그
doSomething(i2.next());
}
메서드를 작게 유지하고 한 가지 기능에 집중
58. 전통적인 for 문보다는 for-each문을 사용해라
i.next()
를 잘못 사용하는 바람에 i*j 가 아닌 회수만큼 호출하고,NoSuchElementException
을 던짐파괴적인 필터링
- 컬렉션 순회하면서, 원소를 제거해야 한다면,remove
메서드를 호출해야함removeIf
를 사용해 명시적으로 순회하는일을 피할 수 있음변형
- 리스트나 배열을 순회하면서 그 일부 혹은 전체를 교체해야한다면, 배열의 인덱스를 사용해야함병렬 반복
- 여러 컬렉션을 병렬로 순회해야 하는 경우59. 라이브러리를 익히고 사용해라
표준 라이브러리를 사용하면 그 코드를 전문가의 지식으로 편리하게 사용 가능
Random.nextInt(int)
를 라이브러리에서 만들어 두었음ThreadLocalRandom
으로 대체하면 대부분 잘 동작핵심적인 일과 관련없는 일에 시간낭비하지 않을 수 있다.
노력하지 않아도 성능이 지속적으로 개선
기능도 다양하게 많음
다른사람이 내 코드를 봐도 낯익은 코드로 보임
60. 정확한 답이 필요하다면 float와 double은 피해라
근사치
로 계산하도록 섥몌되어 있음특히 금융관련 계산과 맞지 않음
BigDecimal
,int
또는long
을 사용해라.61. 박싱된 기본 타입보다는 기본 타입을 사용하라
==
의 연산자를 사용하면 오류가 발생해서,compare
메서드를 사용해야함Integer
와int
를 비교할때i == 42
로 비교하게 되면 Integer 가 풀리며, 기본값이 null 로 비교, 따라서 npe 발생62. 다른 타입이 적절하다면 문자열 사용을 피해라
63. 문자열 연결은 느리니 주의하라
StringBuilder
를 사용하자.64. 객체는 인터페이스를 사용해 참조해라.
Set sonSet = new HashSet<>();