如何使用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;
答案 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);