How can I access variables from another class JAVA - java

So i am developing a program to simulate a collection system and the main system takes in items but there are different types of items such as those that require an id check etc... I am using a polymorphic method to access these different classes however is it possible for me to change a variable from the main class based off what occurs in the method that accesses the other class.
EX:
itemCollection firstCollect = new itemCollection();
Item test = new AlcoholItem(5.94, false, 3.76. 0.06) // takes in weight, bulk, price, and sinTaxRate.
Lets say I have to keep an expected weight of the collection for all non bulk items and have a variable in the itemCollection class called bulk, how can I use the fact that this item isn't bulk. Can I from within the AlcoholItem class method which is Polymorphic can I change itemCollection's bulk variable from the AlcoholItem class?

How can I access variables from another class JAVA ?
Generally you want to avoid that and favor methods for that : getters to retrieve values and setters to set values from objects of other classes.
Can I from within the AlcoholItem class method which is Polymorphic
can I change itemCollection's bulk variable from the AlcoholItem
class?
Adding a bulk item doesn't mean that all items are bulk. You should give a clear semantic about the bulk field in ItemCollection.
About updating the weight for no bulk items in the collection, I would do things in the other way since the collection of items depends on the items : when you add an item in the collection, check whether the item is not bulk, if it is not : update the weight of the collection according to.
Generally you want to avoid bidirectional coupling between classes/objects as much as possible.
You should also define a boolean isBulk() method in the item class/interface.
In ItemCollection class the add() could look like:
public void add(Item item){
if (!item.isBulk()){
weight += item.getWeight();
}
else{
bulk = item.isBulk(); // as discussed check the relevance of this flag.
}
// ...
}

Related

Sort and associate objects with unique identifier in a collection

I'm working my through an assignment and got stuck on step 5, would appreciate any help.
Carefully study the class structure in Products.java.
Design a generic container called GenericOrder that acts as a collection of an arbitrary number of objects in Products.java. Design a mechanism that gives each instance of the container a unique identifier. Implement as many methods as necessary. You must use Java generics features.
Design and implement a subclass of GenericOrder called ComputerOrder that takes an arbitrary number of different classes of ComputerPart objects, Peripheral objects, and Service objects. Implement as many methods as necessary.
Design and implement a subclass of GenericOrder called PartyTrayOrder that takes an arbitrary number of different classes of Cheese objects, Fruit objects, and Service objects. Implement as many methods as necessary.
Design and implement a class called OrderProcessor. You must implement at least the following methods:
accept; // this method accepts a GenericOrder or any of its subclass objects and stores it in any internal collection of OrderProcessor.
process; // this method sorts all accepted orders in the internal collection of GenericOrder into collections of ComputerPart, Peripheral, Cheese, Fruit, and Service. You must associate each object with the unique identifier. You may refer to the TwoTuple.java example in the text book.
dispatchXXX; // this method simulates the dispatch of the sorted collections. For example, the method dispatchComputerParts() should produce this output:
Motherboard name=Asus, price=$37.5, order number=123456
Motherboard – name=Asus, price=$37.5, order number=987654
RAM – name=Kingston, size=512, price=$25.0, order number=123456
Create a client class to test OrderProcessor. You will need to create a datagenerator for testing purpose. It is not mandatory but you may use a variation of Data Generator in TIJ pages 637 to 638.
Here is what I have for Q5
public abstract class OrderProcessor<T> {
private ArrayList<T> dataCollection = new ArrayList<T>();
public void accept(T item){
dataCollection.add(item);
}
public void process(){
Collections.sort(dataCollection);
}
public List getDataCollection(){
return dataCollection;
}
}
In its current state Collections.sort(dataCollection); doesn't compile because it does not accept T and if I change the ArrayList to String any function used from other subclasses won't work because they all T. Any help would be greatly appreciated.
thanks in advance.
EDIT: Since you want to partition your orders and not sort, you can use something like this:
dataCollection.stream().collect(
Collectors.groupingBy(order -> order.getIdentifier())
)
Here, this groups them by their identifiers and puts them into a Map. The order.getIdentifier() part is just a placeholder for whatever you want to use to divide them up. The return type will be Map<TypeOfIdentifier, T>.
For this to work, though, your T has to be of some specific type (T extends Product perhaps?) so you can get the identifier. Since I don't know the code for differentiating between different products, I can't put the exact code here.
The Javadoc for Collectors
This is why Collections.sort wasn't working for you, but you don't need Collections.sort anyways.
T must extend the Comparable interface, because obviously you can't sort objects of just any type. The Comparable interface has a compareTo method that lets you sort.
An alternative would be to write a custom Comparator that defines a single method: compare, which would take 2 objects of type T and return an int representing the order (in most cases it's basically the first argument minus the second argument). For this, you would need to use Collections.sort(dataCollection, customComparator).
You can define your comparator with a lambda expression, but I can't help you beyond that because I have no idea how you want to sort your objects.

Is it a bad practice to add elements to List using getter method in java?

Suppose I have a private ArrayList or a LinkedList inside a class, that I will never assign new reference to it, or in other words this will never happen:
myLinkedList = anotherLinkedList;
So that I won't need to use setMyLinkedList(anotherLinkedList).
But! I need to add elements to it, or remove elements from it.
Should I write a new kind of setter to only, do the task of adding instead of setting, like myLinkedList.add(someElement)?
Or it is OK to do this by using getter, without disobeying Encapsulation principal?
getMyLinkedList().add(someElement)
( + Suppose I am going to lose my mark if I disobey encapsulation :-")
I don't think it a particularly great practice to do something like:
myObj.getMyList().add(x);
since you are exposing a private class variable in a non read only way, but that being said I do see it pretty frequently(I'm looking at you, auto generated classes). I would argue that instead of doing it that way, return an unmodifiable list and allow users of the class to add to the list via an explicit method:
public class MyClass{
private final List<String> myList = new ArrayList<String>();
public List<String> getList(){
return Collections.unmodifiableList(this.myList);
}
public void addToList(final String s){
this.myList.add(s);
}
}
EDIT After reviewing your comments, I wanted to add a bit about your setter idea:
I meant using that line of code inside a new kind of setter inside the class itself, like public void setter(someElement){this.myLinkedList.add(someElement);}
If I'm understanding you correctly, you are saying you want to expose a method that only adds to your list. Overall this is what I think you should be shooting for, and what many have outlined in the answers, however, labeling it as a setter is a bit misleading since you are not reassigning (setting) anything. That, and I strongly recommend returning a read only list from your getter method if possible.
I would suggest in this case it would be best to follow your Encapsulation principals and use a method for adding elements to the list. You have restricted access to your list by making it private so that other classes cannot directly access the datatype.
Let the class that stores your ArrayList have direct access to the list, but when other classes want to add to the list, use an add() method.
In general, you should not assume that the list being returned by the getter is the original one. It could be decorated or proxied for example.
If you want to prevent that a new list is set on the target object, you could define an add method on the target class instead.
As soon as you have a Collection of any kind, it is generally not a bad idea to add methods like add(), remove() to the interface of your class if it makes sense that clients can add or remove objects from your private list.
The reason why it is useful to have these extra methods implemented (it might seem like overkill, because after all those methods mostly just call the method on the Collection) is that you protect evil clients from doing things to your list you don't want them to do, because the interface of most Collections contain more than just the add() and remove() methods and mostly, you don't want clients to be messing around with things you can't control. Therefore the encapsulation principle is that important to your teacher.
Another plus: if at any time, you would decide that a certain condition must be met when an object is added to your list, this can easily be implemented in the method you already have. If you give a client access to the direct reference of your list, it is not easy at all to implement this kind of things (which are not rare).
Hope this helps
So you have a class containing a List field (it should be final, since you don't intend to assign to it), and you want to allow callers to add to the List, but not be able to replace it.
You could either provide a getter for the list:
public List<E> getMyList() {
return myList;
}
Or provide a method to add to that list:
public void addToMyList(E e) {
myList.add(e);
}
Both are valid design decisions, but which you use will depend on your use case. The first option gives callers direct access to the List, effectively making it public. This is useful when users will be modifying and working with the list repeatedly, but can be problematic as you can no longer trust the List is in any sort of reliable state (the caller could empty it, or reorder it, or even maliciously insert objects of a different type). So the first option should only be used when you intend to trust the caller.
The second option gives the caller less power, because they can only add one element at a time. If you want to provide additional features (insertion, add-all, etc.) you'll have to wrap each operation in turn. But it gives you more confidence, since you can be certain the List is only being modified in ways you approve of. This latter option also hides (encapsulates) the implementation detail that you're using a List at all, so if encapsulation is important for your use case, you want to go this way to avoid exposing your internal data structures, and only expose the behavior you want to grant to callers.
It depends on the application - both are acceptable. Take a good look at the class you're writing and decide if you want to allow users to directly access the contents of the list, or if you would prefer that they go through some intermediate process first.
For example, say you have a class ListEncrypter which holds your MyLinkedList list. The purpose of this class is to encrypt anything that is stored in MyLinkedList. In this case, you'd want to provide a custom add method in order to process the added item before placing it in the list, and if you want to access the element, you'd also process it:
public void add(Object element)
{
MyLinkedList.add(encrypt(element););
}
public Object get(int index)
{
return decrypt(MyLinkedList.get(index););
}
In this case, you clearly want to deny the user's access to the MyLinkedList variable, since the contents will be encrypted and they won't be able to do anything with it.
On the other hand, if you're not really doing any processing of the data (and you're sure you won't ever need to in the future), you can skip creating the specialized methods and just allow the user to directly access the list via the get method.

Updating only some attributes of objects in cache

Let's say I have a class Item. Items have object attributes and collection of other objects attributes:
public class Item
{
//Object attributes
String name;
int id;
Color color;
//Collection of object attributes
List<Parts> parts;
Map<int,Owner> ownersById;
}
I have a fairly simple web application that allows crud operations on these items. This is split up into separate operations:
a page where you can update the simple object attributes (name, id...).
a page where you can edit the collection of parts.
a page where you can edit the map of owners.
Because the server load was getting too high, I implemented a cache in the application which holds the "most recently used item objects" with their simple attributes and their collection attributes.
Whenever an edit is made to the name of an item, I want to do the following do things:
Persist the change to the item's name. This is done by converting the item object to xml (without any collection attributes) and calling a web service named "updateItemData".
Update the current user's cache by updating the relevant item's nme inside the cache. This way the cache stays relevant without having to load the item again after persisting it.
To do this I created the following method:
public void updateItem(Item itemWithoutCollectionData)
{
WebServiceInvoker.updateItemService(itemWithoutCollectionData)
Item cachedItemWithCollectionData = cache.getItemById(itemWithoutCollectionData.getId());
cachedItemWithCollectionData.setName(itemWithoutCollectionData.getName());
cachedItemWithCollectionData.setColor(itemWithoutCollectionData.getColor());
}
This method is very annoying because I have to copy the attributes one by one, because I cannot know beforehand which ones the user just updated. Bugs arised because the objects changed in one place but not in this piece of code. I can also not just do the following: cachedItem = itemWithoutCollectionData; because this would make me lose the collection information which is not present in the itemWithoutCollectionData variable.
Is there way to either:
Perhaps by reflection, to iterate over all the non-collection attributes in a class and thus write the code in a way that it does not matter if future fields are added or removed in the Item class
Find a way so that, if my Item class gains a new attribute, a warning is shown in the class that deals with the caching to signal "hey, you need to update me too!")?
an alternative which might seem a bit overkill: wrap all the non-collection attributes in a class, for example ItemSimpleData and use that object instead of separate attributes. However, this doesn't work well with inheritance. How would you implement this method in the following structure?
classes:
public class BaseItem
{
String name;
int id;
}
public class ColoredItem
{
Color color;
}
There many things that can be done to enhance what you currently have but I am going to point out just two things that may help you with your problem.
Firstly, I am assuming that public void updateItem is a simplified version from your production code. So; make sure this method is thread safe, since it is a common source or problems when it comes to caching.
Secondly, you mentioned that
Perhaps by reflection, to iterate over all the non-collection
attributes in a class and thus write the code in a way that it does
not matter if future fields are added or removed in the Item class.
If I understand the problem correctly; then, you can easily achieve this using BeanUtils.copyProperties() here is an example:
http://www.mkyong.com/java/how-to-use-reflection-to-copy-properties-from-pojo-to-other-java-beans/
I hope it helps.
Cheers,

Java: No ArrayList modifications from outside classes

I use an ArrayList in one of my Java project's classes. The class keeps track of whether the list has been changed and offers public methods to add and remove elements from the list that automatically set the variable to "changed".
So far the list is public because I want my list to be publicly readable from everywhere. But I only want the class that owns the list to be able to modify it. So no modifications from outside classes. Is that possible? If so, how?
Usually for access control you'd probably use getter and setter methods. But even with a getter method and the list set to private another class could still do getList().remove(element) and thereby modify the list from the outside without the class noticing that the list was changed.
Make your ArrayList field private, but have your getter return Collections.unmodifiableList(list), which provides an unmodifiable view.
This will allow external code to treat it as a normal List, using for each loops and so on, but will disable modification operations. Additionally, unmodifiableList returns a view in constant time.
This is literally the exact use case it was designed for. Javadoc:
This method allows modules to provide users with "read-only" access to internal lists. Query operations on the returned list "read through" to the specified list, and attempts to modify the returned list, whether direct or via its iterator, result in an UnsupportedOperationException.
Make your List private and add getter method:
public List getList(){
return new ArrayList(yourPrivateList);
}
You can make the ArrayList member private, and instead of a getter that returns the ArrayList, have a getter that accepts an index i and returns the i'th element of the ArrayList.
public class Test
{
private List<String> list = new ArrayList<String>();
public getString (int i)
{
// you might want to add some validation of i here
return list.get(i);
}
}
getString allows the users of your class to access any element of the list without being able to modify it.
If you want to allow your users to iterate over the list without being able to modify it, you can add a getSize() method to return the size of the list (which would allow the users to iterate over the list using the regular for loop), or your class can implement Iterable (without supporting the remove operation).
You have couple of options here:
The getter that returns the ArrayList can clone before returning the object. This way, even if the outside entity modifies the object, they'll end up modifying the clone - not your original object. Note: The clone operation can be costly. I'd suggest the below option.
Use Collections.unmodifiableList(..). Check the documentation here.
Or as other answers suggest: roll out your own methods for access and iteration.
I think your best option here is to keep your List private and add a getter method that returns a copy of the List, but not the List itself. For example:
public class EncapsulationTest {
private List<Object> privateList = new ArrayList<Object>();
// Your constructors and methods to track list
// modification here ...
public List<Object> getList() {
// Maybe you need a null check here
return new ArrayList<Object>(privateList);
}
public void addElement(Object newElement) {
this.privateList.add(newElement);
// Set your 'changed' variable to true
}
public void removeElement(Object element) {
this.privateList.remove(element);
// Set your 'changed' variable to true
}
}
If you do this, you can still read an exact copy of the List, but you can't modify the List itself. Well, actually you can modify the returned List, but as it is a different object, the changes won't affect your object's List.
I hope it helps.

To initialize or not initialize JPA relationship mappings?

In one to many JPA associations is it considered a best practice to initialize relationships to empty collections? For example.
#Entity
public class Order {
#Id
private Integer id;
// should the line items be initialized with an empty array list or not?
#OneToMany(mappedBy="order")
List<LineItem> lineItems = new ArrayList<>();
}
In the above example is it better to define lineItems with a default value of an empty ArrayList or not? What are the pros and cons?
JPA itself doesn't care whether the collection is initialized or not. When retrieving an Order from the database with JPA, JPA will always return an Order with a non-null list of OrderLines.
Why: because an Order can have 0, 1 or N lines, and that is best modeled with an empty, one-sized or N-sized collection. If the collection was null, you would have to check for that everywhere in the code. For example, this simple loop would cause a NullPointerException if the list was null:
for (OrderLine line : order.getLines()) {
...
}
So it's best to make that an invariant by always having a non-null collection, even for newly created instances of the entity. That makes the production code creating new orders safer and cleaner. That also makes your unit tests, using Order instances not coming from the database, safer and cleaner.
I would also recommend using Guava's immutable collections, e.g.,
import com.google.common.collect.ImmutableList;
// ...
#OneToMany(mappedBy="order")
List<LineItem> lineItems = ImmutableList.of();
This idiom never creates a new empty list, but reuses a single instance representing an empty list (the type does not matter). This is a very common practice of functional programming languages (Scala does this too) and reduces to zero the overhead of having empty objects instead of null values, making any efficiency argument against the idiom moot.
I would rather prefer an utility like this:
public static <T> void forEach(Collection<T> values, Consumer<T> consumer) {
if (values != null) values.stream().forEach(consumer);
}
and use it in code like:
Utils.forEach(entity.getItems(), item -> {
// deal with item
});
My suggestion would be to not initialize them.
We ran into a situation where we initialized our collections, then retrieved same entity essentially twice successively. After the second retrieve, a lazy loaded collection that should have had data was empty after calling its getter. If we called the getter after the first retrieve, on the other hand, the collection did load the data. Theory is that the second retrieve got a managed entity from the session that had its collection initialized to empty and appeared to already be loaded or appeared to be modified, and therefore no lazy load took place. Solution was to NOT initialize the collections. This way we could retrieve the entity multiple times in the transaction and have its lazy loaded collections load correctly.
One more item to note: in a different environment, the behavior was different. The collection was lazy loaded just fine when calling the collection's getter on the entity that was retrieved the second time in the same transaction.
Unfortunately I don't have information on what was different between the two environments. It appears - although we didn't prove it 100% and didn't identify the implementations - that different JPA implementations work differently with respect to initialized collections.
We were using hibernate - just don't know which version we were using on each of the two platforms.

Categories