循环遍历一个巨大的列表,检查字符串是否为true

时间:2017-06-05 22:49:47

标签: java performance list search collections

我有以下要求:

List<User> userList = listOfUsers(); // Morethan 50,000 users

我需要从用户列表中找到用户状态。如果其中任何一个用户处于活动状态,则打破循环。

在java中处理这个问题的有效方法是什么?

6 个答案:

答案 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