I'm just starting to work with lists in java. I'm wondering what the recommended method to modify each element of a list would be?
I've been able to get it done with both the following methods, but they both seem fairly unelegant. Is there any better way to get this done in java? And is any of the below methods recommended over the other, or are both on the same level?
//Modifying with foreach
for (String each : list)
{
list.set(list.indexOf(each), each+ " blah");
}
//Modifying with for
for (ListIterator<String> i = list.listIterator(); i.hasNext(); i.next())
{
i.next();
list.set(i.nextIndex()-1, i.previous() + " blah yadda");
}
The second version would be better. Internally they are the same in the end, but the second actually allows you to modify the list, while the first one will throw a ConcurrentModificationException.
But then you are using the Iterator in a wrong way. Here is how you do it correctly:
for (final ListIterator<String> i = list.listIterator(); i.hasNext();) {
final String element = i.next();
i.set(element + "yaddayadda");
}
The iterator is the one that needs to modify the list as it is the only one that knows how to do that properly without getting confused about the list elements and order.
Edit: Because I see this in all comments and the other answers:
Why you should not use list.get, list.set and list.size in a loop
There are many collections in the Java collections framework, each on optimized for specific needs. Many people use the ArrayList, which internally uses an array. This is fine as long as the amount of elements does not change much over time and has the special benefit that get, set and size are constant time operations on this specific type of list.
There are however other list types, where this is not true. For example if you have a list that constantly grows and/or shrinks, it is much better to use a LinkedList, because in contrast to the ArrayList add(element) is a constant time operation, but add(index, element), get(index) and remove(index) are not!
To get the position of the specific index, the list needs to be traversed from the first/last till the specific element is found. So if you do that in a loop, this is equal to the following pseudo-code:
for (int index = 0; index < list.size(); ++index) {
Element e = get( (for(int i = 0; i < size; ++i) { if (i == index) return element; else element = nextElement(); }) );
}
The Iterator is an abstract way to traverse a list and therefore it can ensure that the traversal is done in an optimal way for each list. Test show that there is little time difference between using an iterator and get(i) for an ArrayList, but a huge time difference (in favor for the iterator) on a LinkedList.
EDIT: If you know that size(), get(index) and set(index, value) are all constant time operations for the operations you're using (e.g. for ArrayList), I would personally just skip the iterators in this case:
for (int i = 0; i < list.size(); i++) {
list.set(i, list.get(i) + " blah");
}
Your first approach is inefficient and potentially incorrect (as indexOf may return the wrong value - it will return the first match). Your second approach is very confusing - the fact that you call next() twice and previous once makes it hard to understand in my view.
Any approach using List.set(index, value) will be inefficient for a list which doesn't have constant time indexed write access, of course. As TwoThe noted, using ListIterator.set(value) is much better. TwoThe's approach of using a ListIterator is a better general purpose approach.
That said, another alternative in many cases would be to change your design to project one list to another instead - either as a view or materially. When you're not changing the list, you don't need to worry about it.
Internally there in Iterator for for-each implementation. So there is no deference between these two cases. But if you trying to modify element it will throws ConcurrentModificationException.
I got mine working this way
String desiredInvoice="abc-123";
long desiredAmount=1500;
for (ListIterator<MyPurchase> it = input.getMyPurchaseList().listIterator(); it.hasNext();) {
MyPurchase item = it.next();
if (item.getInvoiceNo().equalsIgnoreCase(desiredInvoice)) {
item.setPaymentAmount(desiredAmount);
it.set(item);
break;
}
}
Related
I am having some trouble with removing values that do not match a given value. At the moment I am copying over values to a new list and trying to clear the original list - but this is inefficient.
This is my code:
int size = list.size();
ArrayList<String> newList;
int count = 0;
newList = new ArrayList<>();
for (int i=0; i<list.size(); i++){
if(list.get(i).getForename().equals(forename)){
newList.add(i, list);
}
}
list.clear();
Is there a way where I can just remove an item in the arraylist if it does NOT match the name?
EDIT:
It works but then I might need a copy, as if I select a another name from the dropdown it will be referring to the old one
Thanks
A first thought would be to iterate on the list and as soon as you find an item not matching the value, you remove it. But it will create a Concurrent modification exception, as you iterate on list while trying to remove elements in it.
An other, still not efficient would be to iterate on the list, keep track of the indexes to remove, and after iterating on the list, remove them.
ArrayList<Integer> indexList = new ArrayList<Integer>();
for(int i = 0; i<list.size(); i++){
if(!list.get(i).getForename().equals(forename)){
indexList.add(i);
}
for(Integer index : indexList){
list.remove(index);
}
indexList.clear();
Please not that this is not really efficient too, but maybe you were looking for a way to delete from the same list.
A simple solution is
while (list.contains(value)) {
list.remove(list.indexOf(value));
}
Depending on what you want, you might want to use streams instead (seems to be what you actually want, since you don't really seem to want to delete elements in your list):
newList = list.stream()
.filter(e -> getForename().equals(forename))
.collect(Collectors.toList());
or to perform your action what you might want to do:
list.stream()
.filter(e -> getForename().equals(forename))
.forEach(person -> doStuff(person));
Another way would be using iterators to avoid conflicts with modifications during iteration:
ListIterator iterator = list.listIterator();
while(iterator.hasNext()){
if(!iterator.getNext().getForename().equals(forename))
iterator.remove();
}
EDIT: Since OP can't use lambdas and streams (because of Java-version), here is what nearly happens for the second stream (the forEach). I am not using the proper interfaces, since OP can't do so either. The difference to streams is, that they also might split this into several threads and hence would be faster (especially on multi-core processors and big lists):
interface Consumer<T>{ //this is normally given by the JAVA 8 API (which has one more default method)
void accept(T t);
}
Consumer<YourObject> doIt = new Consumer<YourObject>(){ //This is what the lambda expression actually does
#Override
public void accept(YourObject e) {
doStuff(e);
}
};
for(YourObject element : list){ //since JAVA 1.5. Alternativ your old for-loop with element=list.get(i);
if(!element.getForename().equals(forename)) //the filter written in easy
continue;
doIt.accept(element); //You could also use a method or expressions instead in this context.
//doStuff(element); //What actually the upper stream does.
}
You might want to look at the oracle tutorial (this chapter) to get a feeling, when this design is appropriate https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html (I have a strong feeling, you might want to use it).
Assuming your List contains String objects the following should be what you are looking for:
for (Iterator<String> it = list.iterator(); it.hasNext()){
String foreName = it.next();
if(forName != null && foreName.equals(forename)){
it.remove();
}
}
try
for (int i=0; i<list.size();){
if(!list.get(i).getForename().equals(forename)){
list.remove(i);
}
else {
i++;
}
}
I have a real-time program that runs a continuous while loop...
example:
while(true)
{
}
Inside that loop I have a for(MyObject o: myobjects) loop. When I run my code I see that every iteration of the while loop a new iterator is created to loop over my LinkedList called myobjects
What is a better way of iterating over a LinkedList without having Java create a ListIterator every time?
New iterator is given out by design. Read this. It gives you a new iterator every time you call iterator() method and it doesn't maintain states.
Code for the iterator :
public ListIterator<E> listIterator(final int index) {
rangeCheckForAdd(index);
return new ListItr(index);
}
What is a better way of iterating over a LinkedList without having Java create a ListIterator every time?
"Better" is very situational. You should consider whether the behavior you have now is actually a problem, because what you describe is about the simplest Java code for the job.
If you do need to iterate specifically over a LinkedList (as opposed, say, to an ArrayList), and you want to do so without creating a new ListIterator every time, then your best bet is probably to create a single ListIterator up front, and reuse it at every iteration:
ListIterator<MyObject> iterator = myobjects.listIterator();
while (true) {
// Return to the beginning of the list:
while (iterator.hasPrevious()) {
iterator.previous();
}
// The desired iteration:
while (iterator.hasNext()) {
MyObject o = iterator.next();
// do something with o
}
}
Do be aware, however, that this opens you up to trouble if the underlying list is modified. Any such modification will invalidate the ListIterator (its methods should start throwing ConcurrentModificationExceptions). In your original code, that will affect just one iteration of the outer loop, but if you reuse the iterator then you may need different handling of that situation. If the list is modified elsewhere in the outer loop, then re-using the same iterator is right out.
On the other hand, if you could be sure that you have a RandomAccess list, such as an ArrayList, then you could reasonably avoid iterators altogether, and just iterate by index:
while (true) {
// The desired iteration:
for (int i = 0; i < myobjects.size(); i += 1) {
MyObject o = myobjects.get(i);
// do something with o
}
}
Do not do that if you have or may have a LinkedList, however, because it will increase the cost of the iteration from O(n) to O(n2) for LinkedLists and similar sequential-access lists.
The source code of LinkedList says a new iterator is being created. If your list is dynamic, you will need a new iterator as it will become stale.
But, I believe if your list is a constant, you are better off running a normal for loop.
`int length = myobjects.size();
for (int i=0; i < length; i++)
{
//access here
}`
How does one iterate through a list datastructure using indices. For example consider a sentence in form a list with each element being a word. Can I step through each word using the index? Something like this --
// sentence defined something like this - List<String>
int size = sentence.size();
for (int i=0; i<size-1; i++)
{
System.out.println(sentence[i] + " " + sentence[i+1]);
}
ofcourse the above code doesn't work but is it possible to do something on those lines? As you can see, I want to access the two consecutive elements and using iterators, it starts becoming really messy.
You can use the get(i) method instead of [i]:
for (int i=0; i<size-1; i++) {
System.out.println(sentence.get(i) + " " + sentence.get(i+1));
}
List instances are not the same as arrays. They have specific methods for obtaining items at certain indexes. Try this:
// sentence defined something like this - List<String>
int size = sentence.size();
for (int i=0; i<size-1; i++)
{
System.out.println(sentence.get(i) + " " + sentence.get(i + 1));
}
Now if you had an array (e.g. String[] sentence = new String[]{"hello", "there"}), what you had would work fine.
As a side note, Java has a for-each loop that can be used on both arrays and Lists:
for (String s : sentence) {
// do something
}
Of course, this can't be used in your case because you're accessing elements at multiple indexes in each iteration of your loop - but it's important to know that something like this exists.
The x[i] expression syntax in Java can only be used for arrays. Nothing else.
As other answers have stated, the way to step through the elements of a Java list using indices is to use List.get(int). However, there is an important performance issue that needs to be considered when you do this.
The issue is that the cost of a get(int) call depends on what List implementation class you use:
For an ArrayList (or a Vector) the get(int) operation on a list of length N is O(1). That means that it does not depend on the list length, and in fact it is cheap: only a bit more expensive than an someArray[i].
For a LinkedList, the get(int) operation on a list has to step through the list from the beginning until it reaches the position you asked for. If the list length is N, then the average cost of get(int) (assuming a random position in the list) is O(N); i.e. it is proportional to the list length. If the length is long, then that will be expensive.
By contrast, if you use an Iterator (explicitly, or implicitly by using the for (E e : l) syntax), getting each element will be O(1) for all of the list implementations in java.util and java.util.concurrent (ignoring multi-threading issues such as heavy contention).
Having said that, there are some cases where iterators don't work, and the application needs to use indices.
You can also use Iterator in this case for ex:
first of all put ur elements on arraylist and try to use Iterator like this:
ArrayList arrayList = new ArrayList();
Iterator itr = arrayList.iterator();
while(itr.hasNext())
{
System.out.println(itr.next()); // Print out the elements from arraylist
}
You can process consecutive pairs of values from a list without using indices. Here's one way:
private void processWordsInSentence(List<String> sentence) {
Iterator<String> it = sentence.iterator();
if (it.hasNext()) {
String previous = it.next();
while(it.hasNext()) {
String current = it.next();
// use previous and current values, e.g.
System.out.println(previous + " " + current);
previous = current;
}
}
}
Why would you want to use something like this instead of sentence.get(index)? I would offer a couple of reasons:
In your sample, your processing is really concerned with consecutive
values from the list, not their positions. So there's no "value add"
to having to fiddle with the index explicitly.
Remember that List<T> is an interface with multiple
implementations. ArrayList<T> performs .get(index) in constant
time, but that same call on a LinkedList<T> requires time
proportional to the value of index. So there could be a real performance
consideration.
The processWordsInSentence implementation above does have to deal explicitly with the case of lists with less than two elements. The loop inside the guarding if can be written with a for statement, to separate traversal from processing the actual data a bit more aggressively, if you prefer that style.
private void processWordsInSentence(List<String> sentence) {
Iterator<String> it = sentence.iterator();
if (it.hasNext()) {
for (
String previous = it.next(), current = null;
it.hasNext();
previous = current
) {
// use previous and current values, e.g.
System.out.println(previous + " " + current);
}
}
}
Try this simple code :
List mobileSoftwares = new ArrayList();
mobileSoftwares.add("Android");
mobileSoftwares.add("IOS");
mobileSoftwares.add("Blackberry");
int size = mobileSoftwares.size();
for (int i = 0; i < size - 1; i++)
{
System.out.println(mobileSoftwares.get(i));
}
I need to figure out the number of elements in an Iterable in Java.
I know I can do this:
Iterable values = ...
it = values.iterator();
while (it.hasNext()) {
it.next();
sum++;
}
I could also do something like this, because I do not need the objects in the Iterable any further:
it = values.iterator();
while (it.hasNext()) {
it.remove();
sum++;
}
A small scale benchmark did not show much performance difference, any comments or other ideas for this problem?
TL;DR: Use the utility method Iterables.size(Iterable) of the great Guava library.
Of your two code snippets, you should use the first one, because the second one will remove all elements from values, so it is empty afterwards. Changing a data structure for a simple query like its size is very unexpected.
For performance, this depends on your data structure. If it is for example in fact an ArrayList, removing elements from the beginning (what your second method is doing) is very slow (calculating the size becomes O(n*n) instead of O(n) as it should be).
In general, if there is the chance that values is actually a Collection and not only an Iterable, check this and call size() in case:
if (values instanceof Collection<?>) {
return ((Collection<?>)values).size();
}
// use Iterator here...
The call to size() will usually be much faster than counting the number of elements, and this trick is exactly what Iterables.size(Iterable) of Guava does for you.
If you are working with java 8 you may use:
Iterable values = ...
long size = values.spliterator().getExactSizeIfKnown();
it will only work if the iterable source has a determined size. Most Spliterators for Collections will, but you may have issues if it comes from a HashSetor ResultSetfor instance.
You can check the javadoc here.
If Java 8 is not an option, or if you don't know where the iterable comes from, you can use the same approach as guava:
if (iterable instanceof Collection) {
return ((Collection<?>) iterable).size();
} else {
int count = 0;
Iterator iterator = iterable.iterator();
while(iterator.hasNext()) {
iterator.next();
count++;
}
return count;
}
This is perhaps a bit late, but may help someone. I come across similar issue with Iterable in my codebase and solution was to use for each without explicitly calling values.iterator();.
int size = 0;
for(T value : values) {
size++;
}
You can cast your iterable to a list then use .size() on it.
Lists.newArrayList(iterable).size();
For the sake of clarity, the above method will require the following import:
import com.google.common.collect.Lists;
Strictly speaking, Iterable does not have size. Think data structure like a cycle.
And think about following Iterable instance, No size:
new Iterable(){
#Override public Iterator iterator() {
return new Iterator(){
#Override
public boolean hasNext() {
return isExternalSystemAvailble();
}
#Override
public Object next() {
return fetchDataFromExternalSystem();
}};
}};
java 8 and above
StreamSupport.stream(data.spliterator(), false).count();
I would go for it.next() for the simple reason that next() is guaranteed to be implemented, while remove() is an optional operation.
E next()
Returns the next element in the iteration.
void remove()
Removes from the underlying collection the last element returned by the iterator (optional operation).
As for me, these are just different methods. The first one leaves the object you're iterating on unchanged, while the seconds leaves it empty.
The question is what do you want to do.
The complexity of removing is based on implementation of your iterable object.
If you're using Collections - just obtain the size like was proposed by Kazekage Gaara - its usually the best approach performance wise.
Why don't you simply use the size() method on your Collection to get the number of elements?
Iterator is just meant to iterate,nothing else.
Instead of using loops and counting each element or using and third party library we can simply typecast the iterable in ArrayList and get its size.
((ArrayList) iterable).size();
Today I was happily coding away when I got to a piece of code I already used hundreds of times:
Iterating through a Collection (here ArrayList)
For some reason, I actually looked at the autocompletion options of Eclipse and it got me wondering:
What cases are the following loops better to use than the others?
The classic array index loop:
for (int i = 0; i < collection.length; i++) {
type array_element = collection.get(index);
}
The Iterator hasNext()/next():
for (Iterator iterator = collection.iterator(); iterator.hasNext();) {
type type = (type) iterator.next();
}
And my favorite because its so simple to write:
for (iterable_type iterable_element : collection) {
}
The first one is useful when you need the index of the element as well. This is basically equivalent to the other two variants for ArrayLists, but will be really slow if you use a LinkedList.
The second one is useful when you don't need the index of the element but might need to remove the elements as you iterate. But this has the disadvantage of being a little too verbose IMO.
The third version is my preferred choice as well. It is short and works for all cases where you do not need any indexes or the underlying iterator (i.e. you are only accessing elements, not removing them or modifying the Collection in any way - which is the most common case).
All of them have there own uses:
If you have an iterable and need to traverse unconditionally to all of them:
for (iterable_type iterable_element : collection)
If you have an iterable but need to conditionally traverse:
for (Iterator iterator = collection.iterator(); iterator.hasNext();)
If data-structure does not implement iterable:
for (int i = 0; i < collection.length; i++)
There is additionally collections’ stream() util with Java 8
collection.forEach((temp) -> {
System.out.println(temp);
});
or
collection.forEach(System.out::println);
More information about Java 8 stream and collections for wonderers link
None of them are "better" than the others. The third is, to me, more readable, but to someone who doesn't use foreaches it might look odd (they might prefer the first). All 3 are pretty clear to anyone who understands Java, so pick whichever makes you feel better about the code.
The first one is the most basic, so it's the most universal pattern (works for arrays, all iterables that I can think of). That's the only difference I can think of. In more complicated cases (e.g. you need to have access to the current index, or you need to filter the list), the first and second cases might make more sense, respectively. For the simple case (iterable object, no special requirements), the third seems the cleanest.
The first option is better performance wise (As ArrayList implement RandomAccess interface). As per the java doc, a List implementation should implement RandomAccess interface if, for typical instances of the class, this loop:
for (int i=0, n=list.size(); i < n; i++)
list.get(i);
runs faster than this loop:
for (Iterator i=list.iterator(); i.hasNext(); )
i.next();
I hope it helps.
First option would be slow for sequential access lists.
Here is an example
Query query = em.createQuery("from Student");
java.util.List list = query.getResultList();
for (int i = 0; i < list.size(); i++)
{
student = (Student) list.get(i);
System.out.println(student.id + " " + student.age + " " + student.name + " " + student.prenom);
}