I've been coding a program and I've faced several issues that I was able to address properly. However, my program is throwing a ConcurrentModificationException and I'm not sure what I can do.
I'm coding with NetBeans 8.0.2 to create a Java desktop application (as required by my professor).
The aim of the program is to manage a hotel. So, it has some parts like "Customers", "Staff" and "Booking" (the one giving me problems).
On each part, I have a JTable that uses a DefaultTableModel. In every part, I'm using files on the hard drive to make the changes persistent. I've coded new customer/staff classes. Now, I'm trying to code booking and unbooking methods. Everything has gone pretty well until I got to the "unbooking" part.
After the table and model I have an ArrayList. In this particular part, I have three of them:
one for the whole table
one containing only the free rooms
one only with the already booked rooms.
The booking part was fine, I'm able to modify the table, the file and the ArrayList without any errors, and my program actually does what it should. But I'm unable to get the unbooking part to work. It should basically be the reverse of booking.
I will post a small part of my code, but if you need to know anything else or need some more parts of my code I would gladly share it.
My code:
public class GestionInstalaciones extends javax.swing.JFrame {
private final String ruta = System.getProperties().getProperty("user.dir");
private final File archivo = new File (ruta+"\\Instalaciones.txt");
private final DefaultTableModel modelo = new DefaultTableModel();
private final ArrayList contenidoInstalaciones;
private final ArrayList contenidoInstalacionesOcupadas;
private final ArrayList contenidoInstalacionesLibres;
public GestionInstalaciones() {
initComponents ();
contenidoInstalaciones = new ArrayList();
contenidoInstalacionesOcupadas = new ArrayList();
contenidoInstalacionesLibres = new ArrayList();
//Añadimos las columnas a la tabla.
modelo.addColumn ("Tipo");
modelo.addColumn ("Nombre Instalacion");
modelo.addColumn ("NIF del Ocupante");
cargarTabla();
}
private void cargarTabla(){
this.contenidoInstalaciones.clear();
FileReader fr = null;
BufferedReader br;
String tipo;
String nombre;
String NIFocupante;
String[] partes;
String linea;
try{
fr = new FileReader(archivo);
br = new BufferedReader(fr);
while ((linea=br.readLine())!=null) {
//Adding info to general ArrayList
this.contenidoInstalaciones.add(linea);
//Splitting line into 3 components.
partes = linea.split(",",3);
tipo = partes[0];
nombre = partes[1];
NIFocupante = partes[2];
//Skipping header.
if ( tipo.equals( "Tipo" )) { continue; }
//Añadimos la fila al modelo.
modelo.addRow(partes);
}
TablaInstalaciones.setModel(modelo);
}
//Capturamos excepciones y cerramos fichero.
catch(IOException e) {}
finally { try { if ( null != fr ) { fr.close(); } } catch (IOException e2){ } }
}//end cargarTabla()
private void botonLiberarInstalacionActionPerformed(java.awt.event.ActionEvent evt) {
Object linea;
int contador=0;
String aux;
String tiposATrabajar = "";
String[] tiposAInsertar;
Iterator instalacionesOcupadas;
//Cleaning of already booked ArrayList.
//this.contenidoInstalacionesOcupadas.clear();
instalacionesOcupadas = contenidoInstalacionesOcupadas.iterator();
this.comboTipoALiberar.removeAllItems();
this.comboTipoALiberar.addItem("Seleccione");
//Reading the general Table.
for (int z = 0; z < TablaInstalaciones.getRowCount() ; z++) {
//The booking parameter is on the 3rd place.
if(!TablaInstalaciones.getValueAt(z,2).equals("")){
//Putting the line into the ArrayList for booked rooms..
linea = TablaInstalaciones.getValueAt(z,0) + "," + TablaInstalaciones.getValueAt(z,1) + "," + TablaInstalaciones.getValueAt(z,2);
this.contenidoInstalacionesOcupadas.add(linea);
contador++;
}
}
**//Reading the booked ArrayList to put the right values on the combobox related.
//===> THIS LINE IS GIVING THE ERROR !!!
while(instalacionesOcupadas.hasNext()) {**
aux = instalacionesOcupadas.next().toString().split(",",3)[0];
//Checking to add only 1 kind of each room type.
if(!tiposATrabajar.contains(aux)); {
if (tiposATrabajar.equals("")) { tiposATrabajar=aux; }
else { tiposATrabajar = tiposATrabajar + "," + aux; }
}
}
//
tiposAInsertar = tiposATrabajar.split(",");
//Adding the type into the combobox.
for (String elemento: tiposAInsertar){ this.comboTipoALiberar.addItem(elemento.replace(",","")); }
}
If the contents of the Collection you are iterating through have been changed since the last time you have used an iterator, you will get an exception if you try to use or reuse it. Create a new one - as a general rule, don't reuse an iterator.
You are:
Creating an iterator
Modifying the list
Using the iterator after the list has been modified ← Error!
You should modify the list before creating the iterator.
Also, you should try to minimize the scope of local variables.
As opposed to:
Iterator<String> someIterator = strings.iterator();
while (someIterator.hasNext()) {
doSomething();
}
You should probably do:
for (Iterator<String> iter = strings.iterator(); iter.hasNext();) {
doSomething();
}
Of course, if you (as you said) do not need to modify the list, use a for-each loop:
for (String s : strings) {
doSomething();
}
Some unrelated points:
Why are you writing things like extends java.awt.JFrame? Import it and use JFrame instead.
Declare and initialize your variables when you need them. If you had initialized the Iterator only in front of your for loop you wouldn't have had this problem.
Use generics! Non-generic Collections will only err at run-time, while generic ones will give compile errors instead.
ConcurrentModificationExceptions happen when you make changes to a chain of elements (list) while you're actively looping through said chain.
I've encountered it often enough and always solve it by reverse looping through the list, that way you loop backwards and you can change or delete elements if you want without messing up the chain (list) you're looping over.
I'd provide you with code, but I find it very hard to read yours, so this'll have to do for now.
Hope this helps and good luck!
Related
Im making a small school project, keep in mind i'm a beginner. Im gonna make a small system that adds member numbers of members at a gym to an array. I need to make sure that people cant get the same member number, in other words make sure the same value doesnt appear on serveral index spots.
So far my method looks like this:
public void members(int mNr){
if(arraySize < memberNr.length){
throw new IllegalArgumentException("There are no more spots available");
}
if(memberNr.equals(mNr)){
throw new IllegalArgumentException("The member is already in the system");
}
else{
memberNr[count++] = mNr;
}
}
While having a contructor and some attributes like this:
int[] memberNr;
int arraySize;
int count;
public TrainingList(int arraySize){
this.arraySize = arraySize;
this.memberNr = new int[arraySize];
}
As you can see i tried using equals, which doesnt seem to work.. But honestly i have no idea how to make each value unique
I hope some of you can help me out
Thanks alot
You can use set in java
Set is an interface which extends Collection. It is an unordered collection of objects in which duplicate values cannot be stored.
mport java.util.*;
public class Set_example
{
public static void main(String[] args)
{
// Set deonstration using HashSet
Set<String> hash_Set = new HashSet<String>();
hash_Set.add("a");
hash_Set.add("b");
hash_Set.add("a");
hash_Set.add("c");
hash_Set.add("d");
System.out.print("Set output without the duplicates");
System.out.println(hash_Set);
// Set deonstration using TreeSet
System.out.print("Sorted Set after passing into TreeSet");
Set<String> tree_Set = new TreeSet<String>(hash_Set);
System.out.println(tree_Set);
}
}
public void members(int mNr){
if(arraySize < memberNr.length){
throw new IllegalArgumentException("There are no more spots available");
}
//You need to loop through your array and throw exception if the incoming value mNr already present
for(int i=0; i<memberNr.length; i++){
if(memberNr[i] == mNr){
throw new IllegalArgumentException("The member is already in the system");
}
}
//Otherwise just add it
memberNr[count++] = mNr;
}
I hope the comments added inline explains the code. Let me know how this goes.
Hey you can’t directly comparing arrays (collection of values with one integer value)
First iterate the element in membernr and check with the integer value
For clarification - I DO NOT want to remove anything from the ArrayList. Therefore 90% of all the answers I have found don't actually apply. I can't find anything here, or elsewhere that helps me out much!
I'm writing a Java Application to play Hangman where the opponent (computer) is essentially cheating, in the sense where it does not 'choose' a word, it has a group of words and decides if the player's guess is correct, or incorrect, depending on which of those leaves the more difficult group of words to guess from.
In a nutshell, my problem is this:
I have an ArrayList, masterList, where I have a set of words, a dictionary if you will, and various methods iterate through this to perform various tasks. My code is single threaded and one of these methods is throwing a ConcurrentModificationException when trying to access the next object in the ArrayList in the second iteration. However, I cannot find anything that actually changes the ArrayList during the iteration.
import java.io.*;
import java.util.*;
public class Main {
private ArrayList<String> masterList;
private ArrayList<String> contains;
private ArrayList<String> doesNotContain;
private HashMap<Integer, ArrayList<String>> wordLengthList;
private HashMap<Integer, ArrayList<String>> difficultyList;
private int guesses = 10;
private Scanner sc;
private FileReader fr;
private BufferedReader br;
private String guessString;
private char guessChar;
private static final String DICTIONARY = "smalldictionary.txt";
private String wordLengthString;
private int wordLengthInt = 0;
public Main(){
masterList = new ArrayList<String>();
contains = new ArrayList<String>();
doesNotContain= new ArrayList<String>();
wordLengthList = new HashMap<Integer, ArrayList<String>>();
difficultyList = new HashMap<Integer, ArrayList<String>>();
sc = new Scanner(System.in);
importTestDictionary(); //does not use masterList
br = new BufferedReader(fr);
importWords(); //Adds to masterList. Both readers closed when finished.
catalogLengths(); //Iterates through masterList - does not change it.
do{
setWordLength(); //does not use masterList
}while(!(validateLengthInput(wordLengthString))); //validation will change the set of masterList if valid.
//Main loop of game:
while(guesses > 0){
do{
getUserInput();
}while(!(validateInput(guessString)));
splitFamilies();//will change set of masterList when larger group is found. Changes occur AFTER where Exception is thrown
printDifficultyList();
}
}
private void importWords(){ //Adds to masterList. Both readers closed when finished.
try{
while(br.readLine() != null){
line = br.readLine();
masterList.add(line);
}
br.close();
fr.close();
}catch(IOException e){
System.err.println("An unexpected IO exception occurred. Check permissions of file!");
}
}
private boolean validateLengthInput(String length){ //validation will change the set of masterList if valid.
try{
wordLengthInt = Integer.parseInt(length);
if(!(wordLengthList.containsKey(wordLengthInt))){
System.out.println("There are no words in the dictionary with this length.\n");
return false;
}
}catch(NumberFormatException e){
System.out.println("You must enter a number.\n");
return false;
}
masterList = wordLengthList.get(wordLengthInt);
return true;
}
private void splitFamilies(){ //will change set of masterList when larger group is found. Changes occur AFTER where Exception is thrown
Iterator<String> it = masterList.iterator();
int tempCount = 0;
while(it.hasNext()){
tempCount++;
System.out.println("tempCount: " + tempCount);
String i = it.next(); //Still throwing ConcurrentModification Exception
if(i.contains(guessString)){
contains.add(i);
}else{
doesNotContain.add(i);
}
}
if(contains.size() > doesNotContain.size()){
masterList = contains;
correctGuess(); //does not use masterList
profileWords();
}
else if(doesNotContain.size() > contains.size()){
masterList = doesNotContain;
incorrectGuess(); //does not use masterList
}
else{
masterList = doesNotContain;
incorrectGuess(); //does not use masterList
}
}
private void printMasterList(){ //iterates through masterList - does not change it.
for(String i : masterList){
System.out.println(i);
}
}
private void catalogLengths(){ //Iterates through masterList - does not change it.
for(String i : masterList){
if(i.length() != 0){
if(!(wordLengthList.containsKey(i.length()))){
wordLengthList.put(i.length(), new ArrayList<String>());
}
wordLengthList.get(i.length()).add(i);
}
}
}
}
The line the exception is thrown from is marked above in the code. Any method using masterList is also marked, any method included that does not use it, there is no comment against.
I did read some answers and some of them suggested using Iterator to avoid the exception. This is implemented above in splitFamilies(). The original code was as below:
private void splitFamilies(){ //will change set of masterList when larger group is found. Changes occur AFTER where Exception is thrown
int tempCount = 0;
for(String i : masterList){ //This line throws ConcurrentModificationException
tempCount++;
System.out.println("tempCount: " + tempCount);
if(i.contains(guessString)){
contains.add(i);
}else{
doesNotContain.add(i);
}
}
....continue as before
tempCount is always 2 when the exception is thrown.
Maybe I'm missing something really simple, but I've tried tracing this, and cannot find out why I'm getting this exception!
I've tried to remove everything irrelevant from the code, but if anyone really wants to view the full thing, I guess I could dump all my code in the question!
The issue comes from the fact that masterList is a reference to either contains or doesNotContain after a first split. When you iterate on masterList, you actually also iterate at the same time on that other list.
So, then you add items to the lists:
if(i.contains(guessString)){
contains.add(i);
}else{
doesNotContain.add(i);
}
Here you do not only add items to contains or doesNotContain, but also potentially to masterList, which leads to the conccurentException.
To solve your issue, just make a copy of your lists, instead of : masterList = contains;
do a copy with: masterList = new ArrayList<>(contains);
And the same for doesNotContains.
Another solution which comes to mind is to reset the two lists contains and doesNotContains for each split. Since you only use them in this method, and nowhere else, remove these two lists from your Class, and defines them as private variables inside splitFamilies
I'm currently learning linked list and I have discovered the basics of coding it and I fully understand them. However, I have a certain amount of nodes preset, so the user would not be able to add more. How would one implement a while loop to keep cycling through and asking the user if they want to add another piece of data.
Here is the code that I already have so far:
public class List {
public int x;
public List ptr = null;
}
Above is the object class for List. List contains a data type of x and a pointer.
import javax.swing.JOptionPane;
public class Main {
public static void main(String[] args) {
List front = new List();
front.x = Integer.parseInt(JOptionPane.showInputDialog("Enter a value"));
List l1 = new List();
l1.x = Integer.parseInt(JOptionPane.showInputDialog("Enter a value"));
List l2 = new List();
l2.x = Integer.parseInt(JOptionPane.showInputDialog("Enter a value"));
front.ptr = l1;
l1.ptr = l2;
printNodes(front);
}
public static void printNodes(List p) {
while (p != null) {
System.out.print(p.x + " ");
p = p.ptr;
}
}
}
As you can see, I have 3 Nodes created, but you cannot add anymore. I'd like to have something along the lines of:
boolean goAgain = true;
while (goAgain) {
//create a new node
String again = JOptionPane.showInputDialog("Add another node?");
if (!again.equalsIgnoreCase("yes")) {
goAgain = false;
}
}
Thank you!
P.S - I am a sophomore in high school, please use vocabulary that I will be able to understand. I wouldn't say I'm a java noob, but I'm no expert either.
Well I'd clean up your while loop to include everything in one statement. But that's just because I'm lazy. ;)
while (!JOptionPane.showInputDialog("Add another node?").equalsIgnoreCase("yes"))
{
//make a new node
}
As for the code to make a new node I would suggest implementing your List class from the List interface that Java has. You can read about it here. If you're just starting out in Java though it might be a little hard to understand. As a comment on your existing code here:
List front = new List();
front.x = Integer.parseInt(JOptionPane.showInputDialog("Enter a value"));
You're not exactly making a new node per-say, you're just creating new instances of your List class. In this case the object is labeled 'front' My suggestion is to read up more on how a List is meant to function. Here is a good example.
I have a program in java that I wrote to return a table of values. Later on as the functions of this program grew I found that I would like to access a variable within the method that isn't returned but I am not sure the best way to go about it. I know that you cannot return more than one value but how would I go about accessing this variable without a major overhaul?
here is a simplified version of my code:
public class Reader {
public String[][] fluidigmReader(String cllmp) throws IOException {
//read in a file
while ((inpt = br.readLine()) != null) {
if (!inpt.equals("Calls")) {
continue;
}
break;
}
br.readLine();
inpt = br.readLine();
//set up parse parse parameters and parse
prse = inpt.split(dlmcma, -1);
while ((inpt = br.readLine()) != null) {
buffed.add(inpt);
}
int lncnt = 0;
String tbl[][] = new String[buffed.size()][rssnps.size()];
for (int s = 0; s < buffed.size(); s++) {
prse = buffed.get(s).split(dlmcma);
//turns out I want this smpls ArrayList elsewhere
smpls.add(prse[1]);
//making the table to search through
for (int m = 0; m < prse.length; m++) {
tbl[lncnt][m] = prse[m];
}
lncnt++;
}
//but I return just the tbl here
return tbl;
}
Can anyone recommend a way to use smpls in another class without returning it? Is this perhaps when you use a get/set sort of setup?
Sorry if this seems like an obvious question, I am still new to the world of modular programming
Right now you have this tbl variable. Wrap it in a class and add the list to the class.
class TableWrapper {
// default accessing for illustrative purposes -
// setters and getters are a good idea
String[][] table;
List<String> samples;
TableWrapper(String[][] table, List<String> samples) {
this.table = table;
this.samples = samples;
}
}
Then refactor your method to return the wrapper object.
public TableWrapper fluidigmReader(String cllmp) throws IOException {
// your code here
String tbl[][] = new String[buffed.size()][rssnps.size()];
TableWrapper tw = new TableWrapper(tbl,smpls);
// more of your code
return tw;
}
Then later in your code where you were going
String[][] tbl = fluidigmReader(cllmp);
You instead go
TableWrapper tw = fluidigmReader(cllmp);
String[][] tbl = tw.table;
List<String> smpls = tw.samples;
If you had used a dedicated class for the return value (such as the TableWrapper mentioned in another answer), then you could add additional fields there.
That is the good thing about classes - they can be extended. But you cannot extend String[][] in Java.
You can set a field, instead of a local variable, which you can retrieve later with a getter. You want to avoid it unless it is needed, but in this case it is.
You can use class(Inside Reader class) variable for this. But make sure that it's read/write is synchronized
I have a Enumeration as shown in below program
public class Test {
public static void main(String args[]) {
Vector v = new Vector();
v.add("Three");
v.add("Four");
v.add("One");
v.add("Two");
Enumeration e = v.elements();
load(e) ; // **Passing the Enumeration .**
}
}
There is also a Student Object
public Student
{
String one ;
String two ;
String three ;
String four ;
}
i need to pass this Enumeration to another method as shown below
private Data load(Enumeration rs)
{
Student stud = new Student();
while(rs.hasMoreElements())
{
// Is it possible to set the Values for the Student Object with appropiate values I mean as shown below
stud.one = One Value of Vector here
stud.two = Two Value of Vector here
stud.three = Three Value of Vector here
stud.four = Four Value of Vector here
}
}
Please share your ideas on this .
Thanks
Sure. You could use the elementAt method, documented here, to get the value you wanted. Do you have a specific reason you are using a Vector? Some of the List implementations might be better.
Enumerations don't have the idea of "first value", "second value", etc. They just have the current value. You could work around this in various ways:
The easy way -- convert it to something easier to work with, like to a List.
List<String> inputs = Collections.list(rs);
stud.one = inputs.get(0);
stud.two = inputs.get(1);
// etc.
Keep track of the position yourself.
for(int i = 0; i <= 4 && rs.hasNext(); ++i) {
// Could use a switch statement here
if(i == 0) {
stud.one = rs.nextElement();
} else if(i == 1) {
stud.two = rs.nextElement();
} else {
// etc.
}
}
I really don't recommend either of these things, for the following reasons:
If you want your parameters in a particular order, just pass them in that way. It's much easier and it's also easier to maintain (and for other people to read).
void example(String one, String two, String three, String four) {
Student student = new Student();
student.one = one;
student.two = two;
// etc.
}
You shouldn't use Enumeration at all, since it's been replaced with Iterator and Iterable since Java 1.2. See ArrayList and Collection.