HashMap 순회 중 map.remove를 호출하면 왜 다음 반복에서 예외가 날까
enhanced for 안의 map.remove는 반복자 밖에서 Map 구조를 바꾼다. 세 엔트리의 부분 삭제와 예외 시점을 비교하고, 조건부 삭제에는 entrySet().removeIf 또는 같은 반복자의 remove를 선택한다. 단일 스레드 재현과 fail-fast의 한계도 구분한다.
빌드노트
Java·JVM 카테고리의 글입니다.
총 48개의 글
enhanced for 안의 map.remove는 반복자 밖에서 Map 구조를 바꾼다. 세 엔트리의 부분 삭제와 예외 시점을 비교하고, 조건부 삭제에는 entrySet().removeIf 또는 같은 반복자의 remove를 선택한다. 단일 스레드 재현과 fail-fast의 한계도 구분한다.
Arrays.fill로 채운 목록 배열은 같은 목록 참조를 공유할 수 있다. 한 번의 add, == 비교, 한 칸 교체와 칸마다 새 목록을 만드는 초기화를 실제 JDK에서 비교해 공유 여부와 수정 위치를 판단한다.
computeIfAbsent는 조회 함수가 null을 반환하면 새 매핑을 저장하지 않는다. 같은 키를 두 번 조회한 호출 횟수와 기존 null 매핑을 비교하고, 부재 결과까지 보관하려면 Optional.empty()처럼 null이 아닌 값을 저장해야 하는 이유를 확인한다.
Stream.toList()는 변경 불가 목록을 반환한다. 같은 원소를 세 방식으로 수집해 add 결과를 비교하고, 후속 수정에 필요한 명시적 ArrayList 수집과 이미 받은 결과의 복사를 설명한다. Collectors.toList()의 실행 결과와 API 보장도 구분한다.
Files.write의 기본 옵션은 기존 파일을 비운다. 실제 내용·크기 비교로 기본 쓰기와 추가 쓰기를 구별하고, CREATE + APPEND와 CREATE_NEW의 실패 조건에 맞춰 호출부를 고른다.
같은 UTF-8 바이트를 String 생성자와 Files.readString으로 읽었을 때 대체 문자와 예외로 갈리는 이유를 비교한다. REPORT와 REPLACE를 직접 적용하고, 손실을 허용할 조건과 대체 뒤 원본을 복구할 수 없는 이유를 확인한다.
CompletableFuture.join()의 짧은 catch에서 실제 실패 원인을 확인한다. get()의 포장 예외와 인터럽트, 직접 취소와 후속 단계의 차이를 구분해 결과를 받는 경계의 오류 처리를 정한다.
TreeSet은 비교 결과가 0이면 equals가 false인 객체도 같은 원소로 취급한다. 짧은 JShell 조회로 add·size·contains의 차이를 확인하고, equals와 일치하는 동점 기준을 추가할지 원본 목록을 정렬할지 결정한다.
Period.getDays()는 연·월·일 중 일 성분이다. 고정 날짜로 40일 구간과 평년·윤년의 한 달을 비교하고, 전체 일수에 ChronoUnit.DAYS.between을 쓰는 기준과 종료일 제외·음수 처리까지 확인한다.
응답용 HashMap을 Map.of로 바꾸면 null 키·값이 생성 시점의 NPE로 이어진다. 실제 Java·JShell 비교로 Map.copyOf와 중복 키 실패를 구분하고, 항목 생략과 명시 null 보존을 API 의미에 맞게 선택한다.
문자열로 만든 2.0과 2.00은 숫자는 같지만 scale이 달라 equals가 false다. HashSet 2개·TreeSet 1개라는 실제 결과를 비교하고, 변경 감지와 키에 같은 동등성 규칙을 적용하는 방법 및 반올림 없이 정규화할 조건을 설명한다.
작은 Integer에서 통과한 == 비교가 큰 ID에서 어긋나는 이유를 JShell로 확인한다. 캐시의 관찰과 Java 17의 보장 범위를 나누고, null을 허용하는 값 비교와 언박싱 예외를 설명한다.