How can I implement my own generic collection in java? - java

I have an inteface 'MyCollection' with just two methods : addAll and containsAll which take as a parameter a generic collection. How can I effectively implement these methods in my class so that they would work on any type of collection.
This is what I've done so far :
The interface:
interface MyCollection<T extends Collection> {
boolean containsAll(T c);
boolean addAll(T c);
}
My class where I implement the methods:
public class MyPersonalCollection<E extends Collection> implements MyCollection {
private E myCollection;
public MyPersonalCollection(E myCollection) {
this.myCollection = myCollection;
}
public boolean containsAll(Collection c) {
return myCollection != null && myCollection.containsAll(c);
}
public boolean addAll(Collection c) {
return myCollection != null && myCollection.addAll(c);
}
}
And the tests:
#Test
public void testIfNewCollectionCanBeAdded() {
ArrayList<String> input = new ArrayList<>();
MyPersonalCollection<ArrayList<String>> myCollection = new MyPersonalCollection<>(input);
input.add("first");
input.add("secon");
input.add("third");
assertTrue(myCollection.addAll(input));
}
#Test
public void testIfMyCollectionContainsAnotherCollection() {
LinkedList<String> list = new LinkedList<>();
MyPersonalCollection<LinkedList<String>> myCollection = new MyPersonalCollection<>(list);
list.add("bacon");
list.add("tuna");
list.add("steak");
assertTrue(myCollection.addAll(list));
}
I also get a warning : Unchecked call to 'containsAll(Collection) as a member of raw type 'Java.Util.Collection" in my class when I call the methods containsAll() and addAll().
So how can I tackle this problem ? Many thanks in advance !

Both E and T extend Collection, but you want to treat a Collection as T in MyCollection in this line:
return myCollection != null && myCollection.containsAll(c);
Which can be wrong because every Collection is not from type T.
Anyway if you are sure that this type casting is safe, simply ignore it and use
#SuppressWarnings("unchecked")
to suppress that warning.

The problem is that you have to define 2 generic:
C for the kind of collection
E for the content of the collection
I fixed your code, now there is no warnings
interface MyCollection<C> {
boolean containsAll(C c);
boolean addAll(C c);
}
public class MyPersonalCollection<E, C extends Collection<E>>
implements MyCollection<C> {
private C collection;
public MyPersonalCollection(C myCollection) {
this.collection = myCollection;
}
public boolean containsAll(C c) {
return collection != null && collection.containsAll(c);
}
public boolean addAll(C c) {
return collection != null && collection.addAll(c);
}
}
You can use your class in the test like this:
MyPersonalCollection<String, LinkedList<String>> myCollection =
new MyPersonalCollection<String, LinkedList<String>>(list);

Related

Convert a method to a generic one to avoid duplicate code

I need some help with the following: I have multiple calls to a method that look like this:
private void saveA(myObjA myObj, List<A> myList) {
if (myList != null && !myList.isEmpty()) {
myObj.saveAll(myList);
}
}
private void saveB(myObjB myObj, List<B> myList) {
if (myList != null && !myList.isEmpty()) {
myObj.saveAll(myList);
}
}
...
Example of interface:
public interface myObjA
extends JpaRepository<A, Long> {
}
public interface myObjB
extends JpaRepository<B, Long> {
}
...
The thing is I'm creating a new one for all the other calls (myObjB, myListB, myObjC, myListC). myObj is actually an interface and the second parameter is always a list of some object. Is there any way to convert this method to a single one and specify the object type in the call?
This can be done using generic method:
public <T, N> void save(JpaRepository<T, N> repo, List<T> list) {
if (null != list && !list.isEmpty()) {
repo.saveAll(list);
}
}
// usage
#Autowired
private MyRepo repository; // MyRepo implements JpaRepository<MyObj, Long>
public void foo(List<MyObj> list) {
save(repository, list);
}

Java - Generics - Casting generic object in generic specified object doesn't work

I'm trying to resolve this apparently simple generic casting problem :
First, declaring this simple generic object :
public interface GenericObject<T> {}
Second, declaring this working interface :
public interface Generic { // I don't want to do Generic<T>
<T> void setGenericObject(GenericObject<T> obj);
}
Then, let's implements this interface :
public class GenericImpl implements Generic {
private GenericObject<String> genericObject; // This is needed
#Override
public <String> void setGenericObject(GenericObject<String> obj) {
genericObject = obj; // eclipse give me this error :
// Type mismatch: cannot convert from
// interfaces.GenericObject<String> to
// interfaces.GenericObject<java.lang.String>
}
}
How can I solve this error ?
Edit :
Actualy, the only way I have to solve this issue is to do this :
public class GenericImpl implements Generic {
private GenericObject<String> genericObject;
#SuppressWarnings("unchecked") // I don't realy like this
#Override
public <T> void setGenericObject(GenericObject<T> obj) {
genericObject = (GenericObject<String>) obj;
}
}
The real problem is that
public <String> void setGenericObject(GenericObject<String> obj)
where the String has nothing to do with the your intended java.lang.String. Here the String is just a type parameter whose name is String by accident.
Please refer to Is it possible to have an interface method defined with a generic return type and a concrete implementation define the return type?.
Case 1:
If T is not used in Generic, then just use a wildcard.
class Generic {
List<?> list;
void set(List<?> list) {
this.list = list;
}
int size() {
return list.size(); // doesn't care about T
}
}
Case 2:
If T is only used as local variables, then declare <T> on the method
class Generic {
<T> void swapFirstAndSecond(List<T> list) {
T first = list.get(0), second = list.get(1);
list.set(1, first);
list.set(0, second);
}
}
Case 3:
If several fields and methods use the same type T, but the exact type of T is not important, then delacre <T> on the class
class Generic<T> {
List<T> list;
void set(List<T> list) {
this.list = list;
}
T getFirst() {
return list.get(0);
}
}
Case 4:
If T must be a specific type, like String, then don't declare type parameter <T>
class Generic {
List<String> list;
void set(List<String> list) {
this.list = list;
}
boolean isFirstContainsSecond() {
String first = list.get(0), second = list.get(1);
// call String.contains here, so T must be String
return first.contains(second);
}
}

Make a copy of a List with abstract type to a List with specific type

first of all my code below just delivers an abstract view of my classes so that you can easily understand what my question is about :) -so also no equals, hashcode.
I have an ABC extended from Observable which has a List of AbstractObservers
Then I have some classes B and C inherit from AbstractObservers. AbstractObservers implements Observer.
The focus is now at the Recover class.
With the method recover() I try to return a List with the concrete type (B or C) instead of AbstractObservers.
I am not satisfies with my solution, I think it could be better, easier?
Have you any idea how I could solve that problem better? The Abstract classes must stay due to Hibernate.
Thank you in advance
public abstract class ABCObservable extends Observable {
List<AbstractObserver> abstractObserverList = new LinkedList<>();
public List<AbstractObserver> getAbstractObserverList() {
return abstractObserverList;
}
#Override
public synchronized void addObserver(Observer o) {
super.addObserver(o);
abstractObserverList.add((AbstractObserver) o);
}
}
AbstractObserver
public abstract class AbstractObserver implements Observer {
#Override
public void update(Observable o, Object arg) {
}
}
B
public class B extends AbstractObserver {
}
C
public class C extends AbstractObserver {
}
Recover
public class Recover {
public List<? extends AbstractObserver> recover(ABCObservable abcObservable) {
List<AbstractObserver> returnList = new LinkedList<>(); //does that delivers a List with AbstractObserver or B or C?
if (abcObservable.getAbstractObserverList().get(0) instanceof B) {
returnList = new LinkedList<>();
returnList.addAll(abcObservable.getAbstractObserverList());
} else if (abcObservable.getAbstractObserverList().get(0) instanceof C) {
returnList = new LinkedList<>();
returnList.addAll(abcObservable.getAbstractObserverList());
}
return returnList; // returns a List with B or C elements
}
}
In Java, you can't convert a list to a new type, what you can do, however, is create a new one and add the values to it. If you use a generic method, you should be able to accomplish this. I haven't test this code, but theoretically it should work:
public <T> List<T> recover(T abcObservable) {
List<AbstractObserver> list = abcObservable.getAbstractObserverList();
List<T> returnList = new LinkedList<>();
returnList = new LinkedList<>();
for(AbstractObserver a : list) {
if(a instanceof T) {
returnList.add(a);
}
}
return returnList;
}
Instead of using a defined class, this snippet uses T, you can find out more about how Java Generic Methods work on this Java Tutorial by Oracle.
EDIT: I think I'm confused about what you are asking for, this doesn't answer your question, if I understand it correctly.

how to pass objects and list dynamically in a method?

I have used below method to check record present in the table.
private static boolean isPresent(StuPersonal object, List<StuPersonal> list)
{
for (StuPersonal candidate : list) {
if (candidate.getFRID().equals(object.getFRID()))
{
return true;
}
}
return false;
}
here StuPersonal is a class and list is a list of class StuPersonal. I need to reuse this method for different classes. How can I do it? I have StuDegree,StuContact,StuCollege,etc and its lists. The process must be done when I pass the classes object and its list. Please advise..
If all of these classes have a getFRID() method, then that should be in an interface (e.g. Identified). Then you can use:
private static <T extends Identified> boolean isPresent(T object, List<T> list) {
String frid = object.getFRID(); // Adjust type appropriately
for (Identified item : list) {
if (item.getFRID().equals(frid)) {
return true;
}
}
return false;
}
Alternatively, as a non-generic method - slightly less safe as it means you can try to find a StuPersonal within a List<StuContact> or whatever:
private static boolean isPresent(Identified object, List<? extends Identified> list) {
String frid = object.getFRID(); // Adjust type appropriately
for (Identified item : list) {
if (item.getFRID().equals(frid)) {
return true;
}
}
return false;
}
Consider using Iterable instead of List, too.
Let each class define equals() method. And then you can just do list.contains(object) which will return boolean. This is the most preferred solution.
<S extends Stu>boolean isPresent(S object, List<S> list) {
for (StuPersonal candidate : list) {
if (candidate.getFRID().equals(object.getFRID())) {
return true;
}
}
return false;
}
where type Stu is a common superclass or interface of types StuDegree,StuContact,StuCollege,etc, which has method getFRID().

Call java collections use an interface of an object instead of the object's class?

I want to call a method using a collection of objects that all implement the same interface. Is this possible?
public class GenericsTest {
public void main() {
ArrayList<Strange> thisWorks = new ArrayList<>();
isAllStrange(thisWorks);
ArrayList<Person> thisDoesNot = new ArrayList<>();
isAllStrange(thisDoesNot);
}
public boolean isAllStrange(ArrayList<Strange> strangeCollection) {
for (Strange object : strangeCollection) {
if (object.isStrange())
return true;
}
return false;
}
public interface Strange {
public boolean isStrange();
}
public class Person implements Strange {
public boolean isStrange() {
return true;
}
}
}
You can do this using the <? extends Interface> notation:
public boolean isAllStrange(List<? extends Strange> strangeCollection) {
for (Strange object : strangeCollection) {
if (object.isStrange())
return true;
}
return false;
}
Also, do not use ArrayList directly, instead use List. More of this:
Bounded Type Parameters
What does it mean to "program to an interface"?
Read about WildCard in Genrics.
You can do this using
<? extends Strange >

Categories