source

Java 8 스트림을 중단하거나 각 스트림에서 반환하시겠습니까?

goodcode 2022. 8. 8. 20:04
반응형

Java 8 스트림을 중단하거나 각 스트림에서 반환하시겠습니까?

외부 반복을 사용하는 경우Iterable사용하고 있다break또는return각 루프에 대해 다음과 같이 확장됩니다.

for (SomeObject obj : someObjects) {
   if (some_condition_met) {
      break; // or return obj
   }
}

어떻게 하면break또는returnJava 8 lamda 식에서 내부 반복을 사용합니다.

someObjects.forEach(obj -> {
   //what to do here?
})

이게 필요하시면 사용하지 마세요.forEach단, 스트림에서 사용할 수 있는 다른 방법 중 하나는 목표가 무엇인지에 따라 달라집니다.

예를 들어, 이 루프의 목적이 일부 술어와 일치하는 첫 번째 요소를 찾는 경우:

Optional<SomeObject> result =
    someObjects.stream().filter(obj -> some_condition_met).findFirst();

(주의: 스트림은 게으르게 평가되기 때문에 전체 컬렉션을 반복하지 않습니다. 조건에 일치하는 첫 번째 개체에서 중지됩니다).

컬렉션에 조건이 참인 요소가 있는지 알고 싶다면 다음을 사용할 수 있습니다.anyMatch:

boolean result = someObjects.stream().anyMatch(obj -> some_condition_met);

람다의 반환은 각각에 대한 연속값이지만 중단에 해당하는 값은 없습니다.돌아가기만 하면 계속할 수 있습니다.

someObjects.forEach(obj -> {
   if (some_condition_met) {
      return;
   }
})

이것은 다음 경우에 가능합니다.Iterable.forEach()(단, 신뢰할 수 있는 것은 아닙니다).Stream.forEach()). 해결책은 좋지 않지만 가능합니다.

경고: 비즈니스 로직을 제어하는 데 사용할 수 없습니다., 비즈니스 로직을 실행하는 동안 발생하는 예외적인 상황을 처리하는 데만 사용해야 합니다.forEach()자원 접근이 갑자기 정지되는 등 처리된 오브젝트 중 하나가 계약을 위반하고 있습니다(예를 들어 스트림의 모든 요소가 계약을 위반해서는 안 된다고 계약서에 기재되어 있습니다).null갑자기 그 중 하나가null) 등입니다.

의 매뉴얼에 따르면:

각 요소에 대해 지정된 액션을 수행합니다.Iterable 모든 요소가 처리되거나 작업이 예외를 발생시킬 때까지...액션에 의해 발생하는 예외는 발신자에게 릴레이 됩니다.

따라서 내부 루프를 즉시 차단하는 예외를 발생시킵니다.

코드는 다음과 같습니다.좋다고는 할 수 없지만, 동작합니다.독자적인 클래스를 만듭니다.BreakException그것은 확장된다RuntimeException.

try {
    someObjects.forEach(obj -> {
        // some useful code here
        if(some_exceptional_condition_met) {
            throw new BreakException();
       }
    }
}
catch (BreakException e) {
    // here you know that your condition has been met at least once
}

주의:try...catch람다 표현에 관한 것이 아니라 오히려 전체에 관한 이다.forEach()방법.보다 알기 쉽게 하려면 , 보다 명확하게 나타내는 코드의 다음의 변환을 참조해 주세요.

Consumer<? super SomeObject> action = obj -> {
    // some useful code here
    if(some_exceptional_condition_met) {
        throw new BreakException();
    }
});

try {
    someObjects.forEach(action);
}
catch (BreakException e) {
    // here you know that your condition has been met at least once
}

아래는 제가 프로젝트에서 사용한 솔루션을 찾으십시오.대신forEach그냥 사용하다allMatch:

someObjects.allMatch(obj -> {
    return !some_condition_met;
});

계속 진행할지 여부를 나타내는 술어를 사용하는 방법을 사용하거나(대신 중단이 있음), 예외를 발생시킬 필요가 있습니다(물론 매우 추악한 접근법입니다.

이렇게 '아니다'라고 쓸 수 있어요.forEachConditional하다

public static <T> void forEachConditional(Iterable<T> source,
                                          Predicate<T> action) {
    for (T item : source) {
        if (!action.test(item)) {
            break;
        }
    }
}

Predicate<T>일반적인 할 수 (「」를 사용하는 것).T 되는 ★★★bool는를 더 - )을 씁니다.Predicate<T>이상적이지 않아요

9에서 Java 9+로 takeWhile:

MutableBoolean ongoing = MutableBoolean.of(true);
someobjects.stream()...takeWhile(t -> ongoing.value()).forEach(t -> {
    // doing something.
    if (...) { // want to break;
        ongoing.setFalse();
    }
});

Java8 + rxjava 를 사용할 수 있습니다.

//import java.util.stream.IntStream;
//import rx.Observable;

    IntStream intStream  = IntStream.range(1,10000000);
    Observable.from(() -> intStream.iterator())
            .takeWhile(n -> n < 10)
            .forEach(n-> System.out.println(n));

병렬 연산의 성능을 최대화하려면 findFirst()와 유사한 findAny()를 사용합니다.

Optional<SomeObject> result =
    someObjects.stream().filter(obj -> some_condition_met).findAny();

그러나 안정적인 결과를 원할 경우 대신 find First()를 사용합니다.

또한 일치하는 패턴(anyMatch()/allMatch)은 부울만 반환하며 일치하는 오브젝트는 얻을 수 없습니다.

나는 이런 일을 통해 성취했다

  private void doSomething() {
            List<Action> actions = actionRepository.findAll();
            boolean actionHasFormFields = actions.stream().anyMatch(actionHasMyFieldsPredicate());
            if (actionHasFormFields){
                context.addError(someError);
            }
        }
    }

    private Predicate<Action> actionHasMyFieldsPredicate(){
        return action -> action.getMyField1() != null;
    }

이를 수행하려면 peek(..)와 anyMatch(..)를 조합합니다.

예를 들어 다음과 같습니다.

someObjects.stream().peek(obj -> {
   <your code here>
}).anyMatch(obj -> !<some_condition_met>);

또는 일반적인 util 메서드를 작성합니다.

public static <T> void streamWhile(Stream<T> stream, Predicate<? super T> predicate, Consumer<? super T> consumer) {
    stream.peek(consumer).anyMatch(predicate.negate());
}

그리고 이렇게 쓰세요.

streamWhile(someObjects.stream(), obj -> <some_condition_met>, obj -> {
   <your code here>
});
public static void main(String[] args) {
    List<String> list = Arrays.asList("one", "two", "three", "seven", "nine");
    AtomicBoolean yes = new AtomicBoolean(true);
    list.stream().takeWhile(value -> yes.get()).forEach(value -> {
        System.out.println("prior cond" + value);
        if (value.equals("two")) {
            System.out.println(value);
            yes.set(false);
        }

    });
    //System.out.println("Hello World");
}

이건 어때?

final BooleanWrapper condition = new BooleanWrapper();
someObjects.forEach(obj -> {
   if (condition.ok()) {
     // YOUR CODE to control
     condition.stop();
   }
});

서 ★★★★★BooleanWrapper는 플로우를 제어하기 위해 구현해야 하는 클래스입니다.

int valueToMatch = 7;
Stream.of(1,2,3,4,5,6,7,8).anyMatch(val->{
   boolean isMatch = val == valueToMatch;
   if(isMatch) {
      /*Do whatever you want...*/
       System.out.println(val);
   }
   return isMatch;
});

일치하는 부분만 작동하고 일치하는 부분을 찾은 후에는 반복이 중지됩니다.

anyMatch 사용을 권장합니다.예:-

return someObjects.stream().anyMatch(obj -> 
    some_condition_met;
);

anyMatch 에 대해서는, 다음의 투고를 참조해 주세요.- https://beginnersbook.com/2017/11/java-8-stream-anymatch-example/

언급URL : https://stackoverflow.com/questions/23308193/break-or-return-from-java-8-stream-foreach

반응형