I'm new to Java and been trying to figure out if I need to pass a new instance of a class when adding the entry to a list, as such:
CCustEntry entry = new CCustEntry();
List<CCustEntry> CustList = new ArrayList<CCustEntry>();
do
{
// set all entry fields
entry.id = [...];
[fill other fields of entry from DB]
// add entry (constructor copies entry)
CustList.add( new CCustEntry( entry ) );
} while( C.moveToNext() == true );
OR... can I remove new and simply pass entry to the add() method like this:
CustList.add( entry );
I've been reading about Lists but I'm more confused than I was before. Coming from Delphi and C++, I'm fine with the syntax, but some of the "grammar" of Java still has me scratching my head.
Thanks for any help.
It depends if the entry will be modified or not. It sounds like you have a bean that makes a shallow copy of the entry, so if the fields of entry will be modified, then you should add a copy. Otherwise, it would be just wasting memory to construct a new one.
Here, it seems like you are using the same entry throughout the loop, so you will want to make a copy. Otherwise, the whole list will contain the same object - i.e., each item is the same object.
Another comment: in Java, it's usual to name fields and values starting with a lowercase letter.
It depends: if you don't create a new instance each time, then you will be adding the same instance to the list multiple times. This means that if you modify an element at one index of the list, then all of the other elements will also get modified in the same way (since they are all the same instance). If you want distinct but equal instances, then you must create a new one each time.
Related
I'm new to Java and is trying to learn the Enumeration 's hasMoreElements() and nextElement() method. After I added some elements to the p1 list while deleted others from the p1 list, I tried to print everything, however, it failed to do so? Why is this happening?
Properties p1 = new Properties();
try (OutputStream os1 = new FileOutputStream("xanadu123.properties")) {
//set the properties value
p1.setProperty("database", "localhost");
p1.setProperty("1", "one");
p1.setProperty("2", "two");
} catch (IOException e) {
e.printStackTrace();
}
Enumeration<Object> eString1 = p1.elements();
while (eString1.hasMoreElements()) {
System.out.println(eString1.nextElement());
}
System.out.println("after printing eString1");
p1.setProperty("3", "three");
p1.remove("2");
System.out.println("before printing eString1 again");
while (eString1.hasMoreElements()) {
System.out.println(eString1.nextElement());
}
Output:
two
one
localhost
after printing eString1
before printing eString1 again
The basic answer is that you cannot rely on Enumeration working if you modify the thing you're enumerating (in this case, the Properties). Once you do that, the Enumeration you constructed may no longer work.
The newer version of Enumeration, Iterator, is the same way, with the exception that some Iterators provide a remove method that allows you to remove the "current element" from a collection without breaking the iterator. (But you have to use the remove method of the Iterator; you can't use any other mechanism for removing an element, or else you could break the iterator.)
The basic reason is that an Enumeration or Iterator contains state information about the entity you're enumerating. If you modify that entity, the state information may no longer be valid. Suppose, for example, that you're iterating over an ArrayList. Most likely, the iterator will contain an integer that's the "current" index of the array. If you then insert something at the front of the ArrayList, the element that is pointed to by that index will become a different element, and next time you call next on the iterator, it will look at the element at that index and return the same element it returned last time. In your case, I'd guess that one piece of state information kept in the Enumeration is a boolean instance variable that says, "Have I reached the end yet?" Once you reach the end of the Properties, that variable will become true. If you then add more properties, the "end-of-the-enumeration" variable will still be true, even though it's effectively wrong at this point.
It simply isn't practical to try to set up Enumerators and Iterators so that they adjust themselves whenever the underlying entity changes. Either a Properties object (or an ArrayList or whatever) would need to keep track of every Enumerator or Iterator created from it, and then go find all of them and adjust them whenever something is done that changes the Properties; or else each Enumerator or Iterator would need a way to query the Properties to ask it, what changes have happened since the last time I checked? Either of those would be very complicated. Consider also that Properties is a hash table, so that when you add a new element, you could add it to any bucket in the hash table. If the Enumerator has already scanned over that bucket, how would it know to go back and scan it again, after you've added a new element? An Enumerator that works that way could be written, I believe, but it would be very inefficient and messy and complicated.
there are two things to notice here:
elements() creates the enumeration from properties. once it's created, it is disconnected from the properties itself. The meaning of that is that adding one more property afterwards will not be added to the enumeration
an enumeration is a 'one time' object, similar to iterator. This means you can loop over the elements one time, after that, the hasMoreElements will return false every time you call it.
given that two facts, it makes perfect sense the second print prints nothing
Do not forget to reset your enumeration before using it again.
eString1 = p1.elements();
while (eString1.hasMoreElements()) {
System.out.println(eString1.nextElement());
}
calls is an arrayList, customerCalls is a hashMap. I was debugging using eclipse and I fount that calls.clear clear the arrayList object already inserted in the customerCalls Hashmap. I am confused because I thought that once the object was submitted to another data structure, it has an independent entity and no operations can be taken on it unless I access this data structure containing it.
I need to clear the arrayList calls to make it free for a new set of calls that would be dedicated to another contract and later inserted as value for the hashmap key (contract Number). Not clearing it accumlates all calls as it appends current iteration addition to the past iteration one.
> if (callContractID.equals(currentContractID)==false){
> customerCalls.put(currentContractID, calls);
> currentContractID = callContractID;
> calls.clear();
> calls.add(call);
> count++;
> }
else {
calls.add(call);
}
Passing a reference to object A to another object in no way alters A (unless the other object explicitly invokes a method on A to change its state, of course). It doesn't spawn an independent copy of A, or make A immutable, or anything like that.
It sounds like what you want to do is to just create a new ArrayList once you're done with the first one and have submitted it to the map.
if (!callContractId.equals(currentContractID) {
calls = new ArrayList<Call>(); // or whatever the type is
// rest of your code...
}
This will replace the value of calls with a reference to a new, empty ArrayList that you can add new elements to. The old ArrayList will still be available to the HashMap, because the map has its own copy of the reference to that first list.
I am confused because I thought that once the object was submitted to another data structure, it has an independent entity and no operations can be taken on it unless I access this data structure containing it.
No. The map contains a reference to an object... just as if you simply assigned another variable to it. You can have lots of references to the same object, and any changes made via one reference will be seen via any of the others. As a very simple example:
StringBuilder b1 = new StringBuilder();
StringBuilder b2 = b1;
b2.append("foo");
System.out.println(b1); // Prints foo
The exact same thing happens with collections:
StringBuilder b1 = new StringBuilder();
List<StringBuilder> list = new List<StringBuilder>();
list.add(b1);
StringBuilder b2 = list.get(0);
// Now b1 and b2 are both reference to the same object...
b2.append("foo");
System.out.println(b1); // Prints foo
Not at all. The object has not been "submitted", it has been passed to another method (it happens that such method has made its own copy of the reference to the object.
All references to the object point to the same object and may call the same methods. The object (usually) has no means to know where it is being called from.
Lets say I have a list like this:
private LinkedList<String> messages = new LinkedList<String>();
When my method gets invoked for the first time there some strings added to this list. And I have also another method in which I need to clear this list from previously added values. To clear it I can use:
messages.clear();
This will remove all the elements from the list. Also I can create a new instance like this:
messages = new LinkedList<String>();
Which way is more proper to clear the list?
messages.clear();
Will actually clear the list, messages = new LinkedList<String>(); will just set messages as referencing a new list instance, so you could argue the first way is more "correct" to clear the list instance.
Say you have a list that is referenced by two variables, a and b. Like this (they don't have to be as close to eachother as this, they might even be in different files..):
final List<String> a = new LinkedList<String>();
final List<String> b = a;
Now, there is a big difference between
a.clear();
which will make both a and b reference the same, empty list, and
a = new LinkedList<String>();
which will make 'a' reference a new, empty list, and 'b' the old, populated list. (So they do not reference the same list).
Since you probably want them to reference the same list, a.clear() is preferred, since you won't get any surprises when your looking at the list referenced by b (which you might believe to be empty, but turns out to be populated if you use the new-approach).
I prefer the first approach i.e. messages.clear(); as it clear the elements but the List is not destroyed and recreated. All elements are removed as desired.
One side effect is there though: It iterates your list and removes one item at a time so if the list is huge then it's an unnecessary overhead.
for (Node<E> x = first; x != null; ) {
Node<E> next = x.next;
x.item = null;
x.next = null;
x.prev = null;
x = next;
}
first = last = null;
size = 0;
modCount++;
Same way second approach has also one side effect: If you are using the object reference of you r list somewhere else in your program, that needs to handled properly otherwise you could get some unwanted surprises e.g. if you added your list to some other object/variable, then first approach will clear that elements from every place where it was referenced while second will not.
Summary: Both the approach outcomes are different in low level nature; though they seem to to serve your high level requirement (clearing the list). Decide carefully based on your low level requirements.
They are almost similar, but I would say messages.clear() is more flexible.
The second approach is simple and much used, but the problem where you have final modifier on your list you can not clear it that way.
messages.clear();
is more efficient. For more safety you can ask if this list is not empty befor
Personnaly I prefere to use LinkedList#clear because it is more clearly to understand during reading the code what you are doing.
But the new LinkedList<String>(); will work fine as well. So it's up to you what to use!
It clearly depends upon your need.
If you want to keep reference to your list object instance (as an example if that clear method is called inside a method in which the messages is a parameter, then the call to .clear() is the best solution.
On the other hand, if the list you want to clear is a member field (or a local variable in a method) of the object the current method is a member of, then you can call new LinkedList<String>(); without any trouble.
Notice that, to avoid the first (which I tend to disapprove), i usuall always return obejcts I modify as results from methods modifying them.
the first one is preferable. the second one makes some extra burden on the garbage collector. but the first one not.
I have an ArrayList that I am adding objects to. Objects are added by using a textbox.
The problem I have is when user enters a value into the textbox, all the entries in my ArrayList take on the new value.
if(e.getSource() == textbox){
String name = textbox.getText();
NameSurferEntry entry = new NameSurferEntry();
entry = db.findEntry(name);
graph.addEntry(entry);
graph.update();
textbox.setText("");
}
Code to add entry:
public void addEntry(NameSurferEntry entry) {
entryArray.add(entry);
}
You're creating a new NameSurferEntry which you on the next line overwrite with a value from your database. If the returned entry is always the same your arraylist will only contain references to the same object.
NameSurferEntry entry = new NameSurferEntry();
entry = db.findEntry(name);
What you should consider is trying to achieve immutability in your objects and/or perform defensive copying. For simple properties it's enough to declare them final, but for complex elements you would typically need to copy the object by creating it anew.
The following sample should work for you, given that you implement the copy constructor
NameSurferEntry copy = new NameSurferEntry(db.findEntry(name));
This means that db.findEntry always returns the same NameSurferEntry instance, and just replaces the name inside it with the name it receives as argument.
Adding an object to an list only adds a reference to the object in the list. It doesn't clone the object to store a copy of it in the list.
BTW, why are you creating a new NameSurferEntry and assign it to the entry variable if it's just to overwrite it with the result of db.findEntry afterwards?
Whatever this is:
entry = db.findEntry(name);
contains and returns one object, and you're changing whatever it contains.
To be more clear: You're adding the same reference to your list over and over, and changing the contents of the single object that reference points at.
OK so this is a BIT different. I have a new HashMap
private Map<String, Player> players = new HashMap<String, Player>();
How do I remove last known item from that? Maybe somethign like this?
hey = Player.get(players.size() - 1);
Player.remove(hey);
The problem is, a HashMap is not sorted like a list. The internal order depends on the hashCode() value of the key (e.g. String). You can use a LinkedHashMap which preserves the insert order. To remove the last entry on this you can use an iterator in combination with a counter which compares to the size and remove the last entry.
It's so easy. Try this:
Map<String, Player> players = new LinkedHashMap<String, Players>();
List<String> list = new ArrayList<String>(players.keySet());
map.remove(list.get(list.size()-1));
I'm a little bit confused. First of all, you're saying that you've got a new ArrayList and you're illustrating this with a line that creates a new HashMap. Secondly, does the Player class really have static methods like get(int) and remove(Object)?
HashMap doesn't have a particular order, ArrayList (as any other List) does.
Removing from an ArrayList
If you've got a list of players, then you can do the following:
private List<Player> players = new ArrayList<Player>();
// Populate the list of players
players.remove(players.size() - 1);
Here, I've used the remove(int) method of List, which allows to remove an item at an arbitrary index.
Removing from a HashMap
If you've got a map of players, there's no such thing as "the last item". Sure, you can iterate over the map and one of the items will pop out last, but that doesn't mean anything. Therefore, first you have to find out what you want to remove. Then you can do the following:
private Map<String, Player> players = new HashMap<String, Player>();
// Populate the map of players
// Find the key of the player to remove
players.remove(toRemove);
Here, I've used the remove(Object) method of Map. Note that in order to remove some key-value pair, you have to show the key, not the value.
There's no "first" and "last" in a HashMap. It's unordered. Everything is accessible by its key, not by index.
You cannot delete from HashMap like that. You need to use LinkedHashMap.
Simple, just do something of this effect.
1) Get a keyset iterator;
2) Create a Key somelastKey = null
3) Iterate through the iterator and assigning somelastKey until iterator finishes.
4) finally, do players.remove(somelastKey);
Bear in mind that HashMap is unordered, it depends on Object's hashCode to determine insertion order.
Instead of using HashMap, try using LinkedHashMap which keeps a predictable iteration order.
Hope this helps....
You'll probably have to extend HashMap, override put so that it caches the key, and then create a new method that just removes the key that was cached.
Unfortunately, this will only let you remove the most recently added. If you need to remove the most recently added multiple times (without inserting in-between the removes), you're out of luck.
In that case, I'd probably do the same overrides, just write the keys to a List. So you'd have both a list and a Map.
When adding:
String key; Player value;
lastKey = key;
map.put(key, value);
//...later...
Player lastAdded = map.remove(lastKey);
Other than that there's really no way without using a LinkedHashMap or in some way creating your own wrapper map or extending HashMap.
You shouldn't be using a raw hashmap anywhere because things like this happen.
Get in the habit of wrapping your collections in business logic classes.
See, in your case right now you need to associate these two related variables--your hashmap and a "Last entered" item so you can remove it.
If you need to remove the last item from some other class, you need to pass both items.
Any time you find yourself passing 2 or more items together into more than one API, you are probably missing a class.
Create a new class that contains the hashmap and a "lastAdded" variable. Have put and remove methods that are just forwarded to the hashmap, but the put method would also set the lastAdded variable.
Also be sure to add a removeLast() method.
NEVER allow access to your hashmap outside this class, it needs to be completely private (this is what I mean by wrapped). In this way you can ensure it doesn't get out of sync with the lastAdded variable (also completely private).
Just to reiterate getters and setters for these variables would be a terrible idea (as they are with nearly all actual OO code).
You will quickly find a bunch of other methods that NEED to be in this class in order to access data inside your hashmap--methods that never felt right in their current location. You will probably also notice that those methods always have an additional parameter or two passed in--those parameters should probably be members of your new class.
Once you get in the habit of doing actual OO design (via refactoring in this case), you'll find your code MUCH more manageable. To illustrate this point, if you find later that you need multiple levels of "delete last", it will be TRIVIAL to add to your class because it will be extremely clear exactly what methods can modify your hashtable and where your new "stack" of lastItems should be located--in fact it's probably a 2 line code change.
If you do not make this wrapper class, various locations will each have code to set "lastAdded" when they add code to the hashtable. Each of those locations will have to be modified, some may be in other classes requiring you to pass your new stack around with the hashtable. It will be easier to get them out of synch if you forget to change one location.