Java: Adding Future<obj> to a list - java

Now that I have a handle on retrieving objects in parallel, how can I add those objects to a list?
I have a list of Future<Site> objects that I'm attempting to add to an ArrayList of Site objects. Here's my for loop. I can add a print statement in the loop and it reveals that the list of Future<Site> objects is indeed populated, however adding to the existing list (last line) does not work.
List<Future<Site>> futures=threadmaker.invokeAll(active_sites.stream().map(site -> new TAG_SCANNER(site, loggr)).collect(Collectors.toList()));
//Now fetch all the results
for (Future<Site> result : futures) {
//SOUND THE ALARMS (adding to existing list)
alarm_sites.add(result.get());
}
EDIT:
I thought Future's get method was blocking, in that the code would not progress until it returns a result. Does my mistake lie in trying to add to an already existing list?

For some reason, creating the list after my invokeall command solved my issues. I'm not sure why the pre-existing list didn't work but I'm marking the issue as solved for now, and I'll look into this later to see what may have happened.

Related

JavaFX deleting from TableView

I'm working on a JavaFX app and am using a TableView as part of the GUI as follows:
public TableView<Meal> meals;
And to it I assigned a button that is supposed to delete elements which are selected. To do that I used a function that kept giving me a NoSuchElementException
public void deleteMealButtonClicked()
{
ObservableList<Meal> mealsSelected = meals.getSelectionModel().getSelectedItems();
ObservableList<Meal> allMeals = meals.getItems();
mealsSelected.forEach(allMeals::remove);
}
I debugged my way into finding out the problem was in the last line of the method.
After researching for quite a while, I happened to stumble across a piece of code that solved the problem. Here is the method with the code that works:
public void deleteMealButtonClicked()
{
ObservableList<Meal> mealsSelected = meals.getSelectionModel().getSelectedItems();
ObservableList<Meal> allMeals = meals.getItems();
if (mealsSelected != null) {
ArrayList<Meal> rows = new ArrayList<>(mealsSelected);
rows.forEach(row -> meals.getItems().remove(row));
}
}
My question is, why does the second method work and not the first? Aren't they fundamentally the same thing, other than adding the selected rows to an ArrayList on the second method?
Thank you in advance.
The selection model of the TableView must observe the ObservableList in the items property in order to properly reflect the state of the table. In other words, if an element is removed from items it must also be removed from the selection model's selected items.
This results in you indirectly modifying the selectedMeals list while iterating it to remove the contained elements from the meals list. In a lot of the java.util collections the iterators are fail-fast and this would result in a ConcurrentModificationException; I guess the selection model is not fail-fast and so you simply see indeterminate behavior (in the form of a NullPointerException).
The second option works because you first make a copy of selectedMeals and then iterate the copy.
You ask in a comment for a way to not create a copy; unfortunately, I can't think of one. You could simplify your code a bit by using the removeAll, however.
ObservableList<Meal> selected = ...;
// List.copyOf is a Java 10 method (and doesn't accept null elements)
table.getItems().removeAll(List.copyOf(selected));
// Pre Java 10 you can use toArray since ObservableList overloads removeAll
// with a version that takes a varargs parameter
table.getItems().removeAll(selected.toArray(new Meal[0]));
// or use the copy constructor of many collection classes
table.getItems().removeAll(new ArrayList<>(selected));
// In Java 11, toArray can be replaced with
table.getItems().removeAll(selected.toArray(Meal[]::new));

Java: ConcurrentModificationException, 3 threads, different lists, same objects

I have the following situation:
In a main function if some controller class I retrieve 10 product objects from my DB. These are hold in an ArrayList object.
Afterwards I create three classes which extend Runnable and I give to each class the product-ArrayList into the constructor.
In each of the constructors is a new local ArrayList created and the objects in the product-ArrayList are added:
this.products = new ArrayList();
products.addAll(productListParam);
Afterwards I start each of three threads and they iterate over their local products-lists and also modify it.
I'm getting a ConcurrentModificationException while iterating over the local product ArrayList..
Why is this happening? I was assuming that if I create a complete new list in each thread I can modify this locally as much as I want without caring about the other threads - am I right? Or does the removal of some object from a local list affect the pbjects somehow so that the other threads throw the Concurrent Modification Exception?
Actually the stacktrace looks like:
java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:819)
at java.util.ArrayList$Itr.next(ArrayList.java:791)
at com.x.y.class.method(Classname.java:326)
and Classname.java at 326 looks like:
325:List<Product> productsToDelete = new ArrayList();
326:for(Product p: products){
...
if(xy){
productsToDelete.add(p);
}
}
products.removeAll(productsToRemove);
Maybe someone has a hint for me what I'm doing wrong?
Edit: Inside the loop the product object p is just used for reading. Additionally there are no modifications done to the products-ArrayList. They are only added to a second "toBeRemoved" list to remove them later after the for-loop finished.. I edited the code above.
I think I'm mostly interested in the question if I can create several list-objects, add the same product-objects to each of them via the addAll()-method and then can to anything with it in each thread without caring about the other threads?!
You can't modify the Collection inside an enhanced for loop that iterates over its elements. Not even if you only have a single thread.
You didn't include the code inside the enhanced for loop, but if what you need to do inside it is remove elements from the list, you can use an explicit iterator.
Iterator<Product> iter = products.iterator();
While (iter.hasNext() {
Product p = iter.next();
....
if (some condition)
iter.remove();
....
}
Sorry guys to bother you, I did a bad beginner fault!
I was setting the mentioned product-ArrayList manually later from some other code basis and did overwrite the new ArrayList.. so all threads again used only one ArrayList and the ConcurrentModificationException occured.
As you see within this example, always double check your code :)
Sorry for bothering you..

How to copy a java.util.List into another java.util.List

I have a List<SomeBean> that is populated from a Web Service. I want to copy/clone the contents of that list into an empty list of the same type. A Google search for copying a list suggested me to use Collections.copy() method. In all the examples I saw, the destination list was supposed to contain the exact number of items for the copying to take place.
As the list I am using is populated through a web service and it contains hundreds of objects, I cannot use the above technique. Or I am using it wrong??!! Anyways, to make it work, I tried to do something like this, but I still got an IndexOutOfBoundsException.
List<SomeBean> wsList = app.allInOne(template);
List<SomeBean> wsListCopy=new ArrayList<SomeBean>(wsList.size());
Collections.copy(wsListCopy,wsList);
System.out.println(wsListCopy.size());
I tried to use the wsListCopy=wsList.subList(0, wsList.size()) but I got a ConcurrentAccessException later in the code. Hit and trial. :)
Anyways, my question is simple, how can I copy the entire content of my list into another List? Not through iteration, of course.
Just use this:
List<SomeBean> newList = new ArrayList<SomeBean>(otherList);
Note: still not thread safe, if you modify otherList from another thread, then you may want to make that otherList (and even newList) a CopyOnWriteArrayList, for instance -- or use a lock primitive, such as ReentrantReadWriteLock to serialize read/write access to whatever lists are concurrently accessed.
This is a really nice Java 8 way to do it:
List<String> list2 = list1.stream().collect(Collectors.toList());
Of course the advantage here is that you can filter and skip to only copy of part of the list.
e.g.
//don't copy the first element
List<String> list2 = list1.stream().skip(1).collect(Collectors.toList());
originalArrayList.addAll(copyArrayofList);
Please keep on mind whenever using the addAll() method for copy, the contents of both the array lists (originalArrayList and copyArrayofList) references to the same objects will be added to the list so if you modify any one of them then copyArrayofList also will also reflect the same change.
If you don't want side effect then you need to copy each of element from the originalArrayList to the copyArrayofList, like using a for or while loop. for deep copy you can use below code snippet.
but one more thing you need to do, implement the Cloneable interface and override the clone() method for SomeBean class.
public static List<SomeBean> cloneList(List<SomeBean> originalArrayList) {
List<SomeBean> copyArrayofList = new ArrayList<SomeBean>(list.size());
for (SomeBean item : list) copyArrayofList.add(item.clone());
return copyArrayofList;
}
I tried to do something like this, but I still got an IndexOutOfBoundsException.
I got a ConcurrentAccessException
This means you are modifying the list while you are trying to copy it, most likely in another thread. To fix this you have to either
use a collection which is designed for concurrent access.
lock the collection appropriately so you can iterate over it (or allow you to call a method which does this for you)
find a away to avoid needing to copy the original list.
Starting from Java 10:
List<E> oldList = List.of();
List<E> newList = List.copyOf(oldList);
List.copyOf() returns an unmodifiable List containing the elements of the given Collection.
The given Collection must not be null, and it must not contain any null elements.
Also, if you want to create a deep copy of a List, you can find many good answers here.
There is another method with Java 8 in a null-safe way.
List<SomeBean> wsListCopy = Optional.ofNullable(wsList)
.map(Collection::stream)
.orElseGet(Stream::empty)
.collect(Collectors.toList());
If you want to skip one element.
List<SomeBean> wsListCopy = Optional.ofNullable(wsList)
.map(Collection::stream)
.orElseGet(Stream::empty)
.skip(1)
.collect(Collectors.toList());
With Java 9+, the stream method of Optional can be used
Optional.ofNullable(wsList)
.stream()
.flatMap(Collection::stream)
.collect(Collectors.toList())
I tried something similar and was able to reproduce the problem (IndexOutOfBoundsException). Below are my findings:
1) The implementation of the Collections.copy(destList, sourceList) first checks the size of the destination list by calling the size() method. Since the call to the size() method will always return the number of elements in the list (0 in this case), the constructor ArrayList(capacity) ensures only the initial capacity of the backing array and this does not have any relation to the size of the list. Hence we always get IndexOutOfBoundsException.
2) A relatively simple way is to use the constructor that takes a collection as its argument:
List<SomeBean> wsListCopy=new ArrayList<SomeBean>(wsList);
I was having the same problem ConcurrentAccessException and mysolution was to:
List<SomeBean> tempList = new ArrayList<>();
for (CartItem item : prodList) {
tempList.add(item);
}
prodList.clear();
prodList = new ArrayList<>(tempList);
So it works only one operation at the time and avoids the Exeption...
You can use addAll().
eg : wsListCopy.addAll(wsList);
re: indexOutOfBoundsException, your sublist args are the problem; you need to end the sublist at size-1. Being zero-based, the last element of a list is always size-1, there is no element in the size position, hence the error.
I can't see any correct answer. If you want a deep copy you have to iterate and copy object manually (you could use a copy constructor).
You should use the addAll method. It appends all of the elements in the specified collection to the end of the copy list. It will be a copy of your list.
List<String> myList = new ArrayList<>();
myList.add("a");
myList.add("b");
List<String> copyList = new ArrayList<>();
copyList.addAll(myList);
just in case you use Lombok:
mark SomeBean with the following annotation:
#Builder(toBuilder = true, builderMethodName = "")
and Lombok will perform a shallow copy of objects for you using copy constructor:
inputList.stream()
.map(x -> x.toBuilder().build())
.collect(Collectors.toList());
subList function is a trick, the returned object is still in the original list.
so if you do any operation in subList, it will cause the concurrent exception in your code, no matter it is single thread or multi thread.

Insert all records in an Iterable<Object> to a List in java

I have an Iterable<MyRecord> records . I iterate over the records like below and add it to a LinkedList as shown below.
for (MyRecord record: records){
sortedList.addLast(record);
}
My iterable has 3 records, all with different values. But in the end although sortedList contains 3 records, ALL THREE ARE THE SAME!!!. How come?
When I printed out the memory location, it's the same for all 3. What am I doing wrong?
Actually your comment reveals the missing link to why this is going wrong. You're using this in a Hadoop mapper or reducer. The trick with Hadoop is that it reuses the objects you're getting in, so that it goes easy on the garbage collector. What you thus have to do is make a copy of each of the objects in your source iterable (the MyRecords), and add those to your LinkedList.
If the sortedList contains the same records, which is the last elements in original records, it's possible that the iterator re-use the tmp reference. You need to check the implementation of the 'records'.
Your question is clear and so is the code (also after reading the comments); this may not help, but maybe you can just do, before your add, a contains check like: if (sortedList.contains(record)) sortedList.add...
I admit this might not really help (also i don't know if contains checks for element memory location under the hood, as i guess it might only check for element presence in the list using equals).
When you are adding items into the list put check :
if(sortedList.contains(record))
{
System.out.println("Record is already available "+record);
}
else
{
sortedList.addLast(record);
}
You will get to know whether the problem is due to same records or because of something else.

Filtering List without using iterator

I need to filter a List of size 1000 or more and get a sublist out of it.
I dont want to use an iterator.
1) At present I am iterating the List and comparing it using Java. This is time consuming task. I need to increase the performance of my code.
2) I also tried to use Google Collections(Guava), but I think it will also iterate in background.
Predicate<String> validList = new Predicate<String>(){
public boolean apply(String aid){
return aid.contains("1_15_12");
}
};
Collection<String> finalList =com.google.common.collect.Collections2.filter(Collection,validList);
Can anyone suggest me how can I get sublist faster without iterating or if iterator is used I will get result comparatively faster.
Consider what happens if you call size() on your sublist. That has to check every element, as every element may change the result.
If you have a very specialized way of using your list which means you don't touch every element in it, don't use random access, etc, perhaps you don't want the List interface at all. If you could tell us more about what you're doing, that would really help.
List is an ordered collection of objects. So You must to iterate it in order to filter.
I enrich my comment:
I think iterator is inevitable during filtering, as each element has to be checked.
Regarding to Collections2.filter, it's different from simple filter: the returned Collection is still "Predicated". That means IllegalArgumentException will be thrown if unsatisfied element is added to the Collection.
If the performance is really your concern, most probably the predicate is pretty slow. What you can do is to Lists.partition your list, filter in parallel (you have to write this) and then concatenate the results.
There might be better ways to solve your problem, but we would need more information about the predicate and the data in the List.

Categories

Resources