我有以下要求:
List<User> userList = listOfUsers(); // Morethan 50,000 users
我需要从用户列表中找到用户状态。如果其中任何一个用户处于活动状态,则打破循环。
在java中处理这个问题的有效方法是什么?
答案 0 :(得分:2)
带方法参考的Java 8解决方案:
userList.stream().filter(User::isActive).findFirst()
它会返回Optional
,因此您可以映射它。
答案 1 :(得分:1)
如果您正在使用SQL,那么有效的方法是使用SQL进行过滤。只选择活跃用户....
当你拥有使用java的所有列表时,它会很慢而且这里没有魔法,你需要迭代。
public User getActiveUserFromList(userList) {
for (User user : userList) {
if (user.isActive()) {
return user;
}
return null;
}
}
如果您有任何订单,您可以尝试破解它,我们假设它是按活动状态排序的
public Boolean isAnyActive(userList) {
if (userList.first().isActive()) { // try first
return true;
}
if (userList.last().isActive()) { // if its ordered and there is an active user, the last surely will be active, since first wasn't
return true;
}
return false;
}
答案 2 :(得分:1)
加速搜索的一种方法(不使用Java 8 )是通过搜索ArrayList
中的两个方向(即从开头到中间,从结尾到中间) )同时通过 多线程 ,我创建了这个示例,并针对 100万 对象对其进行了测试/ user检查其中是否有任何一个处于活动状态(请注意,我只使一个用户处于活动状态并将其置于中间中以查看最长< / strong>搜索可能需要的时间)。
import java.util.ArrayList;
public class User {
// some fields to test
String name;
boolean active;
//volatile means all writes up to the volatile variable
//from other any thread are now visible to all other threads.
//so they can share working on that variable
static volatile boolean finishFirst = false; // to announce first thread finish
static volatile boolean finishSecond = false; // to announce second thread finish
static volatile boolean found = false; // // to announce if an active user found
/**
* Simple Constructor
* @param name
* @param active
*/
public User(String name, boolean active){
this.name = name;
this.active = active;
}
public static void main(String[] args) {
// create an ArrayList of type User
ArrayList<User> list = new ArrayList<User>();
// populate it with 1 MILLION user!!
int i=0;
for(;i<1000000; i++){
// make only the one in the very middle active to prolong the search to max
if(i==500000){
list.add(new User(String.valueOf(i),true));
}
else{
list.add(new User(String.valueOf(i),false));
}
}
System.out.println("End of Adding " + i + " User" );
// to measure how long it will take
long startTime, endTime;
startTime = System.currentTimeMillis();
System.out.println("Found Any Active: "+ isAnyActive(list)); // invoke the method
endTime = System.currentTimeMillis();
System.out.println(endTime-startTime + " MilliScond");
}
public static boolean isAnyActive(ArrayList<User> list){
found = false;
// create two threads, each search the half of the array
// so that shall save time to half
Thread t1 = new Thread(new Runnable(){
@Override
public void run() {
// read one more index in case the size is not an even number
// so it will exceed the middle in one -> no problem at all
for(int i=0; i<=(list.size()/2)+1; i++){
if(list.get(i).active) {
found = true;
finishFirst = true;
break;
}
}
finishFirst = true; // in case did not find any
}
});
// second thread the same, but read from the end to the middle
Thread t2 = new Thread(new Runnable(){
public void run() {
for(int i=list.size()-1; i>=list.size()/2; i--){
if(list.get(i).active) {
found = true;
finishSecond = true;
break;
}
}
finishSecond = true;
}
});
// start both thread
t2.start();
t1.start();
// while one of them has not finished yet
while(!finishFirst || !finishSecond){
// but in case not finished looping but found an active user
// break the loop
if(found){break;}
}
return found; // return the result
}
}
<强>测试强>
End of Adding 1000000 User
Found Any Active: true
31 MilliScond
答案 3 :(得分:0)
我当然会考虑使用Java 8 Lambda。我写了一个示例类:
package com.chocksaway;
import java.util.ArrayList;
import java.util.List;
/**
* Author milesd on 05/06/2017.
*/
class Name {
private String name;
private Boolean status;
public Name(String name, Boolean status) {
this.name = name;
this.status = status;
}
public String getName() {
return name;
}
public Boolean getStatus() {
return status;
}
}
public class FindFirstInStream {
public static void main(String[] args) {
List<Name> userList = new ArrayList<>();
userList.add(new Name("James", false));
userList.add(new Name("Eric", true));
userList.add(new Name("David", false));
Name firstActiveName = userList.stream()
.filter(e -> e.getStatus().equals(true))
.findFirst()
.get();
System.out.println(firstActiveName.getName());
}
}
我创建了一个Name类,其中包含名称和状态。
我用James,Eric和David填充了一个userList。
我使用Java 8流过滤,并返回第一个“活动”名称(Eric)。
这存储在“firstActiveName”中。
答案 4 :(得分:0)
您可以使用Collections ArrayDeque。 ArrayDeques将使用迭代的一半来查找活动用户。在你的情况下
public java.io.PrintStream printf(java.lang.String, java.lang.Object...);
public java.io.PrintStream printf(java.util.Locale, java.lang.String, java.lang.Object...);
public java.io.PrintStream format(java.lang.String, java.lang.Object...);
public java.io.PrintStream format(java.util.Locale, java.lang.String, java.lang.Object...);
答案 5 :(得分:0)
因为我看到许多不使用并行流的Java 8流媒体解决方案,所以我添加了这个答案。您有一个大型集合,您可以在其上进行匹配,因此当您选择使用Java 8时,可以使用parallelStream的强大功能。
Optional<User> result = userList.parallelStream().filter(User::isActive).findAny();
使用parallelStream会将流拆分为多个子流,这对于非常大的集合更有效。它在内部使用ForkJoinPool来处理这些子流。这里唯一的区别是我在此解决方案中使用findAny()
而不是findFirst()
。
这就是Javadoc对findAny()
所说的话:
此操作的行为明确是不确定的;它是 可以自由选择流中的任何元素。这是为了允许最大 并行运营绩效;成本是多倍的 同一源上的调用可能不会返回相同的结果。 (如果一个 需要稳定的结果,请改用findFirst()。)
这是来自Oracle的一个不错的tutorial on Parallelism。