views:

409

answers:

8

I am programming a list of recent network messages communicated to/from a client. Basically I just want a list that stores up to X number of my message objects. Once the list reaches the desired size, the oldest (first) item in the list should be removed. The collection needs to maintain its order, and all I will need to do is

  1. iterate through it,
  2. add an item to the end, and
  3. remove an item from the beginning, if #2 makes it too long.

What is the most efficient structure/array/collection/method for doing this? Thanks!

+3  A: 

I don't think LILO is the real term...but you're looking for a FIFO Queue

Jason Punyon
Haha, that did occur to me that I had it wrong. Still, I mean the same thing! :)
ZenBlender
+10  A: 

You want to use a Queue.

Rich Adams
A: 

LinkedList should be what you're looking for

chburd
A: 

you can get by with a plain old ArrayList. When adding, just do (suppose the ArrayList is called al)

if (al.size() >= YOUR_MAX_ARRAY_SIZE)
{
  al.remove(0);
}
tehvan
But I'm guessing this isn't the most *efficient* way?
ZenBlender
+1  A: 

You can use an ArrayList for this. Todays computers copy data at such speeds that it doesn't matter unless your list can contain billions of elements.

Performance information: Copying 10 millions elements takes 13ms (thirteen milliseconds) on my dual core. So thinking even a second about the optimal data structure is a waste unless your use case is vastly different. In this case: You have more than 10 million elements and your application is doing nothing else but inserting and removing elements. If you operate in any way on the elements inserted/removed, chances are that the time spent in this operation exceeds the cost of the insert/remove.

A linked list seems to better at first glance but it needs more time when allocating memory plus the code is more complex (with all the pointer updating). So the runtime is worse. The only advantage of using a LinkedList in Java is that the class already implements the Queue interface, so it is more natural to use in your code (using peek() and pop()).

[EDIT] So let's have a look at efficiency. What is efficiency? The fastest algorithm? The one which takes the least amount of lines (and therefore has the least amount of bugs)? The algorithm which is easiest to use (= least amount of code on the developer side + less bugs)? The algorithm which performs best (which is not always the fastest algorithm)?

Let's look at some details: LinkedList implements Queue, so the code which uses the list is a bit more simple (list.pop() instead of list.remove(0)). But LinkedList will allocate memory for each add() while ArrayList only allocates memory once per N elements. And to reduce this even further, ArrayList will allocate N*3/2 elements, so as your list grows, the number of allocations will shrink. If you know the size of your list in advance, ArrayList will only allocate memory once. This also means that the GC has less clutter to clean up. So from a performance point of view, ArrayList wins by an order of magnitude in the average case.

The synchronized versions are only necessary when several threads access the data structure. With Java 5, many of those have seen dramatic speed improvements. If you have several threads putting and popping, use ArrayBlockingQueue but in this case, LinkedBlockingQueue might be an option despite the bad allocation performance since the implementation might allow to push and pop from two different threads at the same time as long as the queue size >= 2 (in this special case, the to threads won't have to access the same pointers). To decide that, the only option is to run a profiler and measure which version is faster.

That said: Any advice on performance is wrong 90% of the time unless it is backed by a measurement. Todays systems have become so complex and there is so much going on in the background that it is impossible for a mere human to understand or even enumerate all the factors which play a role.

Aaron Digulla
I still want to know what is most *efficient*. I already know how to do this with an ArrayList, but this is one critical part that I would like to run as fast as possible. By knowing about what is faster than an ArrayList, I might learn something! :)
ZenBlender
See it this way: The fastest running + least lines of code is the "most efficient". Lesson learned: Don't waste time searching for a solution that is better "than the best". That leaves more time to learn the important things.
Aaron Digulla
Who says I'm wasting time? The question interests me. If "fastest running + least lines of code" means using something that isn't an ArrayList, I'd like to learn what that thing is. I know that performance differences are small, but I don't think that invalidates my question.
ZenBlender
I say that because of my experience. I see a lot of pros losing a lot of time looking for a "better" solution instead of using the best one which is right in front of them. ArrayList is the fastest solution, all things considered.
Aaron Digulla
A: 

I think that you want to implement a Queue<E> where you have the peek, pull and remove methods act as if there is nothing on the head until the count exceeds the threshold that you want. You probably want to wrap one of the existing implementions.

dpp
+1  A: 

I second @rich-adams re: Queue. In particular, since you mentioned responding to network messages, I think you may want something that handles concurrency well. Check out ArrayBlockingQueue.

Hank Gay
Well, I've already got it programmed within a simple synchronized method, and was curious about the efficiency of the guts of it. I will look into an ArrayBlockingQueue though, thanks!
ZenBlender
+1  A: 

Based on your third requirement, I think you're going to have to extend or wrap an existing implementation, and I recommend you start with ConcurrentLinkedQueue.

Other recommendations of using any kind of blocking queue are leading you down the wrong path. A blocking queue will not allow you to add an element to a full queue until another element is removed. Furthermore, they block while waiting for that operation to happen. By your own requirements, this isn't the behavior you want. You want to automatically remove the first element when a new one is added to a full queue.

It should be fairly simple to create a wrapper around ConcurrentLinkedQueue, overriding the offer method to check the size and capacity (your wrapper class will maintain the capacity). If they're equal, your offer method will need to poll the queue to remove the first element before adding the new one.

Bill the Lizard