glenn-syj / more-effective-java

이펙티브 자바를 읽으며 자바를 더 효율적으로 공부합니다
4 stars 5 forks source link

[MEJ-008] EnumMap과 HashTable 비교 및 교재 코드 탐구 #165

Closed FickleBoBo closed 1 month ago

FickleBoBo commented 2 months ago

Based on : #162 by @yngbao97


생소한 자료구조였던 EnumMap에 대해서 내부 구현 위주로 탐구를 진행해주셔서 EnumMap의 존재의의에 대해 학습할 수 있던 좋은 글이었습니다.

HashTable은 key가 총 몇 개가 들어올지 알 수 없어서 table의 길이를 동적으로 변경하는 과정이 필요한데 반해, EnumMap은 매개변수로 넘긴 enum에 정의된 상수의 개수만큼만 table을 생성하면 돼서 이러한 과정이 필요없게 되어 성능상 이점이 생길 것 같습니다. 추가로 put 과정에서는 enum 상수의 정렬순서를 index로 값을 할당한다면 해싱하는 과정도 필요없고 해시충돌(다른 key 같은 hash 값에서 발생)도 없어서(key가 동일하면 덮어씌워지는 것으로 보입니다) 유용할 것으로 생각됩니다.

교재 p.227의 코드 37-2는 일반적인 상황에서 EnumMap을 사용할 경우 key는 동일하지만 value는 다른 객체를 넣을 상황이 많아서 value를 Set으로 만들어서 보여준 것으로 보입니다. 같은 동작을 하는 안좋은 코드의 예시로 보여준 37-1의 경우 정상 동작은 하는데 비검사 형변환, 인덱스의 의미를 알 수 없음, 정확한 정숫값 사용을 보증해야 함 을 문제 삼았는데 이에 대해서도 탐구를 진행했습니다.

먼저 비검사 형변환 의 경우 plantsByLifeCycle를 Set[] 에서 List<Set>으로 변경하면 해결되는 것으로 보였습니다. 알고리즘 학습에서 인접리스트를 선언하는 과정과 동일한데, EnumMap 대신 사용할 이유는 없어 보였습니다. 인덱스의 의미를 알 수 없음 의 경우 저자의 의도를 정확히 파악하지 못했는데 plantsByLifeCycle 객체만으로 enum의 값들에 대해 알 수 있음(=Plant class가 없어도 알 수 있음)을 말하는 것이면 유의미해보였습니다. 정확한 정숫값 사용을 보증해야 함 의 경우 oridinal()을 활용하는데 뭐가 문제인지 아직 파악하지 못했습니다.

yngbao97 commented 2 months ago

글의 초점 이외에 있던 부분까지 추가적으로 탐구하고 공유해주셔서 감사합니다. 저도 글을 읽으면서

정확한 정숫값 사용을 보증해야 한다

이 부분에 대해 제대로 이해하지 못했는데요, 추가로 탐구해주신 부분과 함께 다시금 교재를 읽어보니 호출하고자 하는 값을 가져오기 위한 정확한 정수값을 인덱스로 사용해야 한다는 말 같습니다.

37-1 예시 코드에서는 원하는 값을 i라는 정수값을 통해 불러오고 있는데요.

for (int i = 0; i < plantsByLifeCycle.length; i++) {
    System.out.printf("%s: %s%n",
        Plant.LifeCycle.values()[i], plantByLifeCycle[i]);
}

호출에 사용하는 정수값이 정확히 원하는 값을 불러오는 인덱스가 아닌경우에 문제가 생길 수 있습니다. 이에 대해 말하고 있다는 것은

잘못된 값을 사용하면 잘못된 동작을 묵묵히 수행하거나 (운이 좋다면) ArrayIndexOutOfBoundsException을 던질 것이다.

라는 문장에서 조심스럽게 예측해볼 수 있을 것 같습니다. ArrayIndexOutOfBoundsException 오류가 뜬다면 호출시에 잘못된 인덱스 번호를 사용했다는 것을 알수 있게 되지만, 그렇지 않다면 오류없이 잘못된 값을 호출해 사용하게 될테니까요.

해당 부분을 추가로 탐구해주신 덕분에 간과했던 내용을 다시한번 제대로 고민해볼 수 있었습니다. 감사합니다!