final키워드 :
。변수,method,class에 선언하여 활용
。final은 불변하지 않다 ( 중요 )
▶ 오직 재할당을 금지하는 역할만 수행
effectively final
。final로 명시적으로 선언하지 않아도, 변수에 한번만 값이 할당되고 그 이후 재할당이 전혀 일어나지않는변수에 한해람다식또는익명클래스에 의해final로 간주되는 기능
final 변수:
。객체참조변수,변수에 선언하며 한번 값이 할당 될 경우 그 이후에재할당을 금지
▶상수와 의미가 유사
。객체참조변수에 선언 시참조대상객체의주소가 고정되어있으므로할당이 불가능하지만,객체내부 값은 변경가능
▶객체를불변객체로 만드는 경우 내부인스턴스 변수에도final선언
。final을 통해변수에불변속성을 부여할 수 있으나, 일부자료구조 객체(Map,Set등 )의 경우 보장이 안되므로자료구조객체.of(값)을 통해불변성을 보장하는자료구조 객체를 생성
상수와 차이점?
。final 변수: 각클래스 객체에서인스턴스 변수로서메모리 할당되어Heap 영역에 저장
▶객체생성시점부터프로그램 수명주기동안메모리 할당
。상수(static final) : 유일한클래스 변수로서Static 영역에서 저장
▶Compile Time부터프로그램 수명주기동안메모리 할당
final 메소드:
。선언된메소드를자식클래스에서메소드 오버라이드할 수 없도록 설정.
ex )템플릿 메소드 패턴에서템플릿메소드를자식클래스에서메소드 오버라이딩을 방지하기위해 사용
final 클래스
。 더 이상자식클래스를 가질 수 없는Class
▶ 해당클래스를 다른클래스에서상속할 수 없도록 설정
불변(Immutablility)
。변수,객체가 생성된 후에는상태를 변경할 수 없도록 금지하는 특성
▶가변(Mutable)과 반대 개념
。클래스는 되도록 내부인스턴스변수에final을 선언하는 등불변으로 만들어야하며 만약불변으로 만드는게 불가능하면변경 가능성을 최소화
▶가변적으로 만들어야하는 타당한 이유가 있는게 아니면 되도록불변으로 구축
변수에불변성이 없는 경우
ex )JS의var type
。초기값정의 없이변수만 선언 및 사용가능
▶var a;만 선언하고 값을 할당안하고 호출 시undefined도출
▶불변성이 있는 경우 반드시값이 지정되어야함.
JAVA의불변변수,불변객체
불변 변수( Immutable Variable )
。변수앞에final 키워드를 선언
▶변수의재할당을 금지하여불변특성을 부여하여사이드이펙트를 사전에 방지
。객체참조변수에 선언 시참조대상객체의주소가 고정되어있으므로할당이 불가능하지만,객체내부 값은 변경가능
▶객체를불변객체로 만드는 경우 내부인스턴스 변수에도final선언
불변 객체( Immutable Object )
。클래스내인스턴스변수에final을 선언 및생성자를 통해 값 할당하여final을객체참조변수에 선언한불변객체를 생성
▶ 생성 후 그상태( =인스턴스변수)를 변경할 수 없는객체
。불변객체의 복제는 보통copyOf()를 사용한다.
。일부자료구조 인터페이스(Map,Set등 )의 경우자료구조객체.of(값)을 통해불변성을 보장하는자료구조 불변객체를 생성
。생성자를 통해변수에 값을 전달하여불변객체를 생성 시 이후 내부불변변수수정이 불가능
▶불변객체의상태변경 시새 객체를 생성하여재할당하는 방식으로 방식으로 변경해야한다.
▶상태변경시 마다 새객체를 생성하지만 수명이 짧으므로GC의 청소대상이 되기 쉽다.// 불변객체 class Money{ private final int amount; // 인스턴스 변수에 final 선언 public Money(int amount){ this.amount = amount; } } // 선언 final Money m = new Money(2000);
Java에서변수에final을 선언 시불변성을 보장할 수 없는 이유
。final은 선언된변수,객체참조변수에 선언 시값의재할당을 금지하는 기능을 수행.
。자료구조 객체(Map,Set등 )의 경우값을 변경하는게 아닌객체.add(데이터)로객체에 요소를 추가하므로final에 의해불변성을 보장받을 수 없음
▶자료구조객체.of(값)을 통해불변성을 보장하는자료구조 객체를 생성final Set<Integer> Set1 = new HashSet<Integer>(); Set<Integer> Set2 = Set.of(1, 2); Set1.add(3); // 불변객체가 아니므로 데이터 삽입 수행됨 Set2.add(3); // 불변객체에 데이터를 넣으려고 시도했으므로 오류 발생
final키워드 :
。변수,method,class에 선언하여 활용
。final은 불변하지 않다 ( 중요 )
▶ 오직 재할당을 금지하는 역할만 수행
final 변수:
。객체참조변수,변수에 선언하며 한번 값이 할당 될 경우 그 이후에재할당을 금지
▶상수와 의미가 유사
。객체참조변수에 선언 시참조대상객체의주소가 고정되어있으므로할당이 불가능하지만,객체내부 값은 변경가능
▶객체를불변객체로 만드는 경우 내부인스턴스 변수에도final선언
。final을 통해변수에불변속성을 부여할 수 있으나, 일부자료구조 객체(Map,Set등 )의 경우 보장이 안되므로자료구조객체.of(값)을 통해불변성을 보장하는자료구조 객체를 생성
상수와 차이점?
。final 변수: 각클래스 객체에서인스턴스 변수로서메모리 할당되어Heap 영역에 저장
▶객체생성시점부터프로그램 수명주기동안메모리 할당
。상수(static final) : 유일한클래스 변수로서Static 영역에서 저장
▶Compile Time부터프로그램 수명주기동안메모리 할당
final 메소드:
。선언된메소드를자식클래스에서메소드 오버라이드할 수 없도록 설정.
ex )템플릿 메소드 패턴에서템플릿메소드를자식클래스에서메소드 오버라이딩을 방지하기위해 사용
final 클래스
。 더 이상자식클래스를 가질 수 없는Class
▶ 해당클래스를 다른클래스에서상속할 수 없도록 설정
불변의 특징
。코드를 안전하고 예측가능하며 안정적인서비스개발및유지보수가 용이하도록 하는 역할을 수행
1.Thread Safe
。불변 변수는병렬프로그래밍에 유용하며동기화를 고려하지 않아도 됨.
▶ 여러스레드들로부터Concurrent하게 접근되어Race Condition이 발생해도 값이 변경되지않으며 항상 동일한 값을 반환하므로
。런타임이 아니더라도 여러스레드에서Concurrent하게 접근하는변수에 대해불변 속성을 부여 시 해당변수가human error로 수정이 될 경우 사전에컴파일러에 의해 검출되어 수정을 예방하는 용도로 활용되기도 함
2. 다른 사람이 작성한함수를 예측가능하며 안전하게 사용가능
。불변이 보장된함수의 경우 위험없이 이용 가능
3.Side Effect로 인한 피해를 최소화
。Side Effect: 변수의 값 , 상태 등의 변화가 발생하는 효과
▶객체를 여러 곳에서 수정 시상태를 예측하기가 매우 어렵다.
。불변객체는 기본적으로내부 인스턴스변수의 값 변경을 차단하여상태 변경이 금지되어있으므로 안전하게 재사용이 가능하다.
4.원자성( Atomicity ) 보장
。불변객체에 대한메소드실행 중예외가 발생 시메소드호출 전상태로 복구를 보장
▶DB 트랜잭션의원자성과 유사
。불변객체의 특성 이용
▶값 수정성공 시수정된 값을생성자로 전달하여 생성한새 객체로 업데이트
▶예외가 발생하여값 수정실패 시기존 객체를 그대로 유지// 불변객체 class Money{ private final int amount; public Money(int amount){ this.amount = amount; } public int amount(){ return amount; } public Money minus(int targetAmount){ if ( this.amount < targetAmount ) throw new IllegalArgumentException("잔액부족"); return new Money(this.amount - targetAmount); } @Override public String toString() { return "Money{" + "amount=" + amount + '}'; } } public class atomicity { public static void main(String[] args) { Money m2 = new Money(10_000); try { // 성공 시 새 객체로 업데이트 m2 = m2.minus(20_000); } catch(IllegalArgumentException e){ System.out.println(e.getMessage()); } System.out.println(m2.amount()); } }。 case 2 :
Money m2:10_000 - 20_000 = -10_000으로예외가 발생되어새 객체로 업데이트되지 않았으므로기존 객체유지
▶원자성보장
5.불변객체를Set,Map,Cache의요소로 저장 시 안전하게 사용이 가능
。Map,Set의 경우Key - Value 쌍 데이터를 저장.
。해시값을 사용하는자료구조에서Key Type을클래스로 지정 및Key 객체를 통해Value를 찾을 경우 해당클래스내에 정의된equals(),hashCode()메소드를 통해동일객체여부를 판단
。Map의Key Type을불변객체의클래스로 지정 시 안전한 동작을 보장
▶Class객체는equals()를 통해객체의인스턴스변수를 비교 후 동일여부를 판단하므로Class객체의인스턴스변수를 수정하여상태변경시동일 객체가 아니게 되므로 조회가 불가능.
▶불변객체로 지정 시 내부인스턴스변수를 변경하는상태변경자체를 금지하므로동일 객체로 판단할 수 있게하여 안전하게 사용이 가능하다.import java.util.HashMap; import java.util.Map; import java.util.Objects; // Map<K,V>에서 Key Type으로 불변 클래스 class Key{ private final int id1; // 불변변수 private final int id2; // 불변변수 public Key(int id1, int id2) { this.id1 = id1; this.id2 = id2; } @Override public int hashCode() { // 객체 내 인스턴스변수값을 int의 해시값으로 만든 후 return // Hash 자료구조 에서 객체 비교 수행 시 해당 해시값으로 비교 return Objects.hash(id1,id2); } @Override public boolean equals(Object obj) { // 객체 메모리주소값 동일한 경우 true 반환 if ( this == obj ) return true; if ( obj instanceof Key k ) // obj가 Key 클래스의 객체인지 확인 후 Key 클래스로 캐스팅 // 객체의 내부 불변변수가 동일한 경우 true 반환 return this.id1 == k.id1 && this.id2 == k.id2; // 위 조건을 만족하지 못한 경우 false 반환 return false; } } public class ImmutableMap { public static void main(String[] args) { Map<Key,String> map = new HashMap<Key,String>(); map.put(new Key(1,1), "lee"); System.out.println(map.get(new Key(1,1))); // lee 출력 } }6.
Garbage Collector의 성능을 증진
。불변객체활용 시Garbage Collector가 스캔해야하는메모리영역이 감소하여 성능을 증진.
▶불변객체를 수정하여불변객체를 일일이 생성하는 비용보다불변객체를 사용하여GC의스캔범위가 축소되는 비용이 더 저렴하므로불변객체를 이용