Really basic OO comprehension issue I am running into, any help is greatly appreciated.
I'm trying to add instances of "Thing" to an arraylist every-time I press a button, I can't wrap my head around how to create unique instances to add to the list. A different button press should remove the most recent object from the list.
ArrayList myList = new ArrayList<Thing>();
if(input.isKeyPressed(Input.KEY_A)){
Thing myThing = new Thing();
myThing.setNumber(myList.size());
myList.add(myThing);
}
if(input.isKeyPressed(Input.KEY_R)){
if(myList.size()>0){
myList.remove(myList.size()-1);
}
}
If I plan on making lots of "things" and I don't care about what they are called (nor do I want to keep track of unique thing-object names). How can I create a unique 'thing' object on each button press with minimal pain.
UPDATE:
Thanks for the comments, please let me try to articulate my question better...
When I create an ArrayList full of 'Thing', each instance of which is called "myThing", every instance has the same instance variables values.
If I wanted some of the 'Thing''s to have boolean isVisable = true, and other's to have boolean isVisable = false. I get stuck because each element of the list has the same name.
Make sure that Thing implements equals and hashCode correctly and then store the instances in a Set collection (i.e. HashSet). With the implementation of hashCode() and equals() it will be completely up to you which two instances of Thing are the same and hence you will be able to enforce uniqueness any way you need.
Now the trick here is that implementing hashCode() and equals() is not entirely trivial, but you need to know how to do it if you plan to use Java. So read the appropriate chapter of Effective JAva (or better yet read the entire book).
try this:
$ cat Thing.java
import java.util.*;
public class Thing{
UUID id;
Thing () {
id = UUID.randomUUID();
}
public String toString(){
return id.toString();
}
public static void main(String[] argv) {
Thing t = new Thing();
System.out.println(t);
}
}
$ javac Thing.java && java Thing
08bb3702-84d3-4bc3-b8ab-bb52b90b8f78
Related
Lets assume there is a data service that returns instances of the class cat:
class Cat {
int id;
String name;
int iq;
}
I want to hold the instances inside a Set<Cat> that must not hold two cats with the same id. So I need to override the equals and hashcode method to only check for the id.
My question is how can I detect if a cat inside my set requires an update when I receive a new instance from the service with the same id, but different values for name and/or iq? I cannot add the properties to equals or hashcode since then it would be possible that the Set holds instances of the same id.
Do I have to compare all the fields manually or is there another Java-typical solution for this?
Edit for clarification:
Just updating the Set with the new instance would not be enough because there is code triggered on an update. So what I want to do is:
if (set.contains(newCat)) {
Cat current = set.get(newCat);
if (!current.equals(newCat)) { //obviously this is not enough
set.add(current);
//notify EventBusses and such
}
}
Solutions that came into my mind are:
current.requiresUpdate(newCat) //basically copy of equals() with properties
current.updateWith(newCat) //same as above but keeping the old instance
if (!current.name.euqals(newCat.name)) //for each property
only get the objects from the service that have changed. Optimal, but out of scope for me.
All of which would require somewhat redundant code which is why I was hoping there is a pattern or collection that does the work for me.
The solution can include Guava classes.
I think you have two distinct problems:
Comparing Cat objects: If two Cat objects are equal only if id, name and iq are equal, than implement the equals method accordingly.
Maintaining a collection of Cat objects: To maintain a collection of Cat objects in which there are no two objects with the same id, use a Map<Integer, Cat> as already suggested.
Your code may then look something like:
if (mapOfCats.contains(newCat.id)) {
Cat current = mapOfCats.get(newCat.id);
if (!current.equals(newCat)) {
mapOfCats.put(newCat.id, newCat);
// notify EventBusses and such
}
}
You just need to insert the value again.
If id will be match from previous cat object, it will be overwritten in set.
A HashSet internally maintains a HashMap to identify duplicates.
The simpler solution is: if found equal - remove it and add again, with updated values. The code can be somewhat like this :
yourSet.remove(cat);
yourSet.add(newCatObejectWithSameID);
newCatObejectWithSameID will have different name and iq.
Your requirements sound slightly strange - if the ID field is supposed to uniquely identify a Cat, then there should surely only ever be a single instance of a Cat with that ID. Or, at least, the corresponding fields on the multiple Cat instances should be equal.
However, assuming there can be multiple logically different Cat instances with the same ID, the easiest way to handle this is to use a Map<Integer, Cat>:
Map<Integer, Cat> cats = new HashMap<>();
for (Cat cat : getAllCats()) {
if (!cats.containsKey(cat.id)) {
cats.put(cat.id, cat);
} else {
// Do whatever - ignore, log a message, throw an exception?
}
}
Collection<Cat> catsWithUniqueIds = cats.values();
protected static final Map<String, Integer> m = new HashMap();
I have a question in regards to performance of using the above. I am creating a 2D Tile Engine for a simple RPG game. I am using the hash map above to store the name of a tile along with its respected color code (Ex: 0xff00ff21). Since this is a game, the code m.get("name");is called an enormous amount of times to check if a tile is updated or not. (Ex: The render method with my computer runs at about 850 times per second). Please also note, I made sure to declare the HashMap outside of any loops and that it is initialized via a method call(also static) through the constructor that m.put("name", value) inputs all the information.
1) Is using a HashMap in this way a good idea? Is there perhaps another way to go about this more efficiently.
2) Is using a static final implementation of a hashMap good practice? The values will never change and the values used will be needed within the super class and its sub classes (Hence the "protected"). Can I set the key and value variables to final as well?
3) I understand that HashMap doesn't allow for duplicate keys, but from tinkering around with the HashMap, by inputting two of the same keys it simply replaces the older key and value with the newest .put("name", value);Is there to a way to throw an error perhaps if you try to .put("water", 0xff00ff21) and .put("water", 0xff221133) and/or .put("water",0xff00ff21)
Thank you for your time. New to this community and looking forward to helping/getting helped.
Please note that it is bad to ask three questions in one post.
1) IMO, yes. I usually use a HashMap for this kind of things. This can clarify things a lot better and enhance the readability of your code. Just imagine if you you only use hex color values for these kinda things, I think a lot of people would ask you what is 0xff221133 and what is 0xff00ff21.
2) Yes it is! static final is used when you want to declare some kind of constant. However, declaring a hash map as static final doesn't mean that its content cannot be changed. To prevent this, encapsulate the map in a class and only provide get methods:
final class TileColorMap {
private static final HashMap<String, Integer> tileColorMap = //blah blah blah
static {
//Add things to your map here
}
public static int get(String key) {
return tileColorMap.get(key);
}
}
3) If you look at the docs, specifically, Hashmap<>.put, you will see that:
Returns: the previous value associated with key, or null if there was no mapping for key. (A null return can also indicate that the map previously associated null with key.)
So you can add a method that put something into the map and will throw an exception if the key is a duplicate by checking whether the returned value is null.
private static void putStuffInMap (String key, int value) {
Integer returnedValue = tileColorMap.put(key, value);
if (returnedValue != null) {
throw new RuntimeException("Duplicate Keys!");
}
}
1) I'm not sure I understand what you're doing here, but how many different kinds of tiles could you be using here? You might be better off just defining a Tile object with a few constant Tiles that you can just reuse again and again by referring to Tile.WATER, etc instead of doing a hashtable lookup. If water has multiple colors just put them all in the water Tile object and pick from amongst them.
public class Tile
{
public static final Tile WATER = new Tile(...);
public static final Tile ROCK = new Tile(...);
}
2) Making a hashmap instance static and final doesn't make it immutable. The contents can still be updated. There's no performance benefit anyway. A read only hashmap wouldn't be any faster than a writable one. If you don't want it updated, just don't update it. It's your code, it's not like it's going to write to the hashmap when you aren't looking.
3) You could subclass hashmap and make it not accept duplicate keys, but again, I'm not sure what the purpose of this is- why aren't you sure what colors your tiles will be at run time? This strikes me as the kind of thing decided before compile time.
Using HashMap should be efficient enough. Is there more efficient way? Of course there will always be but whether it is appropriate depends on your design. For example, if tiles are statically defined, you may use enum/integer constants to represent a tile (instead of using "name"), and your tile-to-XXX mapping can be easily expressed as ArrayList or even array. (Again, it may not be appropriate to your design).
Again it depends on the design. Are the class containing the map something that is going to instantiate multiple times but you really want each instance to share same mapping? Are you going to give flexibility to the child class to set up the mapping? It is only meaningful to make it static if first answer is YES and second is NO.
To avoid change of content for the map, you can wrap it in a unmodifiable map:
// Access your data through this, so you won't mistakenly modify it
protected final Map<...> tileColorMap = Collections.unmodifiableMap(getTileColorMap());
// your super class or sub-class is providing the actual map
protected Map<...> getTileColorMap() {
Map<...> tileColorMap = new HashMap<>();
// do your setup
return tileColorMap;
}
If you are using Java 8+, it may be better to use Map#merge() method, and have the remapping function throw an exception you desire. Compared with the approach given by other answers, using merge() is safer as original value won't be mistakenly replaced. You may also selectively throw the exception if the new value is different from existing value.
In Java there is a collection called ArrayList. It allows programmer to add an object of type T and remove them by issuing a simple methods, like
list.remove(object);
list.add(object);
For C++ I've found that standard vectors are using value objects only, so I dont see the way to achieve same functionality.
The case is that I want to hold a reference to an object elsewhere why being able remove or add it using some composition pattern. What I'm asking for is how to achieve something like this in C++:
class Composite {
ArrayList<Composite> children = new ArrayList<>();
public void addChild(Composite child) {
children.add(child);
}
public void removeChild(Composite child) {
children.remove(child)
}
}
class Test{
public static void main() {
Composite a = new Composite();
Composite b = new Composite();
a.addChild(b);
a.removeChild(b);
// from here on a.children is empty.
}
}
I dont even know how to bite this thing in C++. Thanks.
UPDATE: Thanks to the ResidenBiscuit answer and others comments I was able to figure out the basic code for this, which is available at this pastebin url: http://pastebin.com/h17hh3r4
In Java, everything besides POD is a reference. There's no specifying you want a reference, because that's all you get.
Not so much in C++. Everything defaults to value. If you want a std::list of reference types, then you'll need a compiler supporting C++11 std::reference_wrapper. You can then do:
std::list<std::reference_wrapper<Type>> t_list
To add to this list, you would need to use std::ref:
t_list.push_back(std::ref(myObj))
Now everything you add into this list will just be a std::reference_wrapper type. You could also store pointers instead by just doing:
std::list<Type*> tptr_list
Which may be easier, or the only option if you don't have a C++11 compliant compiler.
I'm working on a java program, and I have several vectors defined and filled (from a file) inside a method. I need to return the contents of all the vectors from the method. I have heard you can put them all in one object to return them. Is that possible, and if so, how? If not, do you have any possible solutions for me? Thanks in advance for your help!
Here is a code snippet:
Object getInventory()
{
Vector<String> itemID=new Vector<String>();
Vector<String> itemName=new Vector<String>();
Vector<Integer> pOrdered=new Vector<Integer>();
Vector<Integer> pInStore=new Vector<Integer>();
Vector<Integer> pSold=new Vector<Integer>();
Vector<Double> manufPrice=new Vector<Double>();
Vector<Double> sellingPrice=new Vector<Double>();
Object inventoryItem=new Object(); //object to store vectors in
try
{
Scanner infile= new Scanner(new FileReader("Ch10Ex16Data.txt"));
int i=0;
while (infile.hasNext())
{
itemID.addElement(infile.next());
itemName.addElement(infile.next()+infile.nextLine());
pOrdered.addElement(infile.nextInt());
pInStore.addElement(pOrdered.elementAt(i));
pSold.addElement(0);
manufPrice.addElement(infile.nextDouble());
sellingPrice.addElement(infile.nextDouble());
i++;
}
infile.close();
System.out.println(itemID);
System.out.println(itemName);
System.out.println(pOrdered);
System.out.println(pInStore);
System.out.println(pSold);
System.out.println(manufPrice);
System.out.println(sellingPrice);
}
catch (Exception f)
{
System.out.print(f);
}
return inventoryItem;
}
Personnally, I'd scrap that approach completely. It seems like you need a Product class:
public class Product {
private String itemName;
private int itemID;
// etc etc
public Product(String itemName, int itemID) {
this.itemName = itemName;
this.itemID = itemID;
// etc etc
}
public String getItemName() {
return itemName;
}
public int getItemID() {
return itemID;
}
// etc etc
}
Then something like this :
public class Invertory {
private List<Product> products = new ArrayList<Product>
// etc etc
public Inventory(String fileName) throws IOException {
// Load file,
// Read each product,
products.add(new Product(...product arguments); //add to array
}
public Product[] getProducts() {
return products.toArray(new Product[]{});
}
}
First of all, use ArrayList instead of Vector. Then use a Map as your return object, with each value of the entry is one of your Lists.
Second of all, a much better approach is to create an object that actually holds each of your fields and return a java.util.List of these objects.
public class Item
{
String id;
String name
Integer pOrdered;
Integer inStore;
:
:
You're doing a few things wrong.
Firstly, don't use Vector. Like, ever. If ordering is important to you, you want List on the API (and possibly ArrayList or LinkedList as an implementation).
Secondly, you're trying to have a large number of arrays have values that happen to line up. That's going to be nearly impossible to use. Just create a class that represents one record, and return the List of those.
Thirdly: do not catch that exception. You don't know what to do with it, and you're just going to confuse yourself. Only catch an exception if you have a really good idea what to do in the error case (printing out an error message without a stack is just about never the right thing).
The signature of your method is the most important part. If you get that right, the implementation doesn't matter nearly as much. Aim for something that looks like this:
List<Item> getInventory(File input) throws IOException {
}
You really should reconsider your design here. You have multiple vectors, each with properties of the same type of thing — an item in your inventory. You should probably turn this into a single class, perhaps InventoryItem, with members for the name, price, etc. Then, when reading in each item, you construct an InventoryItem with the given properties, and return a single Vector<InventoryItem>.
If you're really attached to keeping track of all those individual Vectors, you could just return a Vector[] with all the vectors you have:
return new Vector[] { itemID, itemName, pOrdered, pInStore, pSold, manufPrice, sellingPrice };
Also, as Robin says, you should use the ArrayList container instead of Vector. The only thing that will change is that you need to change all calls to someVector.AddElement to someList.add.
Sounds like this should be tagged "Homework".
Okay, first of all, are you required to use all these Vectors, or is that your own decision? Though some may point out that using ArrayLists is better, I'd do away with them and create your own Item class.
This way, instead of having a conceptual item's properties distributed across multiple Vectors (the way you're doing now) you have 1 Item instance per item, with fields for all the data relevant to that item. Now, you only need one data structure (Vector or ArrayList) for all your item objects, and you can return that structure from getInventory().
The easiest way to declare the object would be something like
List<Vector<? extends Object>> inventoryItem = new ArrayList<Vector<? extends Object>>
but this has several problems, namely that Java's generics aren't reified, so you have to test and cast the contents of each vector that you get back. A better solution would be to define a container object that has each of the Vectors as fields and add to those.
However, this looks like it is really missing the point. Instead, you should define an InventoryItem who has each of your seven fields. Each time you read an object from the file, instantiate a new InventoryItem and populate its fields. Then, you add this to a single Vector.
Also, it is generally recommended that you do not use the Vector class. Instead, you should use ArrayList. Vector should really only be used if you need its synchronization properties, and even then you should consider wrapping some other list in a Collections.synchronizedList().
Finally, the places where you would want to catch just an Exception can be counted on one hand. You should really be catching an IOException and even that you might want to consider just rethrowing. Also, you should call printStackTrace() on the exception rather than System.out.println().
I find that a good rule of thumb is that it's never really a good idea to pass collections around outside your objects. They are obviously useful inside your object, but outside you lose control and they are not obvious.
Consider the principle of making your code readable instead of documenting it. If you take a collection, how does that tell the caller what to pass in? Even if you use generics, there is no way to assert control over what happens to the collection--someone could be adding to it and deleting from it in another thread after it's passed to you.
There is no reason not to create a business class that contains your collections along with the business logic to manipulate them (yeah, there is always business logic--it's the copy and paste code you'll find around the locations that you access the collection).
I used to find it frustrating that the JDK always seems to take arrays of built-in types rather than collections, but it makes a lot more sense after coming to terms with the idea that passing collections (like passing around any basic type) is just not a very good idea.
While in general I heartily agree with the advice to use List/ArrayList instead of Vector, it is important to know why. Indeed, I have to vehemently disagree with Dustin who says not to use Vector "ever".
A Vector is in essence a synchronized ArrayList. If you truly need synchronization, by all means then, ignore Dustin's admonition, and use Vector.
There is another instance in which Vector is justified. And that is when you need to maintain compatibility with a pre-Java2 code base.
Let's say I have this type in my application:
public class A {
public int id;
public B b;
public boolean equals(Object another) { return this.id == ((A)another).id; }
public int hashCode() { return 31 * id; //nice prime number }
}
and a Set<A> structure. Now, I have an object of type A and want to do the following:
If my A is within the set, update its field b to match my object.
Else, add it to the set.
So checking if it is in there is easy enough (contains), and adding to the set is easy too. My question is this: how do I get a handle to update the object within? Interface Set doesn't have a get method, and the best I could think of was to remove the object in the set and add mine. another, even worse, alternative is to traverse the set with an iterator to try and locate the object.
I'll gladly take better suggestions... This includes the efficient use of other data structures.
Yuval =8-)
EDIT: Thank you all for answering... Unfortunately I can't 'accept' the best answers here, those that suggest using a Map, because changing the type of the collection radically for this purpose only would be a little extreme (this collection is already mapped through Hibernate...)
Since a Set can only contain one instance of an object (as defined by its equals and hashCode methods), just remove it and then add it. If there was one already, that other one will be removed from the Set and replaced by the one you want.
I have code that does something similar - I am caching objects so that everywhere a particular object appears in a bunch of different places on the GUI, it's always the same one. In that case, instead of using a Set I'm using a Map, and then I get an update, I retrieve it from the Map and update it in place rather than creating a new instance.
You really want to use a Map<Integer,A>, not a Set<A>.
Then map the ID (even though it's also stored in A!) to the object. So storing new is this:
A a = ...;
Map<Integer,A> map = new HashMap<Integer,A>();
map.put( a.id, a );
Your complete update algorithm is:
public static void update( Map<Integer,A> map, A obj ) {
A existing = map.get( obj.id );
if ( existing == null )
map.put( obj.id, obj );
else
existing.b = obj.b;
}
However, it might be even simpler. I'm assuming you have more fields than that in A that what you gave. If this is not the case, just using a Map<Integer,B> is in fact what you want, then it collapses to nothing:
Map<Integer,B> map = new HashMap<Integer,B>();
// The insert-or-update is just this:
map.put( id, b );
I don't think you can make it any easier than using remove/add if you are using a Set.
set.remove(a);
set.add(a);
If a matching A was found it will be removed and then you add the new one, you don't even need the if (set.contains(A)) conditional.
If you have an object with an ID and an updated field and you don't really care about any other aspects of that object, just throw it out and replace it.
If you need to do anything else to the A that matches that ID then you'll have to iterate through the Set to find it or use a different Container (like the Map as Jason suggested).
No one has mentioned this yet, but basing hashCode or equals on a mutable property is one of those really, really big things that you shouldn't do. Don't muck about with object identity after you leave the constructor - doing so greatly increases your chances of having really difficult-to-figure out bugs down the road. Even if you don't get hit with bugs, the accounting work to make sure that you always properly update any and all data structures that relies on equals and hashCode being consistent will far outweigh any perceived benefits of being able to just change the id of the object as you run.
Instead, I strongly recommend that you pass id in via the constructor, and if you need to change it, create a new instance of A. This will force users of your object (including yourself) to properly interact with the collection classes (and many others) that rely on immutable behavior in equals and hashCode.
What about Map<A,A> I know it's redundant, but I believe it will get you the behavior you'd like. Really I'd love to see Set have a get(Object o) method on it.
You might want to generate a decorator called ASet and use an internal Map as the backing data structure
class ASet {
private Map<Integer, A> map;
public ASet() {
map = new HashMap<Integer, A>();
}
public A updateOrAdd(Integer id, int delta) {
A a = map.get(a);
if(a == null) {
a = new A(id);
map.put(id,a);
}
a.setX(a.getX() + delta);
}
}
You can also take a look at the Trove API. While that is better for performance and for accounting that you are working with primitive variables, it exposes this feature very nicely (e.g. map.adjustOrPutValue(key, initialValue, deltaValue).
It's a bit outside scope, but you forgot to re-implement hashCode(). When you override equals please override hashCode(), even in an example.
For example; contains() will very probably go wrong when you have a HashSet implementation of Set as the HashSet uses the hashCode of Object to locate the bucket (a number which has nothing to do with business logic), and only equals() the elements within that bucket.
public class A {
public int id;
public B b;
public int hashCode() {return id;} // simple and efficient enough for small Sets
public boolean equals(Object another) {
if (object == null || ! (object instanceOf A) ) {
return false;
}
return this.id == ((A)another).id;
}
}
public class Logic {
/**
* Replace the element in data with the same id as element, or add element
* to data when the id of element is not yet used by any A in data.
*/
public void update(Set<A> data, A element) {
data.remove(element); // Safe even if the element is not in the Set
data.add(element);
}
}
EDIT Yuvalindicated correctly that Set.add does not overwrite an existing element, but only adds if the element is not yet in the collection (with "is" implemented by equals)