List나 Map의 요소를 순회하고 삭제하는 방법에는 여러 가지가 있으며, 부적절하게 사용하면 문제가 발생합니다. 이 글을 통해 좀 더 자세히 알아봅시다.
1. 목록 순회 중 요소 삭제
인덱스 첨자 순회 사용
예: 삭제 2
public static void main(String[] args) { List<Integer> list = new ArrayList<Integer>(); list.add(1); list.add(2); list.add(2); list.add(3); list.add(4); for (int i = 0; i < list.size(); i++) { if(2 == list.get(i)){ list.remove(i); } System.out.println(list.get(i)); } System.out.println("list=" + list.toString()); }
출력 결과:
1 2 3 4 list=[1, 2, 3, 4]
문제:
결과 2개만 삭제되었고, 나머지 2개는 생략된 것으로 나타났습니다. 이유는 첫 번째 이후에 삭제되었습니다. 2에서는 세트의 요소 수가 1개 줄어들고, 다음 요소가 1개 위치 앞으로 이동하여 두 번째 2개 요소가 누락됩니다.
For 루프 순회
예:
public static void listIterator2(){ List<Integer> list = new ArrayList<Integer>(); list.add(1); list.add(2); list.add(2); list.add(3); list.add(4); for (int value : list) { if(2 == value){ list.remove(value); } System.out.println(value); } System.out.println("list=" + list.toString()); }
결과:
Exception in thread "main" 1 2 java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification(Unknown Source) at java.util.ArrayList$Itr.next(Unknown Source) at test.ListIterator.listIterator2(ListIterator.java:39) at test.ListIterator.main(ListIterator.java:10)
설명:
jdk의 ConcurrentModificationException에 대한 설명:
공용 클래스 ConcurrentModificationException은
RuntimeException 메소드가 발생하는 경우 이 예외가 발생합니다. 객체의 동시 수정이 감지되었지만 그러한 수정이 허용되지 않는 경우.
예를 들어 한 스레드가 컬렉션을 반복하는 경우 일반적으로 다른 스레드가 컬렉션을 선형적으로 수정할 수 없습니다. 이러한 경우 반복 결과가 불확실한 경우가 많습니다. 일부 반복기 구현(JRE에서 제공하는 모든 일반 컬렉션 구현 포함)은 이 동작이 감지되면 이 예외를 발생시키도록 선택할 수 있습니다. 이 작업을 수행하는 반복자는 향후 특정 시점에 지정되지 않은 임의 동작의 위험 없이 완전히 빠르게 실패하므로 빠른 실패 반복자라고 합니다.
참고: 이 예외가 항상 객체가 다른 스레드에 의해 동시에 수정되었음을 나타내지는 않습니다. 단일 스레드가 개체의 계약을 위반하는 일련의 메서드 호출을 실행하는 경우 개체에서 이 예외가 발생할 수 있습니다. 예를 들어 스레드가 빠른 실패 반복기를 사용하여 컬렉션을 반복하는 동안 컬렉션을 직접 수정하는 경우 반복기는 이 예외를 발생시킵니다.
참고: 일반적으로 동기화되지 않은 동시 수정이 발생할지 여부를 확실하게 보장할 수 없기 때문에 반복자의 빠른 실패 동작은 보장되지 않습니다. 빠른 실패 작업은 최선을 다해 ConcurrentModificationException을 발생시킵니다. 따라서 이러한 작업의 정확성을 높이기 위해 이 예외에 의존하는 프로그램을 작성하는 것은 실수입니다. 올바른 접근 방식은 다음과 같습니다. ConcurrentModificationException은 버그를 감지하는 데에만 사용해야 합니다.
Java에서는 실제로 처리를 위해 반복자를 사용합니다. 반복자는 반복자를 사용하는 동안 컬렉션이 삭제되는 것을 허용하지 않습니다. 따라서 반복자가 ConcurrentModificationException을 발생시켰습니다.
올바른 방법
예:
public static void listIterator3(){ List<Integer> list = new ArrayList<Integer>(); list.add(1); list.add(2); list.add(2); list.add(3); list.add(4); Iterator<Integer> it = list.iterator(); while (it.hasNext()){ Integer value = it.next(); if (2 == value) { it.remove(); } System.out.println(value); } System.out.println("list=" + list.toString()); }
>2. 맵 순회 중 요소 삭제
올바른 방법 예:
1 2 2 3 4 list=[1, 3, 4]
결과:
public static void main(String[] args) { HashMap<String, String> map = new HashMap<String, String>(); map.put("1", "test1"); map.put("2", "test2"); map.put("3", "test3"); map.put("4", "test4"); //完整遍历Map for (Entry<String, String> entry : map.entrySet()) { System.out.printf("key: %s value:%s\r\n", entry.getKey(), entry.getValue()); } //删除元素 Iterator<Map.Entry<String, String>> it = map.entrySet().iterator(); while(it.hasNext()) { Map.Entry<String, String> entry= it.next(); String key= entry.getKey(); int k = Integer.parseInt(key); if(k%2==1) { System.out.printf("delete key:%s value:%s\r\n", key, entry.getValue()); it.remove(); } } //完整遍历Map for (Entry<String, String> entry : map.entrySet()) { System.out.printf("key: %s value:%s\r\n", entry.getKey(), entry.getValue()); } }
참고
하지만 주의해야 할 사항도 있습니다. iterator의 Remove() 메서드:
iterator.next() 메서드가 호출될 때마다 제거() 메서드는 한 번만 호출할 수 있습니다.
remove() 메서드를 호출하기 전에 next() 메서드를 한 번 호출해야 합니다.JDK-API의 제거() 메소드 설명:
void Remove()는 반복자가 가리키는 컬렉션에서 반복자가 반환한 마지막 요소를 제거합니다. (선택적 조치). 이 메서드는 next 호출당 한 번만 호출할 수 있습니다. 반복자가 가리키는 컬렉션이 반복하는 동안 이 메서드를 호출하는 것 이외의 다른 방법으로 수정되는 경우 반복자의 동작은 지정되지 않습니다.
발생: UnsupportedOperationException - 반복자가 제거 작업을 지원하지 않는 경우. IllegalStateException - 다음 메소드가 호출되지 않았거나, 마지막 메소드 호출 이후에 제거 메소드가 호출된 경우.
요약
Java에서 목록 또는 맵 순회 중에 요소를 삭제하는 방법에 대한 더 많은 기사를 보려면 PHP 중국어 웹사이트에 주목하세요!