목차
소개
Lambda表达式
Stream流操作
中间对象辅助方式
Java java지도 시간 JAVA의 간단한 for 루프에서 예외를 방지하는 방법은 무엇입니까?

JAVA의 간단한 for 루프에서 예외를 방지하는 방법은 무엇입니까?

Apr 26, 2023 pm 12:58 PM
java for

소개

실제 비즈니스 프로젝트 개발에서는 주어진 목록에서 조건에 맞지 않는 요소를 제거하는 작업을 누구나 숙지해야겠죠?

많은 학생들이 즉시 여러 가지 구현 방법을 떠올릴 수 있지만, 당신이 생각하는 이러한 구현 방법은 인간과 동물에게 무해합니까? 겉보기에 평범해 보이는 많은 작업이 실제로는 함정이며, 많은 초보자들이 조심하지 않으면 함정에 빠질 수 있습니다.

실수로 밟은 경우:

  • 코드가 실행 중일 때 직접 예외를 발생시키고 오류를 보고합니다. 이는 적어도 시간이 지나면 발견하고 해결할 수 있다는 점입니다.

    코드는 오류를 보고하지 않지만 비즈니스 로직은 설명할 수 없을 정도로 나타납니다. 이상한 문제는 이런 종류가 더 비극적입니다. 왜냐하면 이 문제에 주의를 기울이지 않으면 후속 비즈니스에 숨겨진 위험이 발생할 수 있기 때문입니다.
  • 그렇다면 이를 달성하는 방법은 무엇인가요? 어떤 구현 방법에 문제가 있을 수 있나요? 여기서 함께 논의해 봅시다. 여기서 논의되는 것은 회향콩에 "회향"이라는 단어를 어떻게 쓰는지에 대한 문제가 아니라 쉽게 무시할 수 있는 매우 심각하고 실용적인 기술적 문제라는 점을 유의하시기 바랍니다.
가설 수요 시나리오:

사용자 목록 allUsers가 주어지면 부서가 dev인 직원을 목록에서 제거하고 나머지 직원 정보를 반환해야 합니다.

추적 작업

foreach 루프 제거 방법

많은 초보자 첫 번째 아이디어는 for 루프를 하나씩 확인하고 조건에 맞는 것을 제거하는 것입니다~너무 쉽습니다...

1분 만에 코드 작성이 끝났습니다:

public List<UserDetail> filterAllDevDeptUsers(List<UserDetail> allUsers) {
    for (UserDetail user : allUsers) {
        // 判断部门如果属于dev,则直接剔除
        if ("dev".equals(user.getDepartment())) {
            allUsers.remove(user);
        }
    }
    // 返回剩余的用户数据
    return allUsers;
}
로그인 후 복사

그런 다음 자신감 있게 실행 버튼을 눌렀습니다:

java.util.ConcurrentModificationException: null
	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
	at java.util.ArrayList$Itr.next(ArrayList.java:859)
	at com.veezean.demo4.UserService.filterAllDevDeptUsers(UserService.java:13)
	at com.veezean.demo4.Main.main(Main.java:26)
로그인 후 복사

뭐라고? 뭐하세요? 예외가 발생하는 이유는 무엇입니까?

무심코 함정에 빠졌는데 왜 예외가 발생했는지 분석해 보겠습니다.

원인 분석:

JAVA foreach 구문의 실제 처리는 반복자 Iterator를 기반으로 합니다.

루프가 시작될 때 먼저 반복 인스턴스가 생성되고 이 반복 인스턴스의 ExpectModCount에 컬렉션의 modCount가 할당됩니다. 반복자가 다음 요소를 순회하기 위해 hashNext() / next()를 사용할 때마다 modCount 변수와 예상ModCount 값이 동일한지 확인하고, 그렇지 않으면 순회가 반환됩니다. 순회를 종료합니다.

루프에서 요소를 추가하거나 삭제하는 경우 컬렉션의 add() 및 제거() 메서드를 직접 호출하여 modCount가 증가하거나 감소하지만 이러한 메서드는 반복 인스턴스에서 예상ModCount를 수정하지 않으므로 결과적으로 반복 인스턴스의 예상ModCount에서 modCount 값과 같지 않으면 ConcurrentModificationException 예외가 발생합니다.

아래 첨자 루프 연산JAVA의 간단한 for 루프에서 예외를 방지하는 방법은 무엇입니까?

흠? foreach 메서드가 작동하지 않으므로 원래의 첨자 루프 메서드를 사용하면 오류가 발생하지 않습니다. 여전히 매우 쉽습니다...

public List<UserDetail> filterAllDevDeptUsers(List<UserDetail> allUsers) {
    for (int i = 0; i < allUsers.size(); i++) {
        // 判断部门如果属于dev,则直接剔除
        if ("dev".equals(allUsers.get(i).getDepartment())) {
            allUsers.remove(i);
        }
    }
    // 返回剩余的用户数据
    return allUsers;
}
로그인 후 복사

코드가 한 번에 완성되고, 실행하고 처리된 출력을 확인하세요:

{id=2, name='lee思', Department='dev'}

{id =3, name ='王五', Department='product'}
{id=4, name='Tiezhu', Department='pm'}



물론, 오류도 보고되지 않고 결과도 출력됩니다. , 완벽해요~

기타..? 정말 괜찮은 걸까요?

우리의 코드 로직은 "dev".equals(department)인지 판단하는 것인데, 출력 결과에는 왜 아직도 제거해야 할 Department=dev 같은 데이터가 있나요?

실제 비즈니스 프로젝트라면 개발 단계에서 오류가 보고되지 않고, 결과가 꼼꼼히 검증되지 않은 후 생산 라인으로 흘러가게 된다면 비정상적인 비즈니스 로직이 발생할 수 있습니다.

이 현상이 나타나는 구체적인 이유를 살펴보겠습니다.

원인 분석:

우리는 실제로 목록의 요소와 첨자 사이에 강력한 바인딩 관계가 없다는 것을 알고 있습니다. 이는 단지 목록의 요소가 변경된 후 해당 첨자의 대응 관계일 뿐입니다. 각 요소는 아래와 같이 아래 첨자가 변경될 수 있습니다.

그런 다음 목록에서 요소를 삭제한 후 목록에서 삭제된 요소 뒤에 있는 모든 요소의 아래 첨자는 앞으로 이동하지만 for의 포인터 i 루프는 항상 거꾸로 누적됩니다. 예, 다음 루프를 처리할 때 일부 요소가 누락되어 처리되지 않을 수 있습니다. JAVA의 간단한 for 루프에서 예외를 방지하는 방법은 무엇입니까?

예를 들어 아래 그림과 같이 i=0이면 A 요소를 삭제해야 한다고 판단하고, 재활용 시 i=1이면 바로 삭제됩니다. 목록의 요소가 앞으로 이동하면 B 요소가 원래 아래 첨자가 됩니다. 0의 위치가 직접 누락되었습니다.

여기서 위 코드가 실행 후 누락되는 이유를 알 수 있습니다~JAVA의 간단한 for 루프에서 예외를 방지하는 방법은 무엇입니까?

올바른 방법

위의 2가지 함정을 확인했습니다. 수술 후 올바르고 적절한 수술방법은 무엇인가요?

Iterator 메서드

어? 좋아요? foreach 메서드도 반복자를 사용한다고 방금 말하지 않았는데 실제로는 트랩 작업인가요? 여기서 반복자 패턴이 올바른 방식이라고 말하는 이유는 무엇입니까?

虽然都是基于迭代器,但是使用逻辑是不一样的,看下代码:

public List<UserDetail> filterAllDevDeptUsers(List<UserDetail> allUsers) {
    Iterator<UserDetail> iterator = allUsers.iterator();
    while (iterator.hasNext()) {
        // 判断部门如果属于dev,则直接剔除
        if ("dev".equals(iterator.next().getDepartment())) {
            // 这是重点,此处操作的是Iterator,而不是list
            iterator.remove();
        }
    }
    // 返回剩余的用户数据
    return allUsers;
}
로그인 후 복사

执行结果:

{id=3, name='王五', department='product'}
{id=4, name='铁柱', department='pm'}

这次竟然直接执行成功了,且结果也是正确的。为啥呢?

在前面foreach方式的时候,我们提过之所以会报错的原因,是由于直接修改了原始list数据而没有同步让Iterator感知到,所以导致Iterator操作前校验失败抛异常了。

而此处的写法中,直接调用迭代器中的remove()方法,此操作会在调用集合的remove(),add()方法后,将expectedModCount重新赋值为modCount,所以在迭代器中增加、删除元素是可以正常运行的。,所以这样就不会出问题啦。

JAVA의 간단한 for 루프에서 예외를 방지하는 방법은 무엇입니까?

Lambda表达式

言简意赅,直接上代码:

public List<UserDetail> filterAllDevDeptUsers(List<UserDetail> allUsers) {
    allUsers.removeIf(user -> "dev".equals(user.getDepartment()));
    return allUsers;
}
로그인 후 복사

Stream流操作

作为JAVA8开始加入的Stream,使得这种场景实现起来更加的优雅与易懂:

public List<UserDetail> filterAllDevDeptUsers(List<UserDetail> allUsers) {
    return allUsers.stream()
            .filter(user -> !"dev".equals(user.getDepartment()))
            .collect(Collectors.toList());
}
로그인 후 복사

中间对象辅助方式

既然前面说了不能直接循环的时候执行移除操作,那就先搞个list对象将需要移除的元素暂存起来,最后一起剔除就行啦 ~

嗯,虽然有点挫,但是不得不承认,实际情况中,很多人都在用这个方法 —— 说的就是你,你是不是也曾这么写过?

public List<UserDetail> filterAllDevDeptUsers(List<UserDetail> allUsers) {
    List<UserDetail> needRemoveUsers = new ArrayList<>();
    for (UserDetail user : allUsers) {
        if ("dev".equals(user.getDepartment())) {
            needRemoveUsers.add(user);
        }
    }
    allUsers.removeAll(needRemoveUsers);
    return allUsers;
}
로그인 후 복사

或者:

public List<UserDetail> filterAllDevDeptUsers(List<UserDetail> allUsers) {
    List<UserDetail> resultUsers = new ArrayList<>();
    for (UserDetail user : allUsers) {
        if (!"dev".equals(user.getDepartment())) {
            resultUsers.add(user);
        }
    }
    return resultUsers;
}
로그인 후 복사

위 내용은 JAVA의 간단한 for 루프에서 예외를 방지하는 방법은 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

자바의 제곱근 자바의 제곱근 Aug 30, 2024 pm 04:26 PM

자바의 제곱근 안내 여기서는 예제와 코드 구현을 통해 Java에서 Square Root가 어떻게 작동하는지 설명합니다.

자바의 완전수 자바의 완전수 Aug 30, 2024 pm 04:28 PM

Java의 완전수 가이드. 여기서는 정의, Java에서 완전 숫자를 확인하는 방법, 코드 구현 예제에 대해 논의합니다.

Java의 난수 생성기 Java의 난수 생성기 Aug 30, 2024 pm 04:27 PM

Java의 난수 생성기 안내. 여기서는 예제를 통해 Java의 함수와 예제를 통해 두 가지 다른 생성기에 대해 설명합니다.

자바의 웨카 자바의 웨카 Aug 30, 2024 pm 04:28 PM

Java의 Weka 가이드. 여기에서는 소개, weka java 사용 방법, 플랫폼 유형 및 장점을 예제와 함께 설명합니다.

자바의 암스트롱 번호 자바의 암스트롱 번호 Aug 30, 2024 pm 04:26 PM

자바의 암스트롱 번호 안내 여기에서는 일부 코드와 함께 Java의 Armstrong 번호에 대한 소개를 논의합니다.

Java의 스미스 번호 Java의 스미스 번호 Aug 30, 2024 pm 04:28 PM

Java의 Smith Number 가이드. 여기서는 정의, Java에서 스미스 번호를 확인하는 방법에 대해 논의합니다. 코드 구현의 예.

Java Spring 인터뷰 질문 Java Spring 인터뷰 질문 Aug 30, 2024 pm 04:29 PM

이 기사에서는 가장 많이 묻는 Java Spring 면접 질문과 자세한 답변을 보관했습니다. 그래야 면접에 합격할 수 있습니다.

Java 8 Stream foreach에서 나누거나 돌아 오시겠습니까? Java 8 Stream foreach에서 나누거나 돌아 오시겠습니까? Feb 07, 2025 pm 12:09 PM

Java 8은 스트림 API를 소개하여 데이터 컬렉션을 처리하는 강력하고 표현적인 방법을 제공합니다. 그러나 스트림을 사용할 때 일반적인 질문은 다음과 같은 것입니다. 기존 루프는 조기 중단 또는 반환을 허용하지만 스트림의 Foreach 메소드는이 방법을 직접 지원하지 않습니다. 이 기사는 이유를 설명하고 스트림 처리 시스템에서 조기 종료를 구현하기위한 대체 방법을 탐색합니다. 추가 읽기 : Java Stream API 개선 스트림 foreach를 이해하십시오 Foreach 메소드는 스트림의 각 요소에서 하나의 작업을 수행하는 터미널 작동입니다. 디자인 의도입니다

See all articles