java流找到匹配还是最后一个?

时间:2018-12-06 08:17:14

标签: java list lambda java-8 java-stream

如何使用Java流在列表中查找第一个匹配项或最后一个元素?

这意味着如果没有元素符合条件,则返回最后一个元素。

例如:

                                                                               java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/firebase/iid/internal/FirebaseInstanceIdInternal;
                                                                                   at com.google.firebase.iid.Registrar.getComponents(Unknown Source)
                                                                                   at com.google.firebase.components.zzf.<init>(com.google.firebase:firebase-common@@16.0.2:52)
                                                                                   at com.google.firebase.FirebaseApp.<init>(com.google.firebase:firebase-common@@16.0.2:539)
                                                                                   at com.google.firebase.FirebaseApp.initializeApp(com.google.firebase:firebase-common@@16.0.2:355)
                                                                                   at com.google.firebase.FirebaseApp.initializeApp(com.google.firebase:firebase-common@@16.0.2:324)
                                                                                   at com.google.firebase.FirebaseApp.initializeApp(com.google.firebase:firebase-common@@16.0.2:310)
                                                                                   at com.google.firebase.provider.FirebaseInitProvider.onCreate(com.google.firebase:firebase-common@@16.0.2:53)
                                                                                   at android.content.ContentProvider.attachInfo(ContentProvider.java:1739)
                                                                                   at android.content.ContentProvider.attachInfo(ContentProvider.java:1708)
                                                                                   at com.google.firebase.provider.FirebaseInitProvider.attachInfo(com.google.firebase:firebase-common@@16.0.2:47)
                                                                                   at android.app.ActivityThread.installProvider(ActivityThread.java:5262)
                                                                                   at android.app.ActivityThread.installContentProviders(ActivityThread.java:4836)
                                                                                   at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4776)
                                                                                   at android.app.ActivityThread.access$1500(ActivityThread.java:176)
                                                                                   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1498)
                                                                                   at android.os.Handler.dispatchMessage(Handler.java:111)
                                                                                   at android.os.Looper.loop(Looper.java:194)
                                                                                   at android.app.ActivityThread.main(ActivityThread.java:5576)
                                                                                   at java.lang.reflect.Method.invoke(Native Method)
                                                                                   at java.lang.reflect.Method.invoke(Method.java:372)
                                                                                   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:956)
                                                                                   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:751)
                                                                                Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.firebase.iid.internal.FirebaseInstanceIdInternal" on path: DexPathList[[zip file "/data/app/com.demoapp.demowork-1/base.apk"],nativeLibraryDirectories=[/vendor/lib64, /system/lib64]]
                                                                                   at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
                                                                                   at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
                                                                                   at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
                                                                                   at com.google.firebase.iid.Registrar.getComponents(Unknown Source) 
                                                                                   at com.google.firebase.components.zzf.<init>(com.google.firebase:firebase-common@@16.0.2:52) 
                                                                                   at com.google.firebase.FirebaseApp.<init>(com.google.firebase:firebase-common@@16.0.2:539) 
                                                                                   at com.google.firebase.FirebaseApp.initializeApp(com.google.firebase:firebase-common@@16.0.2:355) 
                                                                                   at com.google.firebase.FirebaseApp.initializeApp(com.google.firebase:firebase-common@@16.0.2:324) 
                                                                                   at com.google.firebase.FirebaseApp.initializeApp(com.google.firebase:firebase-common@@16.0.2:310) 
                                                                                   at com.google.firebase.provider.FirebaseInitProvider.onCreate(com.google.firebase:firebase-common@@16.0.2:53) 
                                                                                   at android.content.ContentProvider.attachInfo(ContentProvider.java:1739) 
                                                                                   at android.content.ContentProvider.attachInfo(ContentProvider.java:1708) 
                                                                                   at com.google.firebase.provider.FirebaseInitProvider.attachInfo(com.google.firebase:firebase-common@@16.0.2:47) 
                                                                                   at android.app.ActivityThread.installProvider(ActivityThread.java:5262) 
                                                                                   at android.app.ActivityThread.installContentProviders(ActivityThread.java:4836) 
                                                                                   at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4776) 
                                                                                   at android.app.ActivityThread.access$1500(ActivityThread.java:176) 
                                                                                   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1498) 
                                                                                   at android.os.Handler.dispatchMessage(Handler.java:111) 
                                                                                   at android.os.Looper.loop(Looper.java:194) 
                                                                                   at android.app.ActivityThread.main(ActivityThread.java:5576) 
                                                                                   at java.lang.reflect.Method.invoke(Native Method) 
                                                                                   at java.lang.reflect.Method.invoke(Method.java:372) 
                                                                                   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:956) 
                                                                                   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:751) 
                                                                                Suppressed: java.lang.ClassNotFoundException: com.google.firebase.iid.internal.FirebaseInstanceIdInternal
                                                                                   at java.lang.Class.classForName(Native Method)
                                                                                   at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
                                                                                   at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
                                                                                   at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
                                                                                        ... 23 more
                                                                                Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack available

我应该怎么做才能使它返回5;

5 个答案:

答案 0 :(得分:14)

提供列表

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);

您可以这样做:

int value = list.stream().filter(x -> x == 2)
                         .findFirst()
                         .orElse(list.get(list.size() - 1));

如果过滤器的评估结果为true,则检索到该元素,否则返回最后一个元素中的最后一个元素。

如果列表为,则可以返回默认值,例如-1。

int value = list.stream().filter(x -> x == 2)
                         .findFirst()
                         .orElse(list.isEmpty() ? -1 : list.get(list.size() - 1));

答案 1 :(得分:7)

您可以像这样使用reduce()函数:

OptionalInt i = IntStream.rangeClosed(1, 5)
        .reduce((first, second) -> first == 7 ? first : second);
System.out.print(i.getAsInt());

答案 2 :(得分:5)

基本上,我将使用以下两种方法之一或其偏差:

流变体:

<T> T getFirstMatchOrLast(List<T> list, Predicate<T> filter, T defaultValue) {
    return list.stream()
            .filter(filter)
            .findFirst()
            .orElse(list.isEmpty() ? defaultValue : list.get(list.size() - 1));
}

非流变种:

<T> T getFirstMatchOrLast(Iterable<T> iterable, Predicate<T> filter, T defaultValue) {
    T relevant = defaultValue;
    for (T entry : iterable) {
        relevant = entry;
        if (filter.test(entry))
            break;
    }
    return relevant;
}

或者在Ilmari Karonen中用Iterable<T>发表的建议中,您甚至可以呼叫stream::iterator,以防您真正处理Stream而不是{{ 1}}。调用显示的方法将如下所示:

List

在这里我不会使用getFirstMatchOrLast(Arrays.asList(1, 20, 3), i -> i == 20, 1); // returns 20 getFirstMatchOrLast(Collections.emptyList(), i -> i == 3, 20); // returns 20 getFirstMatchOrLast(Arrays.asList(1, 2, 20), i -> i == 7, 30); // returns 20 // only non-stream variant: having a Stream<Integer> stream = Stream.of(1, 2, 20) getFirstMatchOrLast(stream::iterator, i -> i == 7, 30); // returns 20 ,因为从某种意义上说,这听起来对我来说是错误的,即使第一个条目可能已经匹配,它也会遍历整个条目,即不会短路不再。而且对我而言,它不如reduce ...(但这可能只是我的观点)

我什至可能会得到如下结果:

filter.findFirst.orElse

因此呼叫看起来像:

<T> Optional<T> getFirstMatchOrLast(Iterable<T> iterable, Predicate<T> filter) {
    T relevant = null;
    for (T entry : iterable) {
        relevant = entry;
        if (filter.test(entry))
            break;
    }
    return Optional.ofNullable(relevant);
}
// or transform the stream variant to somethinng like that... however I think that isn't as readable anymore...

答案 3 :(得分:3)

如果要在一个管道中执行此操作,则可以执行以下操作:

int startInc = 1;
int endEx = 5;
OptionalInt first = 
       IntStream.concat(IntStream.range(startInc, endEx)
                .filter(x -> x == 7), endEx > 1 ? IntStream.of(endEx) : IntStream.empty())
                .findFirst();

但是最好将生成的数字收集到一个列表中,然后按以下步骤对其进行操作:

// first collect the numbers into a list
List<Integer> result = IntStream.rangeClosed(startInc,endEx)
                                   .boxed()
                                   .collect(toList());
    // then operate on it 
int value = result.stream()
                  .filter(x -> x == 7)
                  .findFirst()
                  .orElse(result.get(result.size() - 1)); 

或者,如果要使后者在源为空的情况下(如果可能的话)返回空的Optional而不是异常,则可以执行以下操作:

List<Integer> result = IntStream.rangeClosed(startInc,endEx)
                                .boxed()
                                .collect(toList());

Optional<Integer> first = 
         Stream.concat(result.stream().filter(x -> x == 7), result.isEmpty() ? 
                Stream.empty() : Stream.of(result.get(result.size() - 1)))
                .findFirst();

答案 4 :(得分:2)

我不确定您为什么真的要使用流,简单的for循环就足够了:

public static <T> T getFirstMatchingOrLast(List<? extends T> source, Predicate<? super T> predicate){
    // handle empty case
    if(source.isEmpty()){
        return null;
    }
    for(T t : source){
        if(predicate.test(t)){
            return t;
        }
    }
    return source.get(source.size() -1);
} 

然后可以这样称呼:

Integer match = getFirstMatchingOrLast(ints, i -> i == 7);