적합한 인터페이스만 있다면 매개변수[아이템 51] 뿐 아니라 반환값, 변수, 필드를 전부 클래스가 아닌 인터페이스 타입으로 선언하라. (객체의 실제 클래스를 사용할 상황은 오직 생성자로 생성할 때뿐) //좋은 예 : 인터페이스를 타입으로 사용 Set sonSet = new LinkedHashSet(); //나쁜 예 : 클래스를 타입으로 사용 LinkedHashSet sonSet = new LinkedHashSet(); 인터페이스를 타입으로 사용할 때 유연성 증가 프로그램이 훨씬 유연해진다. 나중에 구현 클래스를 교체하고 싶다면 그저 새 클래스의 생성자 or 다른 정적 팩터리를 호출해주기만 하면 된다. 다른 코드는 전혀 손대지 않아도 된다. //Set sonSet = new LinkedHashSet(); ..
문자열 연결 연산자 (+) 문자열 연결 연산자(+)는 여러 문자열을 편리하게 합쳐주지만, 본격적으로 사용하면 성능 저하를 감내하기 어려움 문자열 연결 연산자로 문자열 n개를 잇는 시간은 n^2에 비례 (문자열은 불변 [아이템 17] 이라서 두 문자열 연결 시 양쪽 내용을 모두 복사해줘야해서) //문자열 연결을 잘못 사용한 예 - 느리다 public String statement() { String result = ""; for(int i=0; i
문자열을 쓰지 않아야 할 사례 1) 문자열은 다른 값 타입을 대신하기에 적합하지 않다. 기본 타입이든 참조 타입이든 적절한 값 타입이 있다면 그것을 사용하고, 없다면 새로 하나 작성하라. 2) 문자열은 열거 타입을 대신하기에 적합하지 않다. 상수를 열거할때는 문자열보다 열거 타입이 월등히 좋다. [아이템 34] 3) 문자열은 혼합 타입을 대신하기에 적합하지 않다. 여러 요소가 혼합된 데이터를 하나의 문자열로 표현하는 것은 좋지 않다. String compoundKey = className + "#" + i.next(); 각 요소를 개별로 접근하려면 문자열을 파싱해야해서 느리고 귀찮고 오류 가능성도 커진다. equals, toString, compareTo 메서드를 제공할 수 없다. → 차라리 전용 클래스..
자바의 데이터 타입 기본 타입 : int, double, boolean 등 참조 타입 : String, List 각각의 기본타입에 대응하는 참조 타입이 하나씩 있음 → 박싱된 기본 타입 (Integer, Double, Boolean) 오토박싱과 오토언박싱 덕분에 두 타입을 크게 구분하지 않고 사용할 수 있지만, 둘 사이엔 분명한 차이가 있으니 뭘 사용하는진 매우 중요 기본 타입 vs 박싱된 기본 타입 1) 기본 타입은 값만 가지고 있지만, 박싱된 기본 타입은 값에 더해 식별성(identity)이란 속성도 갖고 있음 박싱된 기본 타입의 두 인스턴스는 값이 같아도 서로 다른 인스턴스라고 식별됨 ( == 로 비교시) Comprator naturalOrder = (i, j) -> (i < j) ? -1 : (i..
float와 double 연산은 정확하지 않다. (특히 금융 관련 계산과는 맞지 않음) double result = 1.03 - 0.42; System.out.println(result); // 0.6100000000000001 위와 같은 단순한 계산에도 오차가 발생한다. → float와 double은 부동소수점 방식을 사용하기 때문 부동소수점 방식 부동소수점 방식은 수를 정수와 실수로 구분하지 않고 지수부와 가수부로 구분한다. 소수점이 고정되지 않기 때문에 더 폭넓은 범위를 표현할 수 있지만, 필연적으로 오차가 발생하여 근사값을 구한다. 해결 방법 1) BigDecimal double 타입을 BigDecimal 을 사용하면 실수 연산을 오차없이 사용할 수 있다. BigDecimal은 기본 타입보다 쓰기..
static Random rnd = new Random(); static int random(int n){ return Math.abs(rnd.nextInt()) % n; } public static void main(String[] args) { int n = 2 * (Integer.MAX_VALUE / 3); int low = 0; for (int i = 0; i < 1_000_000; ++i) if (random(n) < n/2) low++; System.out.println(low); } 위 코드는 무작위 정수를 하나를 생성하는 코드인데 문제점이 많다. n이 그리 크지 않은 2의 제곱수라면 얼마 지나지 않아 같은 수열이 반복된다. n이 2의 제곱수가 아니라면 몇몇 숫자가 평균적으로 더 자주 반환된..
전통적인 for문 //컬렉션 순회하기 for (Iterator i = c.iterator(); i.hasNext()) { Element e = i.next(); // ... } //배열 순회하기 for (int i = 0; i < a.length; i++) { // ... } 위 for문은 while문보다는 낫지만 [아이템 57] 가장 좋은 방법은 아님 반복자와 인덱스 변수는 코드를 지저분하게 함 → 우리에게 정말 필요한건 원소들뿐 요소 종류가 늘어나면 오류 가능성이 높아짐 컬렉션이냐 배열이냐에 따라 코드 형태가 매우 달라짐 for-each 문 //컬렉션 순회하기 for(Element e : elements) { // ... } //배열 순회하기 for(int i : a) { // ... } for-ea..
지역변수의 유효 범위를 최소로 줄이면 코드 가독성과 유지보수성이 높아지고 오류 가능성은 낮아짐 지역변수 범위를 줄이는 방법 1) 가장 처음 쓰일 때 선언하기 사용하려면 멀었는데, 미리 선언부터 해두면 코드가 어수선해져 가독성 떨어짐 범위를 제대로 제한하지 않으면 이미 사용한 뒤에도 할당 해제가 되지않고 힙 메모리에 유지됨 2) 거의 모든 지역변수는 선언과 동시에 초기화해야함 초기화에 필요한 정보가 충분하지 않다면 그때까지 선언을 미뤄야함 try-catch 문은 예외 : 변수 초기화 과정에서 검사 예외를 던질 가능성이 있다면 try 블록안에서 초기화해야함 반복문 : for, for-each 문은 반복 변수의 범위가 반복문 블록 안으로 제한됨 → 반복 변수의 반복문이 종료된 이후에도 써야하는 게 아니면 wh..