instanceOf in a Controller class ok? (Cannot edit any other class) - java

The project has 4 classes. A Person, an Employee that extends Person and an Academic that extends Employee.
I also have a Store, which is a user-made alternative to an Array. One of the functions of Store is ‘elementAt()’, which returns to us an object in Store.
The problem I have is that elementAt() always returns as type Person. This is a huge problem because, in my Controller class, before I let the user perform an action only applicable to an Academic I NEED to check whether the user has actually chosen an employee or not.
public Person elementAt(int index)
{
// Returns element at position index
return list[index];
}
There is one big problem; according to the project specification I cannot alter the Person, Employee, Academic or Store class any further. Meaning, I have to determine the type of the Store index somewhere, somehow within my controller class.
I wanted to run this by people with more experience so thank you for having a look.

Instanceof seems to me the only option you have; and I don't think that its evil to use it in this case. But you are right, it is not the nicest thing in thinking in objects ;o)
At least you might encapsulate that like
public boolean isAcademic(Person p) {
return p instanceof Academic;
}
to concentrate the "code smell" in one position, and make it easier to later refactor it.

I don't know if i got it right, but if you just want to check the returned object type, do this:
Person person = store.elementAt(0);
if (person instanceof Academic) {
//do stuff
}

Related

Setting a Maximum limit for an ArrayList

So for school I am making a program where we are creating a booking system where people can book a ticket for a movie that has a capacity of 10 people. People are allowed to change the time of the booking to the next day as long as the theater is not full for that day.
An array will be no good in this situation as I need to be able to remove an object from the array and make another free space in said array, and then add the removed object to a different Array for the different day. This part is suitable for an ArrayList but it has no size limit so I'm stuck with what the best solution is. Any ideas that I can look into?
Thanks
You can try the below, start from an array and convert it to list via Arrays.asList. Just note you could only use the set() method on the List, and not the add/remove methods as these would modify its size :
String[] array = {"a1","b2","c3"};
List<String> fixed = Arrays.asList(array);
fixed.set(0, "new_string"); // OK
fixed.add("aNewString"); // This will throw an exception
You can extend a class which already has the functionality you need and only override the methods required to implement new functionality (i.e. enforce a size limit).
Consider the following solution:
public class CappedList<T extends Object> extends ArrayList<T> {
private final int maxSize;
public CappedList(int maxSize) {
this.maxSize = maxSize;
}
#Override
public boolean add(T e) {
if (this.size() == this.maxSize) {
//Already reached max size, abort adding
throw new IllegalStateException("List is maxed out");
} else {
return super.add(e);
}
}
}
For completeness, you need to also override all add and addAll overloaded methods. You can then use this CappedList class instead of a simple ArrayList. A utility function isMaxedOut would be handy, in order to avoid exception handling:
public boolean isMaxedOut() {
return this.size() == this.maxSize;
}
It all depends how far you are in understanding of the language.
Let's say, first of all as a base logic that you might consider is, that you should find what is unique for 10 tickets. Obviously it's a group, which has own unique identifier and that's a date, so you have to concentrate on binding your tickets to a date groups, then you should control the amount what you are populating per date, you might need advanced control logic, rather than an usual variable that might do the job for you.
First of all, I would not store tickets in a different variables per day.
Let's go into details.
If you are obsessed by using only one specific property and that's ArrayList, I found nice answer here
But to have more precise population and access to the list later, for example to filter out specific date and see those tickets that are sold that day you should do it with a bit more structured logic, rather than a simple ArrayList(), may be you should even use different Type of variable that you should store that data in.
If you are on a bit advanced programming course, from the brief observation, for a simple task I might say that there is the way to use getter and setter methods to implement limitations and you could use any type of object to store that data, beside ArrayList.
Or you could write own functions that can control adding and removing elements from a list.
Or in more advanced way, if you have been introduced to a class concept, you could use class to define a ticket and then you could construct any logic behind it. This last one is the best way to go - to write easily readable, understandable and reusable code, or store specific data and control it the way you want.

List usage without specifying the Type

I see a code in the new environment. It is as follows:
List results;
if (<Some Condition>) {
results = List<XYZ> results;
} else {
results = List<ABC> results;
}
XYZ and ABC are Hibernate Entities.
Though this works, I guess this is not a proper way to do this.
I would like to know whats the better way to do it. I know there is no "perfect" way to do it. But this can be better.
Remember these are non-similar Entities. So I think wrapping these Entities with an Interface might not be a good idea.
Generics are a compile-time mechanism, so, if you don't know the type of object you are pulling, generics are not appropriate.
I understand that the entities are different and not correlated, but I don't understand why an interface is not a good idea. Basically, you know that you want to collect some data, according to some condition. So, just for the fact that XYZ and ABC are candidates to be type of the collected data, you do have some commonalities. In that case, you may have a
List<? extends CommonInterface>
and CommonInterface is used just here.
However, assuming XYZ and ABC are completely distinct, one more option could be to split the method in two parts and use a generic method receiving also the type of data you want to collect:
public void methodForTheCondition() {
if (<some condition>) {
List<XYZ> l = genericMethod(XYZ.class);
// do something
} else {
List<ABC> l = genericMethod(ABC.class);
// do something else, which I assume is different, otherwise opt for
// a common interface
}
}
public <T> List<T> genericMethod(Class<T> clazz) {
List<T> result = new ArrayList<T>();
return result;
}
But this can be better.
What makes you believe this? Without knowing the exact condition, this looks simply like a mass-loading of items in a generic EntityManager and therefore returning a List<X> whatever X might be.
From the code point of view, there is nothing wrong, because you are creating a untypted List and assigning a List of a certain type to that variable later...
As long as you use List as a raw-type, you are able to assign any List to it. This is what interfaces are designed for (Assigning a type without knowing the exact type...)
Remember these are non-similar Entities. So I think wrapping these Entities with an Interface might not be a good idea.
There are a lot of Interfaces out there that makes perfect sence for non-similar Items. Starting with anything that Aggregates elements (List, Map), ending with Interfaces that simply describe one thing that is in common, I.E: Serializable, Comparable, etc..
An Interface does not mean that the objects are related in some way (that is what parent/abstract classes are used for) An Interface simply say that a certain functionality is implemented. (hence, you can inherit multiple interfaces in one class)

Caching database results in Java objects under Play 2.1

In the model layer of an application I'm working on, I have an Organization class, that has a one-to-many relationship with a Person class. Person objects can have a number of different roles, based on their one-to-many relationships to another set of objects of the superclass Certificate. To determine if a Person is a "signatory", I call
public boolean isSignatory() {
return this.certificatesAsSignatory.size() > 0;
}
I want to return a list of signatories for an organization, so I'm going to loop through the set of related persons, checking for signatories. What I'd like to do is cache the result, so I don't have to regenerate the data from the database each time. I've added a private field to Organization that looks like
private List<Person> signatories;
and the basic method looks like this
public List<Person> getSignatories() {
for ( final Person person : this.people ) {
if ( person.isSignatory() ) {
this.signatories.add( person );
}
}
return this.signatories;
}
Now, when I call the method to return the list, I'll store the result in signatories and return it. When it's called again, I can check if signatories already contains a list, and return that instead of doing the calculations again.
My question is this: how do I keep the cache of the list of signatories up to date?
So the list contains all persons who are signatories. It would seem a good idea to update that list every time Person changes from being a signatory to not being one, or vice versa. Im guessing you have some method that sets if a Person is a signatory or not? In that function you could make a call to clear the cache so it would refill the list next time it is needed. Im also guessing it can be done when a new Person is inserted into the db and should be a signatory.
Its hard to be more specific since I dont know how your code is sturctured. But the idea of a cache is to reset it when the data thats in it changes.

Adding unique object instances into an ArrayList

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

Updating an object within a Set

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)

Categories