Java ConcurrentModificationException when using list.remove() - java

I've got a method called removeSup which is supposed to remove an object Supplement from a list of supplements.
this is the code for the method:
private static void removeSup(Supplement supToRemove, List<Supplement> listToRemoveFrom) {
Iterator<Supplement> iterator = listToRemoveFrom.iterator();
while(iterator.hasNext()){
if(iterator.next().equals(supToRemove)){
iterator.remove();
}
}
}
there is a class called magazine which defines the list of supplements.
public class Magazine {
private List<Supplement> supList;
public List<Supplement> getSupList() {
return this.supList;
}
public void setSupList(List<Supplement> supList) {
this.supList = supList;
}
public Magazine(Double cost, String _name){
this.supList = new ArrayList<>();
this.weekCost = cost;
this.name = _name;
}
}
the class supplement has the following constructor
public Supplement(String _name, Double _price, String _magName ){
this.name=_name;
this.price=_price;
this.magName = _magName;
}
in the main class client there is a search that the user can do to remove a certain Supplement
private static void searchSup(){
System.out.println("Search for Supplement");
String search = scanner.nextLine();
for (Supplement sup : magazine.getSupList()) {
if (!sup.getSupName().equalsIgnoreCase(search)) {
//do something
}
else{
removeSup(sup,magazine.getSupList());
}
}
}
the main method in the client class is as follows:
private Magazine magazine;
public static void main(String[] args) {
magazine = new Magazine(3.0, "pop");
List<Supplement> startList = new ArrayList<>();
startList.add(new Supplement("Nat Geo", 3.0,"pop"));
startList.add(new Supplement("Discovery", 5.0,"pop"));
startList.add(new Supplement("Health", 6.3,"pop"));
startList.add(new Supplement("IT", 8.3,"pop"));
magazine.setSupList(startList);
searchSup();
}
When I run this program and type any of the added supplements, i get an error
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
at java.util.ArrayList$Itr.next(ArrayList.java:831)
at Client.searchSup(Client.java:131)
at Client.searchSup(Client.java:140)
at Client.main(Client.java:588)
is it the for loop i am using to search giving me an error? if so how would i go about fixing this?

You generally shouldn't modify a Collection while iterating over it. It's fine to modify elements, but you really shouldn't remove something from a Collection while iterating. See here: http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html. Also, the Javadoc for ConcurrentModificationException may be helpful.
You might try returning a new list with the Supplement removed:
private static List<Supplement> removeSup(Supplement supToRemove, List<Supplement> listToRemoveFrom) {
List<Supplement> filteredSupplements = new ArrayList<Supplement>();
for(Supplement supplement : listToRemoveFrom) {
if(!suppplement.equals(supToRemove)){
filteredSupplements.add(supplement);
}
}
return filteredSupplements;
}

It seams that the "magazine" is local var in the method of main, not accessible to searchSup.Fix it like
private void searchSup(Magazine magazine)
{
//...
}
and more details if you can provide, the codes in Line 131 and 140 will be helpful.

I figured out that the search i was doing was not working with what i wanted to do so i created a method which returns an integer of the Supplement in the list.
private static int indexOfSup(List<Supplement> supSearchList, String nameOfSup) {
for (Supplement sup : supSearchList) {
if (sup.getSupName().equalsIgnoreCase(nameOfSup)) {
return supSearchList.indexOf(sup);
}
}
return -1;
}
i then use this integer to remove from the list.
a simple List.Remove(index) worked fine
Thanks for all the replies.

Related

How to read MultiValue ArrayList in Java

I've defined a arrayList as following
List<List<RiskyPersons>> dataArray = new ArrayList<>();
Here is RiskyPersons Class
public class RiskyPersons {
private SA3Tenant sa3tenant;
private int NumberofPersonInCategory;
public RiskyPersons(){
}
public RiskyPersons(SA3Tenant sa3tenant, int NumberofPersonInCategory) {
this.sa3tenant = sa3tenant;
this.NumberofPersonInCategory = NumberofPersonInCategory;
}
}
Then I've successfully added data and saved in dataArray ArrayList.
Following output is showing the saved ArrayList using SOP(dataArray);
[[RiskyPersons{sa3tenant=Homeless.SA3Tenant#3a7cc6b0, NumberofPersonInCategory=99}]]
I want to read this dataArray ArrayList and display values separately. How do I access "NumberofPersonInCategory" value?
From Java-8 and above one can use stream:
dataArray.stream()
.flatMap(List::stream)
.map(RiskyPersons::NumberofPersonInCategory)
.forEach(System.out::println)
I hope this will help you !
public class RiskyPersons {
private SA3Tenant sa3tenant;
private int NumberofPersonInCategory;
public int getNumberofPersonInCategory() {
return NumberofPersonInCategory;
}
public RiskyPersons(){
}
public RiskyPersons(SA3Tenant sa3tenant, int NumberofPersonInCategory) {
this.sa3tenant = sa3tenant;
this.NumberofPersonInCategory = NumberofPersonInCategory;
}
}
List<Integer> values = dataArray.parallelStream().flatMap(Collection::stream).map(RiskyPersons::getNumberofPersonInCategory)
.collect(Collectors.toCollection(ArrayList::new));
You'll need to iterate it twice as
for (List<RiskyPersons> rp : dataArray) {
for (RiskyPersons o : rp) {
System.out.println(o.NumberofPersonInCategory); // unrelated : but its bad naming convention
}
}

Priority queue adding new object vs adding already created

Im writing a mapreduce program where in reduce function receives as input value an iterable of PageRankNode(with two fields) object and im adding it to priority queue. On iterating over each object and adding it to priority queue, the resultant priority queue only contains the last object i added.
However, it seems to work as expected when i create a new object of the same type and add to priority queue.
I was wondering why is this happening?
Below sample works. However instead of "topPages.add(new PageRankNode(pageNode.pageName,pageNode.pageRank))", i use "topPages.add(pageNode)" it doesnt work as expected.
The comparator implementation for the priority queue is also added below.
private Comparator<PageRankNode> comparator= new PageNodeComparator();
private PriorityQueue<PageRankNode> topPages= new PriorityQueue<PageRankNode>(100,comparator);
public void reduce(NullWritable key,Iterable<PageRankNode> pageNodes,Context context) throws IOException,InterruptedException{
for(PageRankNode pageNode:pageNodes){
//topPages.add(pageNode);
topPages.add(new PageRankNode(pageNode.pageName,pageNode.pageRank));
if(topPages.size()>100){
topPages.poll();
}
}
PageRankNode pageNode;
while(!topPages.isEmpty()){
pageNode=topPages.poll();
context.write(NullWritable.get(),new Text(pageNode.pageName+":"+pageNode.pageRank));
}
}
public class PageNodeComparator implements Comparator<PageRankNode>{
public int compare(PageRankNode x,PageRankNode y){
if(x.pageRank < y.pageRank){
return -1;
}
if(x.pageRank > y.pageRank){
return 1;
}
return 0;
}
}
I don't think you provided enough information to properly diagnose this. I see that you have InterruptedException in the reduce method suggesting that you might be running this on multiple threads -- if so that might be the underlying cause.
I wrote a small program that does the same and its output is as expected.
import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;
public class Main {
private static Comparator<PageRankNode> comparator = new PageNodeComparator();
private static PriorityQueue<PageRankNode> topPages = new PriorityQueue<PageRankNode>(100, comparator);
public static void main(String[] args) {
reduce(Arrays.asList(
new PageRankNode("A", 1000),
new PageRankNode("B", 1500),
new PageRankNode("C", 500),
new PageRankNode("D", 700),
new PageRankNode("E", 7000),
new PageRankNode("F", 60)
));
}
public static void reduce(Iterable<PageRankNode> pageNodes) {
for(PageRankNode pageNode : pageNodes) {
//topPages.add(pageNode);
topPages.add(new PageRankNode(pageNode.pageName, pageNode.pageRank));
if(topPages.size() > 100) {
topPages.poll();
}
}
PageRankNode pageNode;
while(!topPages.isEmpty()) {
pageNode = topPages.poll();
System.out.println(pageNode.pageName);
}
}
public static class PageRankNode {
private String pageName;
private int pageRank;
public PageRankNode(String pageName, int pageRank) {
this.pageName = pageName;
this.pageRank = pageRank;
}
}
public static class PageNodeComparator implements Comparator<PageRankNode> {
#Override
public int compare(PageRankNode x, PageRankNode y) {
if(x.pageRank < y.pageRank) {
return -1;
}
if(x.pageRank > y.pageRank) {
return 1;
}
return 0;
}
}
}
Output is:
F
C
D
A
B
E

Java NullPointerException In the constructor's class

I have made a Java class where I have defined a constructor and some methods but I get a NullPointer Exception, and I don't know how I could fix It.
public class Job {
String idJob;
int time;
int timeRun;
Job j1;
List<Job> startBeforeStart;
List<Job> restricted;
Job(String idJob, int time){
this.idJob=idJob;
this.time=time;
}
public boolean isRestricted() {
return restricted.size() != 0;
}
public void startsBeforeStartOf(Job job){
startBeforeStart.add(job);
job.restricted.add(this);
}
public void startsAfterStartOf(Job job){
job.startsBeforeStartOf(this);
}
public void checkRestrictions(){
if (!isRestricted()){
System.out.println("+\n");
}
else{
Iterator<Job> itR = restricted.iterator();
while(itR.hasNext()){
Job j1 = itR.next();
if(time>timeRun){
System.out.println("-\n");
time--;
}
else {
restricted.remove(j1);
}
}
}
}
#Override
public boolean equals(Object obj) {
return obj instanceof Job && ((Job) obj).idJob.equals(idJob);
}
public void run() {
timeRun++;
}
}
PS
Looking in a forum a user says that to fix the error I should make an ArrayList inside the constructor (without modify the received parameters that should remain String id and int time), but I haven't understand what He mean.
You are not creating an instrance of List<Job> for both the lists startBeforeStart and restricted - you only declare a variable, which is assigned with a null pointer.
Thus, whenever you try to access this List [for example: return restricted.size() != 0;] - you are trying to dereference a null pointer - which causes your NPE.
You should create an instance of the List - using the new operator [probably in the constructor].
Have a look at ArrayList and LinkedList and chose which is better for you.
For example, if you use to use an ArrayList for both, your c'tor should be something like:
Job(String idJob, int time){
this.idJob=idJob;
this.time=time;
startBeforeStart = new ArrayList<Job>();
restricted= new ArrayList<Job>();
}

Java constructor varargs conflict when passing string

I have an issue with one of my class. I'm using a "varargs" constructor for unknown number of parameter.
public Groupe(String...nom){
for(String item:nom){
this.nom.add(item.toLowerCase());
}
}
public Groupe(String nom){
String[] list =nom.split(",");
for(String s : list){
this.nom.add(s.toLowerCase());
}
}
The first constructor is called...that's fine, but there is a conflict when passing only ONE parameter with the second contructor. I would like to use the second constructor when passing only one string, and the first if 2 and more parameters.
I'd want to handle this
new Groupe("Foo,Bar");
This is where I call it. I suspect the "error" comes from there
public void reserver(String...nom){
Groupe gr = new Groupe(nom);
passager.add(gr);
}
I don't pass a String, but a Varargs (tab?)...
It should be fine, with the caveat that null can be converted to either String[] or String:
public class Test {
public Test(String single) {
System.out.println("Single");
}
public Test(String... multiple) {
System.out.println("Multiple");
}
public static void main(String[] args) {
new Test("Foo"); // Single
new Test("Foo", "Bar"); // Multiple
new Test(); // Effectively multiple
// new Test(null); // Doesn't compile - ambiguous
new Test((String) null); // Single
}
}
EDIT: Now that you've shown us the calling code, that's definitely the problem:
public void reserver(String...nom){
Groupe gr = new Groupe(nom);
passager.add(gr);
}
Here, the type of nom is String[] - so it will always call the first constructor. You've got an array of strings there - under what circumstances do you want to call the second constructor?
To be honest, given that the two constructors act significantly differently, I would actually make both constructors private, and provide static methods:
public static Groupe fromStringArray(String... nom)
public static Groupe fromCommaSeparatedString(String nom)
Then it will be absolutely clear what you're expecting in each case.
Maybe this can be a solution:
public Groupe(String...nom){
if (nom.length == 1) {
add(nom[0].split(","));
} else {
add(nom);
}
}
private void add(String[] list) {
for(String s : list){
this.nom.add(s.toLowerCase());
}
}
The varargs part can be empty. So you can get what you want with
public Groupe(String nom){
String[] list = nom.split(",");
for(String s : list){
this.nom.add(s.toLowerCase());
}
public Groupe(String nom1, String nom2, String...nom){
this.nom.add(nom1);
this.nom.add(nom2);
for(String item:nom)
this.nom.add(item.toLowerCase());
}
You could also, of course, use one ctor with an if statement on the length of the input array, splitting out cases 0 (not handled with the code above), 1, and > 1.
public class OverloadVarArgs {
public static void main(String... args){
OverloadVarArgs a = new OverloadVarArgs("One Argument");
OverloadVarArgs b = new OverloadVarArgs("Two", "Arguments");
OverloadVarArgs c = new OverloadVarArgs("One, Argument");
}
public OverloadVarArgs(String a){
System.out.println("Constructor 1");
}
public OverloadVarArgs(String... a){
System.out.println("Constructor 2");
}
}
Output:
Constructor 1
Constructor 2
Constructor 1

How do I get the method name from within that method?

I am trying to create a function that returns the method name from within that method:
public static String getMethodName(final int depth)
{
final StackTraceElement[] ste = Thread.currentThread().getStackTrace();
return ste[ste.length - 1 - depth].getMethodName();
}
However, when I call this method from Activity.onCreate(), it returns "main" instead of "onCreate".
How do I get the actual method name from within that method?
return ste[1+depth].getMethodName();
If you change return statement as above, you would get immediate calling method name , of cource depth shoould be zero..
Despite the fact initiating an Exception is more expensive way, I would do it anyway.
Log.d("CurrentMethod", new Exception().getStackTrace()[0].getMethodName());
Works if called in onCreate.
A singleton to manage logs:
public class ActiveLog {
public static final String TAG = "TRACE LOG";
private static ActiveLog instance;
private static boolean actif;
public static ActiveLog getInstance() {
if (null == instance)
instance = new ActiveLog();
return instance;
}
private ActiveLog() {
ActiveLog.setActif(true);
}
public void log() {
if(isActif())
Log.d(TAG, "" + (new Exception().getStackTrace()[1].getClassName())
+ ": "
+ (new Exception().getStackTrace()[1].getMethodName()));
}
public static boolean isActif() {
return actif;
}
public static void setActif(boolean actif) {
ActiveLog.actif = actif;
}}
An example of use:
public class MyTest {
public void test() {
ActiveLog.getInstance().log();
}
}
The result:
09-05 14:37:09.822: D/TRACE LOG(XXXX): com.TestProject.MyTest: test
I think your problem maybe you are accessing the stack upside down. In the returned value element 0 is the most recent call (which would be getStackTrace()). I think what you are intending to do is:
public static String getMethodName(final int depth) {
final StackTraceElement[] ste = Thread.currentThread().getStackTrace();
return ste[1 + depth].getMethodName();
}
This will access the most recent call in the stack (outside of the call to getStackTrace()). For example if you have a method:
public void foo() {
System.out.println(getMethodName(0));
}
This will print "foo" with the above implementation of the function. Of course you may also want to add some bounds checking to the function since it could easily go outside the array.

Categories

Resources