How to override addAll function in Java? - java

For instance I have two Arraylists with different data types.
ArrayList<Integer> intValues = new ArrayList<Integer>();
intValues.add(1);
intValues.add(2);
intValues.add(3);
ArrayList<String> strValues = new ArrayList<String>();
strValues.add("4");
strValues.add("5");
strValues.add("6");
If both of these lists contained the same data type objects, I would easily call addAll function;
intValues.addAll(intValues2);
But of course if I try to call addAll function with these different type lists, compiler warns me with incompatible types: ArrayList cannot be converted to Collection<? extends Integer> warning.
So I have to create a bad solution like;
for(String s: strValues)
{
intValues.add(Integer.parseInt(s));
}
Is there a better way to do this, I mean, creating a class which implements List, overriding addAll function etc. so I will be able to call;
intValues.addAll(strValues);
And intValues list will contain 1,2,3,4,5,6.
Edit: I really don't want to store String values in an Integer array, I have to deal with some creepy old code at the moment and I need a Collection to hold some differend kinds of classes, trying to create a Constructor for those objects, this integer-string scenario is just a simple way to introduce my problem.
Let me tell you about my current situation with another integer-string like scenario:
Creepy class A is car, it holds car's weight, price, color, engine type.
Creepy class B is watch, it holds watch's still type, movement type, price, lug size etc.
I am trying to create a holder class, so it will hold those classes and adding a few functions (for example, overriding compare method makes the holder class to compare prices of different classes).
Now I think I have to create a HolderHolder class which implements List so I can call holderHolder.addAll(carsList) and holderHolder.addAll(watchesList), and it will hold these as Holder objects and yes, this does not look pretty.

You act as if what you want is self-evident and logical. It really isn't. "4" and 4 are entirely unrelated, and expecting that your list of integers now has a value 4 when you call addAll with "4" is, as a consequence, as bizarre as expecting your list of movies to gain 'Forrest Gump' when you call .addAll(colorsOfTheRainbow) on that, because in your mind, 'green' is so incredibly similar to 'Forrest Gump', that you might as well assume that. (Here, 'green' is "4" and 'Forrest Gump' is 4).
So let's do some work and make this more sensible:
That 'assumption' (that "4" is so similar to 4, that you want .add("4") to just mean that 4 shows up in your list) needs to encoded, explicitly, in your code. Now it makes sense, and now you can write a function that maps Green to Forrest Gump and use it for that example just the same - we've generalized the principle.
What you're really talking about is a mapping function that maps an element of your List<String> (so.. a String) to a type that your target list is of (Integer), and you then want the operation: Take this list. Map every value in it with my mapping function. Then, add all the mapped values to this other list.
That makes perfect sense.
So, write that.
List<Integer> intValues = ...;
strValues.map(Integer::valueOf).forEachOrdered(intValues::add);

Looks like bad smell.
One bad Solution can be an own implementation of an List with Type Object. But than you have to cast and work with the Classes of the primitive types.
I think i every case you have to parse or cast. That cost to much of performance just for easy call of addAll.
I would think about the incoming data and why they have to be the same but in different types?
Edit:
If i get to know it correct. It is a little bit hard to understand without more detailed infos.
But maybe you can write an mapper class to map thoose old creepy classes in one new class an then you can put these new class in an collection and can compare all by overriding equals.
public class CreepyClassMapper
{
public CreepyClassMapper(Car aCar, Watch aWatch)
{
}
#override
private boolean equals(Object obj)
{
// maybe add an instance check
CreepyClassMapper other = (CreepyClassMapper) object;
// do your compare stuff
return true;
}
}

if i were you, i will create a function like this in util class
public void append(ArrayList<Integer> intValues, ArrayList<String> strValues){
}

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.

Calling a subclass method from an ArrayList of type superclass in Java

I am trying to understand polymorphism, and the best practice when working with inheritance through subclasses and superclasses. I have three classes: Items, Books, and DVDs. Items is the superclass, where Books and DVDs are the subclasses that extend Items.
At first, I tried storing new objects of type Book and DVD in an array list of type Items, which worked fine.
ArrayList<Items> library = new ArrayList<Items>;
library.add(new DVD(...));
library.add(new Book(...));
The problem occurrs when I tried calling a method getRuntime from the DVD subclass. This would return the run length of the DVD. I can't move this method to the Items superclass and it would not be applicable to a book.
library.get(0).getRuntime();
I can understand why I get an error, the object in the array list is stored of the type Items, and can only access the methods in the Items class. So one option is to cast to the right subclass type:
((DVD) library.get(0)).getRuntime();
But what if I am calling many methods from the subclass, would I have to cast each time? Also, is using cast like this considered bad practice?
My other option would be to create two seperate array lists for each subclass:
ArrayList<DVD> libraryDvds = new ArrayList<DVD>;
ArrayList<Books> libraryBooks = new ArrayList<Books>;
Does this not defeat the point of polymorphism though? Furthermore, say I now wanted to print a list of all my items, I'd have to call both array lists rather than just one that holds them all.
Thanks for any help, I can provide more detailed code examples if needed.
If getRuntime is really specific to DVD then the cast is the only way to go. You will need to cast each time needed.
Before casting, good practice would be to check type before (using instanceof), or catch ClassCastException.
But a more elegant way could be to have a list of DVD instead of a list of Items. You could also have a list of items if you need it.
ArrayList<Items> library = new ArrayList<Items>; // list to use when processing the whole library
ArrayList<DVD> libraryDvds = new ArrayList<DVD>; // list to use when processing only DVDs
I don't think you are defeating the point of polymorphism by doing this because you are doing specific actions only for DVD, so the function you want to implement is not polymorphic.
A last solution, if you really want to use polymporphism here would be to declare getRuntime() on Item and write an implementation in Book that would do return an instance of Runtime which does nothing.

Should we use the topmost parent class as a type of reference variable?

I have seen some people using the topmost parent class as a variable type to hold the child instance and some people use just parent class only. For example:
Collection obj = new ArrayList();
Or
List obj = new ArrayList();
Here, List comes under the Collection only then can’t we use above first line instead of second?
Again, we can't use everywhere in collection framework the reference variable of Collection class only to hold any instance of the class under Collection?
Is this a good practice?
So, I wanted to know which comes under the best practices and why?
If someone could justify technically like performance concerns etc. would be greatly appreciated.
It really really depends on your needs. In your example it doesn't really changes much for basic needs but if you inspect the two interfaces there are some changes. Look :
https://docs.oracle.com/javase/7/docs/api/java/util/Collection.html
and
https://docs.oracle.com/javase/7/docs/api/java/util/List.html
We can notice that the List gives you access to methods Collection doesn't.
set(int index, E element) for instance is defined in the List interface and not in Collection.
This is because every classes inheriting from Collection don't need to implement all the same methods.
Performance wise it have no impact.
Always use the top-most parent class that have all the functionalities you need. For your example there is no need to go higher than List .
There is no so called "best practice" for choosing the class to be used for the reference type. In fact, the class in the highest hierarchy is the Object class. Do you use Object as the reference type for everything you do? No, but generally you may choose the higher class with the all the methods available for your needs.
Instead of following the so called "best practice", apply what suits best for your situation.
These are some pros and cons for using higher hierarchy classes as reference type:
Advantage
Allows grouping of object which shares the same ancestor (super class)
Allows all instances of the given class to be assigned to it
Animal dog = new Dog();
Animal cat = new Cat();
Allows polymorphism
dog.makeNoise();
cat.makeNoise();
It is only an advantage when you are accessing common behaviours or members.
Disadvantage
Requires casting when you are accessing behaviours which exist in one object but not the other.
dog.swim(); //error, class Animal do not have swim()
((Dog)dog).swim();
As you start dumping various objects in the common parent class, you may have a hard time trying to figure out which members belongs to which class.
(Cat(cat)).swim(); //error, class Cat do not have swim()
The general idea is hiding as much as you can so things are easier to change. If you need indexing for instance (List.get(int index) then it MUST be a list because a collection does not support .get(index). If you don't need indexing, then hiding the fact you're using a list, means you can switch to other collections that might not be a list later without any trouble.
For example, maybe one month later I want to use a set instead of list. But Set doesn't support .get(index). So anybody who uses this List might use the indexing features of a list and it would make it difficult to switch to a set because every where someone else used .get(), would break.
On the other hand, excessively hiding your types can cause accidental performance issues because a consumer of your method didn't know the type. Suppose you return a List that's actually a linkedlist (where indexing is O(n)). Suppose the consumer of this list does a lookup for each entry in another list. That can be O(n*m) performance which is really slow. If you advertised that it was a linked list in the first place, the consumer of the linkedlist would realize that it's probably not a good idea to make multiple indexes into this list and the consumer can make a local copy.
Library code (suppose the one you're designing)
public class Util {
public static List<String> makeData() {
return new LinkedList(Arrays.asList("dogs", "cats", "zebras", "deer"));
}
}
Caller's code (suppose the one that's using your library or method)
public static void main(String [] args) {
List<String> data = Util.makeData();
int [] indicesToLookUp = {1,4,2,3,0};
for( int idx : indicesToLookUp ) {
if(idx < data.size()) {
// each index (LinkedList.get()) is slow O(N)
doSomethingWithEntry(idx, list.get(idx));
}
}
}
You could argue it's the caller's fault because he incorrectly assumed the List is an ArrayList<> and should have made a local copy of the list.

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)

What is the difference between creating instance by extending superclass and by extending its own class?

For example:
List<String> list = new ArrayList<String>();
vs
ArrayList<String> list = new ArrayList<String>();
What is the exact difference between these two?
When should we use the first one and when should we use the second?
Use the first form whenever possible (I would even say: use Collection if sufficient). This is especially important when accepting input from client code (method arguments). Sometimes, for the convenience of the client code/library user it is better to accept the most generic input you can (like Collection) and deal with it rather than forcing the user to convert arguments all the time (user has LinkedList but the API requires ArrayList - terrible).
Use the second form only when you need to invoke methods on list variable that are defined in ArrayList but not in List (like ArrayList.trimToSize()). Also when returning data to the user consider (but this is not the rule of thumb) returning more specific types. E.g. consider List over Collection so the client code can easier deal with the result. However! Returning too specific types (e.g. ArrayList) will lock your implementation for the future, so try to find a compromise.
This is a general rule - use the most general type you can. Even more general: use common sense.
List is not a superclass, it is an interface.
By using List rather than ArrayList, you make sure that users of your list will only use methods that are defined on List. Meaning that you can change the implementation to (for example) Vector, without breaking the existing code.
So, use the first form.
The first form is the most desirable one because you hide the implementation (ArrayList) from the rest of your code and ensure your code only works with the abstraction (List). The advantage of this is that your code will be more generic and therefore easier to adapt, for example when you change from using an ArrayList to a LinkedList, Vector or own List implementation. It also means local changes are less likely to cause changes in other parts of your code ('ripple-effect'), increasing your code's maintainability.
You need the second form when you want to do things with your variable that are not offered by the List interface, for example ensureCapacity or trimToSize
EDIT: extra explanation of changing the implementation
Here is an example of declaring a variable as a Collection (an even more generic interface in java.util):
public class Example {
private Collection<String> greetings = new ArrayList<String>();
public void addGreeting(String greeting) {
greetings.add(greeting);
}
}
Now suppose you want to change the implementation in order to store unique greetings, and therefore switch from ArrayList to HashSet. Both are implementations of the Collection interface. This would be easy in this case because all the existing code treats the greetings field as a Collection:
public class Example {
private Collection<String> greetings = new HashSet<String>();
public void addGreeting(String greeting) {
greetings.add(greeting);
}
}
There is an exception. If there is code which casts the greetings field back to its implementation, this makes that code 'implementation-aware', violating the information-hiding you tried to achieve, for example:
ArrayList<String> greetingList = (ArrayList<String>) greetings;
greetingList.ensureCapacity(42);
Such code would cause a runtime error 'java.lang.ClassCastException: java.util.HashSet incompatible with java.util.ArrayList' if you change the implementation to HashSet, so this practice should be avoided if possible.
There are some advantages of using interfaces against concrete classes:
You are not stuck to concrete implementation (you can easy change it without modifying code)
Your code is clearer as no methods of concrete class are available
You need concrete implementation only in case if you USE some features of it.
E.g. we have Matrix interface and have two concrete implementations SparseMathix and FullMatrix. If you want to effectively multiply them you CAN use some implementation details of SparseMatrix otherwise performance MAY be too slow.

Categories