Effectivie Java

직렬화: 객체 -> 바이트 스트림역직렬화: 바이트 스트림 -> 객체직렬화된 객체는 다른 VM에 전송하거나 디스크에 저장한 후 나중에 역직렬화할 수 있다. 직렬화를 통해 프로그래머가 어렵지 않게 분산 객체를 만들 수 있다는 취지였지만, 실상은 보이지 않는 생성자, API와 구현 사이의 모호해진 경계, 성능, 보안 등 그 대가가 컸다. 지금까지 경험한 바로는 단점이 더 컸다. 직렬화의 근본적인 문제는 공격 범위가 너무 넓고 지속적으로 넓어져 방어하기 어렵다는 점이다. 이는 역직렬화될 때, ObjectInputStream의 readObject 메서드가 호출되기 때문인데, 이 메서드는 클래스패스 안의 거의 모든 타입의 객체를 만들어 낼 수 있는, 마법 같은 생성자이기 때문이다. 가젯(gadget): 역직렬화 과..

지연 초기화 : 필드의 초기화 시점을 그 값이 처음 필요할 때까지 늦추는 방법. 최선의 조언은 "지연 초기화는 필요할 때까지는 하지 말라"이다. 지연 초기화는 양날의 검이다. 지연초기화하는 필드에 접근하는 비용이 커지기 때문이다. 실제로는 성능을 느려지게 할 수도 있다.public class LazyExample { private String data; public String getData() { if (data == null) { // 초기화 체크 data = "지연 초기화된 값"; } return data; }} 그럼에도 해당 클래스의 인스턴스 중 그 필드를 사용하는 인스턴스의 비율이 낮은 반면, 그 필드를 초기화하는 비용이 ..

검사 예외(checked exception)은 항상 따로따로 선언하고, 각 예외가 발생하는 상황을 자바독의 @throws 태그를 사용하여 정확히 문서화하자. 공통 상위 클래스 하나로 뭉뚱그려 선언하는 일은 삼가자.throws Exception이나 Throwable을 하면 안된다. 사용자에게 각 예외에 대처할 수 있는 힌트도 못주고 다른 예외들까지 삼켜버릴 수 있다. main() 메서드는 오직 JVM만이 호출하므로 Exception을 던지도록 선언해도 괜찮다. /** * @throws IllegalStateException */public void testMethod(String parameter) throws IllegalStateException { }비검사 예외(unchecked exception)..

자바의 데이터 타입1. 기본형: int, double, boolean 등2. 참조형: String, List, Integer, Double, Boolean 등각각의 기본 타입에 대응하는 참조 타입 = 박싱된 기본 타입 주된 차이 세 가지1. 기본 타입은 값만 가지고 있으나, 박싱된 기본 타입은 값 + 식별성을 가지고 있다. 즉 메모리 주소를 할당받는다.그러므로 박싱된 기본 타입의 두 인스턴스는 값이 같아도 서로 다르다고 식별될 수 있다.2. 기본 타입의 값은 언제나 유효한 반면 박싱된 기본 타입은 유효하지 않은 값, 즉 null을 가질 수 있다.3. 기본 타입이 박싱된 기본 타입보다 시간과 메모리 사용면에서 더 효율적이다. 문제 1.박싱된 기본 타입에 == 연산자를 사용하면 예상치 못한 에러가 발생할 수..

자바의 명명 규칙은 크게 철자, 문법 두 범주로 나뉜다. 철자1. 패키지와 모듈 이름은 각 요소를 점으로 구분하여 계층적으로 짓는다. 요소들은 모두 소문자 알파벳 혹은 (드물게) 숫자로 이뤄진다. 조직 바깥에서도 사용될 패키지라면 조직의 dns 이름을 역순으로 사용한다.(예시: com.google) 2. 클래스와 인터페이스의 이름은 하나 이상의 단어로 이뤄지며, 각 단어는 대문자로 시작한다. 널리 통용되는 줄임말을 제외하고는 단어를 줄여 쓰지 않도록 한다.3. 메서드와 필드 이름은 첫 글자를 소문자로 쓴다는 점만 빼면 클래스 명명 규칙과 같다. 4. 상수 필드는 모두 대문자로 쓰며 단어 사이는 밑줄로 구분한다. (NEGETIVE_INFINITY)5. 지역변수에서도 다른 멤버와 비슷한 명명 규칙이 적용된..

한 줄짜리 출력값 혹은 작고 크기가 고정된 객체의 문자열 표현을 만들때라면 괜찮지만, 많이 연결해야 한다면 성능 저하는 불가피하다. 문자열은 불변이라서 두 문자열을 연결할 경우 문자열 각각을 복사해서 더해야 함으로 문자열 n개를 잇는 시간은 n2에 비례한다. 성능을 높이고 싶으면 String 대신 StringBuilder를 사용하라.시간이 약 6배 빨라진다.StringBuilder는 메서드 체이닝 방식을 통해한 줄짜리 출력값 혹은 작고 크기가 고정된 객체의 문자열 표현을 만들때라면 괜찮지만, 많이 연결해야 한다면 성능 저하는 불가피하다. 문자열은 불변이라서 두 문자열을 연결할 경우 문자열 각각을 복사해서 더해야 함으로 문자열 n개를 잇는 시간은 n2에 비례한다. String 연결은 매번 새로운 객체를 생..

명명 패턴이란, 변수나 함수의 이름을 일관된 방식으로 작성하는 패턴.예를 들어 JUnit은 버전 3까지 테스트 메서드 이름을 test로 시작하게 하였다. testMethod()하지만 이 방식은 단점이 크다. 첫 번째 단점, 오타가 나면 안된다. tetsMethod로 잘못 작성하면 테스트 무시하고 지나간다.두 번째 단점, 올바른 프로그램 요소에서만 사용되리라 보증할 방법이 없다. (즉, 메서드에서만 test로 시작하는 명명을 하리라 보증할 방법이 없다는 것) 메서드가 아닌 클래스 이름을 test로 시작하게 지어서 넘겨주면 개발자는 이 클래스에 정의된 테스트 메서드들이 수행되길 바랬지만 JUnit은 클래스 이름에 관심이 없기에 경고도 띄우지 않은 채 테스트들은 수행되지 않는다.세 번째 단점, 프로그램 요소를..

배열 vs 리스트 첫 번째 차이,배열은 공변이다. -> Sub가 Super의 하위 타입이면, Sub[]는 Super[]의 하위타입이다.제네릭은 불공변이다. -> List와 List는 서로 다른 타입이다. 문제는 배열에 있다.public static void main(String[] args) { Object[] objects = new Long[1]; objects[0] = "haha";}Exception in thread "main" java.lang.ArrayStoreException: java.lang.StringLong 배열에 String을 넣으려고 하니 런타임 에러가 터진다. ArrayStoreException : Thrown to indicate that an attempt has ..


5장 들어가기 전에, 제네릭을 지원하기 전에는 컬렉션에서 객체를 꺼낼 때마다 형변환을 해야 했다.public static void main(String[] args) { List list = new ArrayList(); list.add(1); int get = (Integer) list.get(0); String str = (String) list.get(0);}*런타임 예외 발생java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String위와 같은 코드는 런타임 예외가 발생한다. 런타임 에러는 프로그램 실행 중 발생하기 때문에 크리티컬한 이슈를 발생시킬 수 있을 뿐만 아니라..