배경 > 이펙티브 자바 아이템 1를 참고해보면 좋을 거 같아요 :) 정적 팩터리 메서드 정적 팩터리 메서드는 객체 생성 역할을 하는 클래스 메서드다. 장점1. 이름을 가질 수 있다. 생성자 자체는 생성되는 객체의 특성을 직관적으로 설명하지는 않는다. 이렇게 메서
점층적 생성자 패턴 정적 팩터리와 생성자는 선택적 매개변수가 많을 때 적절히 대응하기 어렵다. 필드 매개변수만 받는 생성자, 필수 매개변수와 선택 매개변수 1개를 받는 생성자, 선택 매개변수를 2개 받는 생성자... 식으로 생성자를 늘려나가는 점층적 생성자 패턴을 이
싱글턴이란 인스턴스를 오직 하나만 생성할 수 있는 클래스를 말한다. ex. 함수와 같은 무상태 객체, 설꼐상 유일해야 하는 시스템 컴포넌트클래스를 싱글턴으로 만들면 이를 사용하는 클라이언트를 테스트하기 어려워질 수 있다.타입을 인터페이스로 정의하고, 인터페이스를 구현한
정적 멤버만 담은 유틸리티 클래스는 인스턴스로 만들어 쓰려고 설계한게 아니다. (정적 메서드와 정적 필드만을 담은 클래스는 객체지향적이지 않다고 비판받기도 한다)하지만 생성자를 명시하지 않으면 컴파일러가 자동으로 기본 public 생성자를 넣어준다. 추상 클래스로 만드
많은 클래스가 하나 이상의 자원에 의존한다. 정적 유틸리티를 잘못 사용한 예싱글턴을 잘못 사용한 예위 두 방식 모두 사전을 단 하나만 사용한다는 가정을 한것이다. 하지만 실전에서는 사전이 언어별로 따로있고, 테스트용 사전도 필요할 수 있다. SpellChecker가 여
똑같은 기능의 객체를 매번 생성하지 말고 객체 하나를 재사용하는게 나을 때가 많다. 이 문장은 실행될 때마다 String 인스턴스를 새로 만든다. 생성자에 넘겨진 매개변수와 생성자가 만들어내는 것이 기능적으로 완전히 똑같다. 이 문장이 반복문이나 빈번히 호출되는 메서드
자바는 가비지 컬렉터가 있지만 메모리 관리에 신경을 안써도 되는 것은 아니다. 위 코드는 메모리 누수 문제가 있다.스택이 커졌다가 줄어들었을 때 스택에서 꺼내진 객체들을 가비지 컬렉터가 회수하지 않는다. 이 스택이 그 객체들의 다 쓴 참조(obsolete referen
자바는 두 객체 소멸자가 있다. finalizer: 예측할 수 없고 위험할 수도 있다. 자바9부터 deprecated로 지정되었다.cleaner: finalizer보다는 덜 위험하지만, 여전히 예측할 수 없고 느리고 불필요하다.자바의 finalizer와 cleaner는
InputStream, OutputStream, java.sql.Connection 등은 close 메서드를 호출해 닫아줘야한다. 하지만 이걸 클라이언트가 놓치면 성능 문제가 생긴다. 안전망으로 finalizer가 있지만, 그리 믿으만하지 못하다 (아이템8).원래 닫힘
아래와 같은 상황이면 아예 equals를 재정의하지 말자.각 인스턴스가 본질적으로 고유하다. ex. Thread인스턴스의 논리적 동치성을 검사할 일이 없다.상위 클래스에서 재정의한 equals가 하위 클래스에도 딱 들어맞는다.클래스가 private 이거나 package
equals를 재정의한 클래스 모두에서 hashCode도 재정의해야 한다. 그렇지 않으면 hashCode 일반 규약을 어기게 되어 HashMap이나 HashSet 같은 컬렉션의 원소로 사용할 때 문제가 생길 수도 있다.아래는 Object 명세의 규약이다.equals 비
Object의 기본 toString은 클래스\_이름@16진수로\_표시한\_해시코드를 반환한다.toString 규약사람이 읽기 쉬운 정보를 반환하라모든 하위 클래스에서 재정의하라toString 메서드는 객체를 println, printf, 문자열 연결 연산자 (+), a
Comparable을 구현햇다는 것은 그 클래스의 인스턴스들에는 자연적인 순서가 있다는 것을 뜻한다. 그래서 Comparable을 구현한 객체들의 배열은 손쉽게 정렬이 가능하다. 자바 플랫폼 라이브러리의 모든 값 클래스와 열거 타입이 Comparable을 구현했다. 알
잘 설계된 컴포넌트는 내부 구현을 완벽히 숨겨, 구현과 API를 분리한다. 정보 은닉의 장점 시스템 개발 속도 향상. 여러 컴포넌트 병렬 개발 가능 시스템 관리 비용 절감. 컴포넌트를 더 빨리 파악 가능하고 교체 부담 감소 성능 최적화에 도움을 준다. 최적화할 컴포
패키지 바깥에서 접근할 수 있는 클래스라면 접근자를 제공함으로써 내부 표현 방식을 바꿀 수 있는 유연성을 얻을 수 있다. 필드를 공개하면 이를 사용하는 클라이언트가 생겨날 것이므로 내부 표현 방식을 마음대로 변경할 수 없다.package-private 클래스 혹은 pr
불변 클래스는 인스턴스 내부 값을 수정할 수 없는 클래스다. String, 기본 타입의 박싱된 클래스들 등이 불변 클래스의 예다. 아래는 불변 클래스를 만드는데 필요한 규칙이다. 객체의 상태를 변경하는 메서드를 제공하지 않는다.클래스를 확장할 수 없도록 한다.하위 클래
상속은 코드를 재사용하는 강력한 수단이지만, 최선은 아니다. 다른 패키지의 구체 클래스를 상속하는 일은 위험하다. 여기서 '상속'은 클래스가 다른 클래스를 확장하는 구현 상속을 말한다. 클래스가 인터페이스를 구현하거나 인터페이스가 다른 인터페이스를 확장하는 인터페이스
메서드를 재정의하면 어떤일이 일어나는지 문서화해야 한다. 상속용 클래스는 재정의할 수 있는 메서드들을 내부적으로 어떻게 이용하는지(자기사용) 문서로 남겨야 한다.공개된 메서드에서 해당 클래스의 또 다른 메서드를 호출할 수도 있다. 근데 그 다른 메서드가 재정의 가능 메
자바8부터는 인터페이스도 디폴트 메서드를 제공할 수 있게되어 인터페이스와 추상 클래스 모두 인스턴스 메서드를 구현 형태로 제공할 수 있다. 둘의 가장 큰 차이는 추상 클래스가 정의한 타입을 구현하는 클래스는 반드시 추상 클래스의 하위 클래스가 되어야 한다. 자바는 단일
디폴트 메서드를 선언하면, 그 인터페이스를 구현한 후 디폴트 메서드를 재정의하지 않은 모든 클래스에서 디폴트 구현이 쓰이게 된다. 모든 기존 구현체들과 매끄럽게 연동되리라는 보장은 없다. 디폴트 메서드는 구현 클래스에 대해 아무것도 모르고 무작정 삽입되는 것이다.디폴트
인터페이스는 자신을 구현한 클래스의 인스턴스를 참조할 수 있는 타입 역할을 하고, 즉 클래스가 어떤 인터페이스를 구현한다는 것은 자신의 인스턴스로 무엇을 할 수 있는지를 클라이언트에게 알려주는 것이다. 인터페이스는 이 용도로만 사용해야 한다. 상수 인터페이스 안티패턴은
두 가지 이상의 의미를 표현할 수 있으며, 그중 현재 표현하는 의미를 태그값으로 알려주는 클래스다. (사실 본적이 없다). 위의 코드는 원과 사각형을 표현할 수 있다. 열거 타입, 태그 필드, switch문 등 쓸데 없는 코드가 많다.여러 구현이 섞여 있어 가독성이 나
중첩 클래스는 다른 클래스 안에 정의된 클래스다. 중첩 클래스는 자신을 감싼 바깥 클래스에서만 쓰여야 하며, 그 외의 쓰임새가 있다면 톱레벨 클래스로 만들어야 한다. 중첩 클래스 종류정적 멤버 클래스(비정적) 멤버 클래스익명 클래스지역 클래스첫 번째를 제외하면 나머지는
소스 파일 하나에 톱레벨 클래스를 여러 개 선언해도 컴파일러는 문제를 표시하지 않는다. 하지만 여러 위험들이 있다. 한 클래스를 여러 가지로 정의할 수 있으며, 그중 어느 것을 사용할지는 어느 소스 파일을 먼저 컴파일하냐에 따라 달라지기 때문이다.Main.javaUte
Box<T> : 제네릭 클래스 혹은 제네렉 인터페이스. 제네릭 클래스와 제네릭 인터페이스를 통틀어 제네릭 타입이라 한다. 'T의 Box' 또는 'T Box'라고 읽는다T : 타입 변수 또는 타입 매개변수. (T는 타입 문자)Box : 원시 타입(raw typ
배열을 꼭 반환해야하는 상황이 아니라면 컬렉션을 사용하는게 어떨까요?이펙티브 자바 28. 배열보다 리스트를 사용하라이 부분은 프리코스 때도 공통 피드백에 있던 내용이었다. 당시에는 큰 이유가 없어 잘 와닿지 않았던 것 같다.배열은 공변(covariant)다. 공변성이란
Object 기반 스택 - 제네릭이 필요하다 이 클래스에는 제네릭 타입이어야 한다. 지금은 클라이언트가 스택에서 꺼낸 객체를 형변환 해야하는데, 이때 런타임 오류가 날 위험이 있다. 클래스 선언에 타입 매개변수를 추가하면된다. 제네릭 스택 첫 단계 - 컴파일되지
메서드도 제네릭으로 만들 수 있다. Collections의 알고리즘 메서드(sort, binarySearch)등은 모두 제네릭이다.로 타입 - 좋지 않다. (아이템 26)컴파일은 되지만 경고가 된다. 타입 안전하지 않기 때문이다.(타입 매개변수들을 선언하는) 타입 매개
매개변수화 타입은 불공변(invariant)이다. 즉 List<Type1>은 List<Type2>의 하위 타입도, 상위 타입도 아니다. 따져보면 말이 되는데 List<Object>에는 어떤 객체든 넣을 수 있지만, List<String>에는 문자열
가변인수 메서드를 호출하면 가변인수를 담기 위한 배열이 자동으로 하나 만들어진다. 내부로 감춰야 했을 이 배열이 클라이언트에게 노출되는 문제가 생겼다. 그래서 varargs 매개변수에 제네릭이나 매개변수화 타입이 포함되면 알기 어려운 컴파일 경고가 발생한다.거의 모든
열거 타입은 일정 개수의 상수 값을 정의하고, 그 외의 값은 허용하지 않는 것이다. 자바에서 열거 타입을 지원하기 전에는 상수를 한 묶음 선언해서 사용하고 했다. 정수 열거 패턴 기법에는 단점이 많았다. 서로 다른 종류끼리 동등 연산자(==)로 비교해도 경고 메시지가
열거 타입은 해당 상수가 그 열거 타입에서 몇 번째 위치인지를 반환하는 ordinal이라는 메서드를 반환한다. 그래서 이 ordinal을 쓰고 싶을 수 있다.나쁜 예시실제로 체스 미션을 하면서 ordinal을 사용했다. 유지보수하기 힘든 코드다. 상수 선언 순서가 바뀌
비트 열거 상수예전에는 열거 값들이 집합으로 사용될 경우 각 상수에 서로 다른 2의 거듭제곱 값을 할당한 정수 열거 패턴을 사용해왔다. 비트별 OR를 이용해 여러 상수를 하나의 집합으로 모을 수 있고, 이런 집합을 비트 필드라 한다.하지만 비트 필드는 정수 열거 상수의
이런 Enum 클래스에서 생애주기별로 총 3개의 집합을 만들고 정원을 한바퀴 돌며 각 식물을 해당 집합에 넣자. 어떤 프로그래머는 집합들을 배열 하나에 넣고 생애주기의 ordinal 값을 그 배열의 인덱스로 사용하려 할 것이다. 하지만 배열은 제네릭과 호환되지 않으니
열거 타입은 보통은 확장에 적합하지 않다. 확장할 수 있는 열거타입이 필요할 때도 있는데 연산 코드가 그 예시다. 사용자 확장 연산을 추가할 수 있도록 열어주는 것이다. 열거 타입이 임의의 인터페이스를 구현하면 된다. 인터페이스를 이용해 확장 가능 열거 타입을 흉내냈다
위의 코드는 equals 메서드를 재정의(override) 하지 않고 다중정의(overrload)했다. Object의 equals는 Object를 매개변수로 받는다. @Override 애너테이션을 달았으면 이런 일을 컴파일러가 잡아줬을 것이다. 상위 클래스의 메서드를
예전에는 함수 타입을 표현할 때 추상 메서드를 하나만 담은 인터페이스를 사용했다. 이런 인터페이스의 인스턴스를 함수 객체라했다. JDK 1.1부터는 함수 객체를 만드는 주요 수단은 익명클래스였다. 익명 클래스의 인스턴스를 함수 객체로 사용컴파일러가 문맥을 사렾 타입을
자바 8때 Map에 추가된 merge 메서드다. merge 메서드는 키, 값, 함수를 인수로 받으며 주어진 키가 맴 안에 아직 없으면 {키, 값} 쌍을 저장하고, 있으면 세 번째 인수로 받은 함수를 현재값과 주어진 값에 적용한 다음 그결과로 현재 값을 덮어쓴다. 깔끔해
람다가 지원되면서 상위 클래스의 기본 메서드를 재정의해 원하는 동작을 구현하는 템플릿 메서드 패턴의 매력이 줄었다. 현대적인 방법은 같은 효과의 함수 객체를 받는 정적 팩터리나 생성자를 제공하는 것이다. 즉 함수 객체를 매개변수로 받는 것이다.java.util.func
스트림 API가 제공하는 추상 개념 중 핵심은 두 가지다. 스트림은 데이터 원소의 유한 혹은 무한 시퀀스를 뜻한다. 스트림 파이프라인은 이 원소들로 수행하는 연산 단계를 표현하는 개념이다. 스트림 파이프라인은 소스 스트림에서 시작해 종단 연산으로 끝나며, 그 사이에 하
스트림은 그저 API가 아니라 함수형 프로그래밍에 기초한 패러다임이다. 그래서 이 패러다임까지 함께 받아들여야 한다.스트림 패러다임의 핵심은 계산을 일련의 변환으로 재구성하는 부분이다. 이때 각 변환 단계는 가능한 이전 단계의 결과를 받아 처리하는 순수 함수여야 한다.
스트림은 반복을 지원하지 않는다. 따라서 스트림과 반복을 알맞게 조합해야 좋은 코드가 나온다. API를 스트림만 반환하도록 짜놓으면 반환된 스트림을 for-each로 반복하길 원하는 클라이언트는 불만이 생긴다.Stream 인터페이스는 Iterable 인터페이스가 정의한
동시성 프로그램밍을 할때는 안전성과 응답 가능 상태를 유지하기 위해 신경써야 한다.메르센 소수 생성 프로그램메르센 소수란 소수 가운데 ‘2의 n승 빼기 1’로 표현되는 소수를 말한다.7초만에 완료되었다.성능 향상을 위해서 병렬 처리를 해보자.parallel()을 추가해
메서드와 생성자는 매개변수의 값을 몸체가 실행되기 전에 확인하면 좋다. public과 protected 메서드는 매개변수 값이 잘못됐을 때 던지는 예외를 문서화해야 한다. 클래스 수준 주석은 그 클래스의 모든 public 메서드에 적용되므로 훨씬 깔끔하다. 자바
자바는 안전한 언어다. 네이티브 메서드를 사용하지 않으니 메모리 충돌 오류에서 안전하다.그래도 클라이언트가 불변식을 깨뜨리려 혈안이 되어있다고 가정하고 방어적으로 프로그래밍해야 한다.어떤 객체든 그 객체의 허락 없이는 외부에서 내부를 수정하는 일은 불가능하다. 하지만
메서드 이름을 신중히 짓자. 항상 표준 명명 규칙(아이템 68)을 따라야 한다. 편의 메서드를 너무 많이 만들지 말자. 메서드가 너무 많으면 테스트하기 어렵고 사용하는 사람도 힘들다. 확신이 서지 않으면 만들지 말자.매개변수 목록은 짧게 유지하자.4개 이하가 좋다. 같
"집합", "리스트", "그 외"를 차례로 출력하기를 예상했지만, 실제로 수행해보면 "그 외"만 세 번 출력한다.다중정의(오버로딩)된 세 classify 중 어느 메서드를 호출할지가 컴파일타임에 정해진기 때문이다. 컴파일 타임에는 for 문 안에 c는 항상 Collec
가변인수(varargs) 메서드는 명시한 타입의 인수를 0개 이상 받을 수 있다. 가변인수 메서드를 호출하면 가장 먼저 인수의 개수와 길이가 같은 배열을 만들고 인수들을 이 배열에 저장하여 가변인수 메서드에 건내준다. 인수가 1개 이상이어야할 때도 있다. 하지만 인수
만약 null을 반환하면 null을 처리한느 코드를 작성해야 한다. 컬렉션이나 배열 같은 컨테이너가 비었을 때 null을 반환하는 메서드를 사용할 때면 항상 방어 코드를 넣어줘야 한다. 빈 컨테이너를 할당하는 데도 비용이 드니 null을 반환하는 쪽이 낫다는 주장도 있
자바 8이전에는 메서드가 특정 조건을 반환할 수 없을 때예외 반환null 반환을 했다. 하지만 각각 문제점이 있다.예외는 진짜 예외적인 상황에서만 사용해야 한다 (아이템 69). 예외를 생성할 때 스택 추적 전체를 캡처하므로 비용이 비싸다.별도의 null 처리 코드를
지역변수의 유효 범위를 최소화하면 가독성과 유지보수성이 좋아지고 오류 가능성이 낮아진다.지역변수의 범위를 줄이는 가장 강력한 기법은 처음 쓰일 때 선언하기이다.실제 사용하는 블록 바깥에 선언한 변수는 그 블록이 끝난 뒤에도 살아있따.거의 모든 지역 변수는 선언과 동시에
컬렉션 순회하기 - 더 나은 방법 존재배열 순회하기 - 더 나은 방법 존재반복자와 인덱스 변수를 코드를 지저분하게하고 오류가 생길 가능성이 높아진다. 1회 반복에서 반복자는 세 번 등장하고 인덱스는 네 번 등장하고 있다. 혹시라도 잘못된 변수를 사용했을 때 컴파일러가
표준 라이브러리는 검증된 코드다.표준 라이브러리르 쓰면 핵심적인 일에 집중할 수 있다.따로 노력하지 않아도 성능이 지속해서 개선된다.표준 라이브러리는 꾸준히 개선된다. 기능이 점점 추가된다. 부족한 부분은 다음 릴리스에 추가된다.자바 프로그래머라면 java.lang,
float과 double 타입은 과학과 공학 계산용으로 설계되었다. 따라서 정확한 결과가 필요한 금융 관련 계산과는 맞지 않는다. 금융 계산에는 BigDecimal, int 혹은 long을 사용해야 한다.이렇게 하면 사탕 4개를 구입후 정확히 0달러가 남는다. BigD
기본 타입과 박싱된 기본 타입은 차이가 있다. 박싱된 기본 타입은 값에 더해 식별성을 가진다. 그래서 박싱된 기본 타입의 두 인스턴스는 값이 같아도 서로 다르다고 식별될 수 있다. 기본 타입의 값은 언제나 유효하나, 박싱된 기본 타입은 유효하지 않은 값, 즉 null을
문자열은 다른 값 타입을 대신하기에 접합하지 않다. 받은 데이터가 수치형이라면 int, float, BigInteger등 적당한 수치 타입으로 변환해야 한다. '예/아니오' 질문의 답이라면 적절한 열거 타입이나 boolean으로 변환해야 한다.문자열은 열거 타입을 대신
문자열 연결 연산자로 문자열 n개를 잇는 시간은 n^2에 비례한다. 문자열은 불변이라서 두 문자열을 연결할 경우 양쪽의 내용을 모두 복사해야 한다.성능을 포기하고 싶지 않다면 String 대신 StringBuilder를 사용하자.네오의 강의 시간에 바이트 코드를 봤을
적합한 인터페이스만 있다면 매개변수뿐 아니라 반환값, 변수, 필드를 전부 인터페이스 타입으로 선언하라. 인터페이스를 타입으로 사용하면 프로그램이 훨씬 유연해진다. 나중에 구현 클래스를 교체할 때 새 클래스의 생성자를 호출해주기만 하면 된다. 적합한 인터페이스가 없다면
리플렉션(java.lang.reflect)을 통해 프로그램에서 임의의 클래스에 접근할 수 있다. Class 객체가 주어지면 그 클래스의 생성자, 그 주어진 그 클래스의 생성자, 메서드, 필드에 해당하는 Constructor, Method, Filed 인스턴스를 가져올
자바 네이티브 인터페이스(Java Native Interface, JIN)은 자바 프로그램이 네이티브 메서드를 호출하는 기술이다. 네이티브 메서드는 C나 C++ 같은 언어로 작성한 메서드다.주로 아래와 같은 경우 사용한다.레지스트리 같은 플랫폼 특화 기능네이티브 코드로
패키지의 각 요소는 일반적으로 8자 이하 짧은 단어로 한다. utilities 보다는 util처럼 약어를 추천한다. 여러 단어로 구성된 이름이라면 awt처럼 첫 글자만 따기도 한다.객체를 생성할 수 있는 클래스는 보통 단순 명사나 명사구를 사용한다. (Thread, P
JVM은 배열에 접근할 때마다 경계를 넘지 않는지 검사하니, 그 하나를 생략해보고자 한 코드다. 하지만 잘못 됐다. 에외는 예외 상황에 쓸 용도로 설계되었으므로 JVM 구현자가 최적화를 하지 않았을 수 있다. try-catch 블록 안에 넣으면 JVM이 적용할 수 있는
호출하는 쪽에서 복구하리라 여겨지는 상황이라면 검사 예외(checked exception)를 사용하라. checked exception은 호출자가 그 예외를 catch로 잡아 처리하거나, 위로 전파하도록 강제한다. 따라서 메서드 선언에 포함된 checked except
검사 예외를 잘 사용하면 발생한 문제를 프로그래머가 처리하여 안전성을 높여준다.하지만 과하게 쓰면 오히려 불편하게 된다.어떤 메서드가 검사 예외를 던질 수 있게 선언됐다면, 이를 호출하는 쪽에서 catch 블록을 두거나 바깥으로 던져서 전파해야 한다. 이는 클라이언트에
표준 예외를 사용하라. 많은 프로그래머가 익숙하다.클래스 수가 적으면 메모리 사용량도 줄고 클래스 적재 시간도 적게 걸린다.많이 쓰이는 예외IllegalArgumentException: 호출자가 인수로 부적절한 값을 넘길 때 던지는 예외.IllegalStateExcep
메서드가 저수준 예외를 처리하지 않고 바깥으로 전파하면 윗 레벨 API를 오염시킨다. 상위 계층에서는 저수준 예외를 잡아 자신의 추상화 수준에 맞는 예외로 바꿔 던져야 한다. 이를 번역 예외(exception translation)이라 한다.예외를 번역할 때 저수준 예
예외는 아주 중요한 정보다. 검사 예외는 항상 딸로따로 선언하고, 각 예외 발생 상황을 자바독의 @throws 태그로 정확히 문서화하자. 공통 상위 클래스 하나로 뭉뚱그리지 말자.유일한 예외는 main메서드다. main은 오직 JVM만이 호출하므로 Exception을
예외를 잡지 못해 프로그램이 실패하면 스택 추적(stack trace)가 출력된다. 스택 추적은 예외 객체의 toString 메서드를 호출해 얻는 문자열이다. 만약 실패를 재현하기 어려우면 자세한 정보를 얻기가 어렵다. 그래서 실패 원인에 관한 정보를 가능한한 많이 담
실패 원자적(failure-atomic): 호출된 메서드가 실패하더라도 해당 객체는 메서드 호출 전 상태를 유지해야 한다.예를 들어 작업 도중 예외가 발생하도 그 객체는 여전히 정상적으로 사용할 수 있는 상태. 메서드를 실패 원자적으로 만드는 방법은 다양하다. 불변 객
메서드 선언에 예외를 명시하는 것은 적절한 조취를 취해달라고 말하는 것이다. 위에 처럼 catch 블록을 비워두면 예외가 존재할 이유가 없어진다.예외를 무시하기로 했다면 catch 블록안에 그렇게 결정한 이유를 주석으로 남기고 예외 변수의 이름도 ignored로 바꿔
synchronized 키워드는 해당 메서드나 블록을 한번에 한 스레드씩 수행하도록 보장한다.한 객체가 일관된 상태를 가지고 생성되고, 이 객체에 접근하는 스레드가 락을 건다. 상태를 확인하고 필요하면수정한다. 일관된 상태에서 다른 일관된 상태로 변화시키는 것이다. 그
역직렬화에 시간이 오래 걸리는 짧은 스트림을 역직렬화하는 것만으로 서비스 거부 공격에 노출될 수 있다.직렬화 위험을 회피하는 가장 좋은 방법은 아무것도 역직렬화하지 않는 것이다. 객체와 바이트 시퀀스를 변환해주는 다른 메커니즘이 많이 있따. 자바 직렬화를 써야할 이유는