Java 8 Streams: 여러 필터와 복잡한 조건 비교
경우에 따라서는, A를 필터링 하고 싶은 경우가 있습니다.Stream
여러 조건이 있는 경우:
myList.stream().filter(x -> x.size() > 10).filter(x -> x.isCool()) ...
또는 복잡한 조건과 단일 조건에서도 동일한 작업을 수행할 수 있습니다. filter
:
myList.stream().filter(x -> x.size() > 10 && x -> x.isCool()) ...
제 생각에는 두 번째 접근 방식이 더 나은 성능 특성을 가지고 있는 것 같습니다만, 저는 잘 모르겠습니다.
첫 번째 접근 방식은 가독성이 우수합니다. 하지만 어떤 방법이 더 나은 성능을 제공합니까?
두 가지 방법을 모두 실행해야 하는 코드는 너무 비슷하여 결과를 신뢰할 수 없습니다.기본 객체 구조는 다를 수 있지만 핫스팟 최적화 도구에는 문제가 되지 않습니다.따라서 다른 환경 조건에 따라 다르다면 더 빨리 실행될 수 있습니다.
두 필터 인스턴스를 결합하면 더 많은 객체가 생성되고 따라서 더 많은 위임 코드가 생성되지만, 대체와 같이 람다 식이 아닌 메서드 참조를 사용하면 이 값이 변경될 수 있습니다.filter(x -> x.isCool())
타고filter(ItemType::isCool)
이렇게 하면 람다 표현에 대해 작성된 합성 위임 메서드가 제거됩니다.따라서 두 개의 메서드 참조를 사용하여 두 개의 필터를 조합하면 단일 필터보다 같거나 적은 위임 코드가 생성될 수 있습니다.filter
람다 식을 사용한 호출&&
.
그러나 앞서 말한 바와 같이 이러한 오버헤드는 HotSpot 옵티마이저에 의해 제거되며 무시할 수 있습니다.
이론적으로 두 개의 필터는 단일 필터보다 더 쉽게 병렬화할 수 있지만, 이는 계산 부하가 높은 작업에만 관련이 있습니다.
그래서 간단한 답은 없다.
결론은 냄새 감지 한계치 이하의 성능 차이는 생각하지 말라는 것입니다.읽기 쉬운 것을 사용하세요.
§…그 후 단계의 병렬 처리를 실시하는 실장이 필요하지만, 현재는 표준적인 스트림 실장에서는 행해지지 않는 길입니다.
복잡한 필터 조건은 성능 측면에서 더 낫지만, 최고의 성능은 표준 루프에 대한 오래된 패션을 보여줍니다.if clause
최적의 옵션입니다.소규모 어레이의 경우 10개 요소의 차이는 최대 2배이며, 대규모 어레이의 경우 차이는 그다지 크지 않습니다.
여러 어레이 반복 옵션에 대한 성능 테스트를 수행한 GitHub 프로젝트를 보실 수 있습니다.
스몰 어레이 10 요소 스루풋 ops/s의 경우: 중규모 10,000 요소의 경우 throughput ops/s: 대규모 어레이의 경우 1,000,000개의 요소 스루풋 ops/s:
메모: 테스트 실행일
- 8 CPU
- 1 GB RAM
- OS 버전: 16.04.1 LTS (Xenial Xerus)
- Java 버전: 1.8.0_builes
- jvm: -XX:+G1 사용GC - 서버 - Xmx1024m - Xms1024m
업데이트: Java 11은 퍼포먼스가 다소 향상되었지만 역동성은 그대로입니다.
벤치마크 모드:스루풋, ops/time
이 테스트에서는 두 번째 옵션이 훨씬 더 나은 성능을 발휘할 수 있음을 보여 줍니다.먼저 조사 결과, 그 다음 코드:
one filter with predicate of form u -> exp1 && exp2, list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=4142, min=29, average=41.420000, max=82}
two filters with predicates of form u -> exp1, list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=13315, min=117, average=133.150000, max=153}
one filter with predicate of form predOne.and(pred2), list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=10320, min=82, average=103.200000, max=127}
이제 코드:
enum Gender {
FEMALE,
MALE
}
static class User {
Gender gender;
int age;
public User(Gender gender, int age){
this.gender = gender;
this.age = age;
}
public Gender getGender() {
return gender;
}
public void setGender(Gender gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
static long test1(List<User> users){
long time1 = System.currentTimeMillis();
users.stream()
.filter((u) -> u.getGender() == Gender.FEMALE && u.getAge() % 2 == 0)
.allMatch(u -> true); // least overhead terminal function I can think of
long time2 = System.currentTimeMillis();
return time2 - time1;
}
static long test2(List<User> users){
long time1 = System.currentTimeMillis();
users.stream()
.filter(u -> u.getGender() == Gender.FEMALE)
.filter(u -> u.getAge() % 2 == 0)
.allMatch(u -> true); // least overhead terminal function I can think of
long time2 = System.currentTimeMillis();
return time2 - time1;
}
static long test3(List<User> users){
long time1 = System.currentTimeMillis();
users.stream()
.filter(((Predicate<User>) u -> u.getGender() == Gender.FEMALE).and(u -> u.getAge() % 2 == 0))
.allMatch(u -> true); // least overhead terminal function I can think of
long time2 = System.currentTimeMillis();
return time2 - time1;
}
public static void main(String... args) {
int size = 10000000;
List<User> users =
IntStream.range(0,size)
.mapToObj(i -> i % 2 == 0 ? new User(Gender.MALE, i % 100) : new User(Gender.FEMALE, i % 100))
.collect(Collectors.toCollection(()->new ArrayList<>(size)));
repeat("one filter with predicate of form u -> exp1 && exp2", users, Temp::test1, 100);
repeat("two filters with predicates of form u -> exp1", users, Temp::test2, 100);
repeat("one filter with predicate of form predOne.and(pred2)", users, Temp::test3, 100);
}
private static void repeat(String name, List<User> users, ToLongFunction<List<User>> test, int iterations) {
System.out.println(name + ", list size " + users.size() + ", averaged over " + iterations + " runs: " + IntStream.range(0, iterations)
.mapToLong(i -> test.applyAsLong(users))
.summaryStatistics());
}
@Hank D @Hank D h h h h h가 6 른 h 른 른 h h h h h h h h 。 형식의 술어가u -> exp1 && exp2
이치노
one filter with predicate of form u -> exp1 && exp2, list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=3372, min=31, average=33.720000, max=47}
two filters with predicates of form u -> exp1, list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=9150, min=85, average=91.500000, max=118}
one filter with predicate of form predOne.and(pred2), list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=9046, min=81, average=90.460000, max=150}
one filter with predicate of form u -> exp1 && exp2, list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=8336, min=77, average=83.360000, max=189}
one filter with predicate of form predOne.and(pred2), list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=9094, min=84, average=90.940000, max=176}
two filters with predicates of form u -> exp1, list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=10501, min=99, average=105.010000, max=136}
two filters with predicates of form u -> exp1, list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=11117, min=98, average=111.170000, max=238}
one filter with predicate of form u -> exp1 && exp2, list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=8346, min=77, average=83.460000, max=113}
one filter with predicate of form predOne.and(pred2), list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=9089, min=81, average=90.890000, max=137}
two filters with predicates of form u -> exp1, list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=10434, min=98, average=104.340000, max=132}
one filter with predicate of form predOne.and(pred2), list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=9113, min=81, average=91.130000, max=179}
one filter with predicate of form u -> exp1 && exp2, list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=8258, min=77, average=82.580000, max=100}
one filter with predicate of form predOne.and(pred2), list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=9131, min=81, average=91.310000, max=139}
two filters with predicates of form u -> exp1, list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=10265, min=97, average=102.650000, max=131}
one filter with predicate of form u -> exp1 && exp2, list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=8442, min=77, average=84.420000, max=156}
one filter with predicate of form predOne.and(pred2), list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=8553, min=81, average=85.530000, max=125}
one filter with predicate of form u -> exp1 && exp2, list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=8219, min=77, average=82.190000, max=142}
two filters with predicates of form u -> exp1, list size 10000000, averaged over 100 runs: LongSummaryStatistics{count=100, sum=10305, min=97, average=103.050000, max=132}
언급URL : https://stackoverflow.com/questions/24054773/java-8-streams-multiple-filters-vs-complex-condition
'source' 카테고리의 다른 글
Vuex의 setimeout 기능 내 상태를 변경 및 커밋할 수 있습니까? (0) | 2022.09.01 |
---|---|
Java 유닛 테스트에 텍스트 파일 리소스를 읽는 방법은 무엇입니까? (0) | 2022.09.01 |
TypeError: 정의되지 않은 속성 'get'을 읽을 수 없습니다(Vue-resource 및 Nuxt). (0) | 2022.09.01 |
잘못된 소품: 소품에 대한 형식 검사에 실패했습니다. (0) | 2022.09.01 |
Vue 구성 요소의 Vuex 바인딩 유형을 선언하는 방법 (0) | 2022.09.01 |