술어로 첫 번째 요소 찾기
Java 8 lamda를 사용하기 시작한 지 얼마 안 되어 기능적인 언어로 익숙한 것을 구현하려고 합니다.
예를 들어, 대부분의 기능적 언어에는 시퀀스 또는 첫 번째 요소를 반환하는 목록으로 동작하는 일종의 검색 함수가 있습니다.true
Java 8에서 이를 실현하는 유일한 방법은 다음과 같습니다.
lst.stream()
.filter(x -> x > 5)
.findFirst()
그러나 필터가 목록 전체를 스캔하기 때문에 비효율적으로 보입니다(적어도 잘못된 것일 수 있습니다).더 좋은 방법이 있을까요?
아니요, 필터는 전체 스트림을 검사하지 않습니다.이것은 느린 스트림을 반환하는 중간 작업입니다(실제로 모든 중간 작업은 느린 스트림을 반환합니다).다음과 같은 테스트를 실시하면 쉽게 납득할 수 있습니다.
List<Integer> list = Arrays.asList(1, 10, 3, 7, 5);
int a = list.stream()
.peek(num -> System.out.println("will filter " + num))
.filter(x -> x > 5)
.findFirst()
.get();
System.out.println(a);
출력:
will filter 1
will filter 10
10
스트림의 첫 번째 두 요소만 실제로 처리됩니다.
그래서 당신은 완벽하게 괜찮은 방법으로 접근 할 수 있습니다.
그러나 필터가 전체 목록을 스캔하기 때문에 비효율적으로 보입니다.
아니요. 술어를 만족시키는 첫 번째 요소가 발견되면 바로 "끊겨"집니다.특히 스트림 패키지 javadoc에서 게으름에 대한 자세한 내용을 볼 수 있습니다(강조).
필터링, 매핑 또는 중복 제거와 같은 많은 스트림 작업이 느긋하게 구현되어 최적화의 기회를 노출시킬 수 있습니다.예를 들어, "3개의 연속된 모음을 가진 첫 번째 문자열 찾기"는 모든 입력 문자열을 검사할 필요는 없습니다.스트림 운영은 중간(스트림 생산) 운영과 터미널(가치 또는 부작용 생산) 운영으로 나뉩니다.중간 작업은 항상 느립니다.
return dataSource.getParkingLots()
.stream()
.filter(parkingLot -> Objects.equals(parkingLot.getId(), id))
.findFirst()
.orElse(null);
개체 목록에서 하나의 개체만 걸러야 했습니다.그래서 이걸 썼어 도움이 됐으면 좋겠어
Alexis C의 답변 외에 검색 중인 요소가 존재하는지 확실하지 않은 배열 목록을 사용하는 경우 이 항목을 사용하십시오.
Integer a = list.stream()
.peek(num -> System.out.println("will filter " + num))
.filter(x -> x > 5)
.findFirst()
.orElse(null);
그런 다음 단순히 a가 다음과 같은지 여부를 확인할 수 있습니다.null
.
이미 @AjaxLeung에 의해 답변되어 있습니다만, 코멘트가 있어 찾기가 어렵습니다.
확인 전용
lst.stream()
.filter(x -> x > 5)
.findFirst()
.isPresent()
으로 단순화되다
lst.stream()
.anyMatch(x -> x > 5)
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
// Stream is ~30 times slower for same operation...
public class StreamPerfTest {
int iterations = 100;
List<Integer> list = Arrays.asList(1, 10, 3, 7, 5);
// 55 ms
@Test
public void stream() {
for (int i = 0; i < iterations; i++) {
Optional<Integer> result = list.stream()
.filter(x -> x > 5)
.findFirst();
System.out.println(result.orElse(null));
}
}
// 2 ms
@Test
public void loop() {
for (int i = 0; i < iterations; i++) {
Integer result = null;
for (Integer walk : list) {
if (walk > 5) {
result = walk;
break;
}
}
System.out.println(result);
}
}
}
개선된 원라이너 답변:부울값 반환값을 찾고 있는 경우 isPresent를 추가하면 더 나은 결과를 얻을 수 있습니다.
return dataSource.getParkingLots().stream().filter(parkingLot -> Objects.equals(parkingLot.getId(), id)).findFirst().isPresent();
루핑 기능이 있는 범용 유틸리티 함수가 훨씬 깔끔한 것 같습니다.
static public <T> T find(List<T> elements, Predicate<T> p) {
for (T item : elements) if (p.test(item)) return item;
return null;
}
static public <T> T find(T[] elements, Predicate<T> p) {
for (T item : elements) if (p.test(item)) return item;
return null;
}
사용 중:
List<Integer> intList = Arrays.asList(1, 2, 3, 4, 5);
Integer[] intArr = new Integer[]{1, 2, 3, 4, 5};
System.out.println(find(intList, i -> i % 2 == 0)); // 2
System.out.println(find(intArr, i -> i % 2 != 0)); // 1
System.out.println(find(intList, i -> i > 5)); // null
언급URL : https://stackoverflow.com/questions/23696317/find-first-element-by-predicate
'programing' 카테고리의 다른 글
int64_t의 정의 (0) | 2022.08.07 |
---|---|
상위 슬롯의 재사용 가능한 구성 요소 액세스 하위 메서드 (0) | 2022.08.03 |
Java Enum 정의 (0) | 2022.08.03 |
코드의 maven pom.xml에서 버전을 가져옵니다. (0) | 2022.08.03 |
Java 코드에서 Unix 쉘 스크립트를 실행하는 방법 (0) | 2022.08.03 |