java generics - one impl class, multiple views - java

I have the interface defined as below and is implemented by a single class MatchedAddressImpl.
interface MatchedAddress extends HouseHelpData, StreetHelpData, TownHelpData
public class MatchedAddressDetails implements MatchedAddress
the client should be provided different views (HouseHelpData or StreetHelpData or TownHelpData or MatchedAddress) of the same MatchedAddressImpl. So I have provided the below API for the clients.
public List<MatchedAddress> matchedAddresses()
public List<? extends HouseHelpData> houseHelpData()
public List<? extends StreetHelpData> streetHelpData();
public List<TownHelpData> townHelpData();
the problem is that the client needs to do something like below and I read ineffective java that the return types should not contain wild cards as the client usage looks ugly...I appreciate it if someone can help me improve the API. what I want is to remove the wildcards from the above methods.
List<? extends StreetHelpData> streetHelpDataList = details.streetHelpData();

For most cases, the proper usage is simply List<StreetHelpData>. You would still be able to put objects of type StreetHelpDataImpl, for instance.
Wildcards are, in my opinion, misleading. Basically, for List<? extends StreetHelpData> it would mean: "This list contains elements all of a certain type, which is a sub-type of StreetHelpData."
Wildcard example:
Consider :
class Animal {}
class Lion extends Animal {}
class Tiger extends Animal {}
The list List<? extends Animal> contains either Lions only (List<Lion>), Tigers only (List<Tiger>), or both (List<Animal>). However, the list List<Animal> can contain all sorts of Animals - Lions and/or Tigers - at all times.
(Thanks to Tom Hawtin for his pointers)

Why do you need wildcards in your API to begin with? Get rid of them.
I'm guessing the reason you've done it that way is you've tried to do the following in your implementation:
public List<HouseHelpData> houseHelpData() {
List<MatchedAddressDetails> results = new ArrayList<MatchedAddressDetails>();
... // populate it
return results;
}
and you've got a compiler error. Java Generic Tutorial explains why the above is illegal - basically it's to prevent you from inadvertedly adding HouseHelpData implementation incompatible with MatchedAddressDetails to the list and then trying to access it (from the downcasted list) as MatchedAddressDetails instance. What you CAN do, however, is:
public List<HouseHelpData> houseHelpData() {
List<HouseHelpData> results = new ArrayList<HouseHelpData>();
...
results.add(new MatchedAddressDetails());
...
return results;
}
No wildcards necessary.
If that was not the reason for adding the wildcards to API, perhaps you can clarify your question and explain what was it.

Related

Java Generic Type extend multiple classes

How can the type for a generic class extend multiple classes? For example, say I have I generic that I want to be able to take objects that are subclasses of Melons or Berries, but not objects that are subclasses of other subclasses of Fruits?
I was thinking something like
public class MyGeneric<T extends Melons & Berries>
but this does not work as an interface is expected after the ampersand, not a class. Additionally, online I saw the suggestion to make an interface and have T implement the interface, however I do not understand how to make an interface that specifies classes that can be accepted by a generic.
& means and. T extends Melons & Berries means that T must be some type that extends both. You evidently want it to mean or. It doesn't. And <T extends Melons | Berries> is not legal java syntax. For good reason - that would be useless.
You may think: Wait, you can't extend 2 things. Yes, you can - extends in generics refers solely to supertypes; it's like a combination of extends and implements.
For example:
void test(List<? extends Serializable & CharSequence> items) {
}
can be invoked by passing a List<String>. That's because String is a subtype of Serializable, and also a subtype of CharSequence.
The 'point' of this is that when you get an element from this list, you can treat it as either. Because it's and - it's a list of both.
There is no way in java to say: "I want to accept a list of Berries, or a list of melons, but not a list of Apples". The reason there's no way to say that, is because its useless:
If there's a thing you can do to both melons and berries but not bananas, then whatever it is will have to be defined in an interface of sorts. Perhaps Melons and Berries both implement 'SeededFruit', and Banana doesn't. In that case, just write List<? extends SeededFruit> isntead.
If you just want to use aspects of melons and berries that are shared by all fruit (also bananas), just write List<? extends Fruit> - why put up arbitrary restrictions?
If you want to write if (x instanceof Melons) doThing1; else if (x instanceof Berries) doThing2; - java isn't 'meant' for that. There are tons of things java doesn't have that would be really convenient if everybody wrote code like that. But java doesn't have that, will not have that, folks don't usually write their java code like that. Usually if someone does, they're writing very 'bad' code, in the sense that it is overcomplicated and/or hard to maintain and/or hard to adopt in the face of changing requirements, and needlessly so: You could write it differently and avoid those traps.
The way I would do is to group the classes using an interface. Then I use the interface to define the generic class. See below:
interface ForGenerics { }
class Fruit { }
class Melon extends Fruit implements ForGenerics {}
class Berry extends Fruit implements ForGenerics {}
class Apple extends Fruit {}
class MyGeneric<T extends ForGenerics> { }
public class Main{
public static void main(String[] args) {
MyGeneric<Melon> a;
MyGeneric<Berry> b;
// can't make MyGeneric of Apple
// MyGeneric<Apple> c;
}
}

Java: Generics on data structures and wildcards

I'm trying to learn how to use generics and for that, I'm creating my own data structure similar to a list with an Iterator and all.
The uppermost class is declared as:
public class BasicList<A> implements Iterable {
}
It's just a list with nodes and a single pointer to the next element.
There's another list, called DescendingList, that does pretty much the same, only this time around, you're getting another output since the Iterator is different. I'm giving a comparator to this List to get the Iterator to work. The comparator is just an interface:
public interface Bigger<A> {
boolean bigger(A x);
}
DescendingList looks like this:
public class DescendingList<A extends Bigger<A>> extends BasicList<A> implements Iterable {
}
The idea is that it could work with any kind of object that is comparable through the Bigger interface.
Now I have an abstract class:
public abstract class Rock implements Bigger<Rock> {
}
And finally, a normal class which extends the Rock class:
public class Mineral extends Rock {
}
So, the issue at hand is that, while I can easily create a new BasicList filled with Minerals like this:
BasicList<Mineral> min = new BasicList<Mineral>();
I can't do the same with the DescendingList. Whenever I try going with
DescendingList<Mineral> min = new DescendingList<Mineral>();
my IDE (IntelliJ) goes all
"Type parameter "Rock" is not within it's bound; should implement Bigger<Mineral>"
And I don't really get why that happens. I am pretty sure that I've messed up the type parameters somehow and I'm really not sure where. This should be solveable somehow (at least without removing any classes/interfaces - the class headers might be and probably are completely messed up). Thanks in advance for any help you might offer.
A Mineral isn't a Bigger<Mineral>, it's a Bigger<Rock>, and that is incompatible with Bigger<Mineral>, because even though a Mineral is a Rock, Java's generics are invariant. It needs to be a Bigger<Rock> because of how Rock is defined -- implementing Bigger<Rock> -- and that DescendingList declares type parameter A to be a Bigger<A>.
Because it's a consumer (type parameter as a method parameter), the type parameter A needs a lower-bound (super) on its declaration.
class DescendingList<A extends Bigger<? super A>> // ...
This way Mineral will be within its own bound.
As an aside, you are implementing the raw form of Iterable in BasicList; you should supply a type argument there.

Adding subclass to list - The method add(capture#2-of ? extends TopBean)...not applicable for the arguments (TopBean)

I've asked this question before but never got a solution what to do.
I am trying to add a subtype to a list defined as follows. This should be 100% legal, the subtype extends the main type.
private List<? extends TopBean> beans;
public List<? extends TopBean> getBeans() {
return beans;
}
I am trying to do this:
this.getBeans().add(new SecondaryBean());
SecondaryBean extends TopBean (not directly but at some level).
This is driving me nuts - the error is
The method add(capture#2-of ? extends TopBean) in the type List<capture#2-of ? extends TopBean> is not applicable for the arguments (SecondaryBean)
If I cast it to TopBean, same error, just diffent wording
The method add(capture#2-of ? extends TopBean) in the type List<capture#2-of ? extends TopBean> is not applicable for the arguments (TopBean)
I must add a child SecondaryBean into the List of generic TopBeans. What to do here?
you can't add any non-null to wild cards defined this way.
if you would have defined it
List<? super TopBean>
then adding anything extending TopBean was possible but getting was a different story - only things that TopBean extends or implements
I don't understand why you define your list as a wildcard at the first place, defining it as List seems to give you everything you need. methods sometimes should be defined with wikdcards but not the data members
Basically your declaration is wrong. Don't use wild cards in a variable declaration or a return type. Only use wildcards for method parameters.
private List<TopBean> beans;
public List<TopBean> getBeans() {
return beans;
}
There could be a lot of reasons and discussion why you don't use wild cards anywhere but method parameters, but that's my personal general rule. It's overly simplistic but will cover 90% - 99% of all real world use of generics in Java.
Now with the above code I've given, you can add a TopBean to your list, or any subclass of TopBean.
I fixed this issue. With the below cast, the error went away (there's a warning but I can live with that).
((List<SecondaryBean>)this.getBeans()).add(new SecondaryBean());
I am guaranteed to have a List of SecondaryBeans, so this is safe.

Confused by the following data type

List<? extends List<? extends ObservationInteger>>
Just to give you a background which probably has nothing to do with the question. Trying to use the JAHMM library to build and score HMM's.
One of the parameters to the functions mentions the above as the datatype and I have no idea what it means.
From what I understand with help from a friend
List<? extends ObservationInteger> means a List of instances of any classes extending "ObservationInteger" which is a valid class in the library.
It is the outer List<? extends List<?... that is confusing me.
Can someone throw some light on this?
List<? extends List... means that it can be List of any Collections implementing List interface.
List<List<? extends ObservationInteger>> list = new ArrayList<List<ObservationInteger>>(); - compiler error because without ? extends compiler requires exact match:
List<List<? ObservationInteger>> list = new ArrayList<List<? extends ObservationInteger>>(); - OK
but this looks better
List<? extends List<? ObservationInteger>> list = new ArrayList<List<ObservationInteger>>(); - OK
It means any Class implementing List Interface with instances of any Class implementing List Interface with instances of any classes extending "ObservationInteger"
It is a List of Objects, which are all instances of a class that extends List.Because those objects are instances of Lists, each of them happens to contain a certain amount of Objects, which are all instances of a class that extends ObservationInteger.
It's a list of lists of things. Visualize it as a two-dimensional structure (rows & columns).
The ? extends means it is also valid for any subtypes of List and any subtypes of ObservationInteger.

Java Generics - explanation needed

I have a question about Java Generics. In code below we have interface B parametrized by another type that must implement interface A.
This code is correct.
Question is: why it does not work with following list() method declaration?
private <X extends A, Y extends B<X>> List<Y> list()
Working code:
public interface A {
}
public interface B<T extends A> {
}
public class Test {
private static class AA implements A {}
private static class BB implements B<AA> {}
private <R extends A, X extends R, Y extends B<X>> List<Y> list() {
return null;
}
private void test() {
List<BB> l = list();
}
}
EDIT:
I've reworked the code. Now we have bird paremetrized by sound it can make. Question is why useless_t is necessary?
public class Test {
public interface Sound {
}
public interface Bird<T extends Sound> {
}
private static class Quack implements Sound {}
private static class Duck implements Bird<Quack> {}
private <useless_t extends Sound, sound_t extends useless_t, bird_t extends Bird<sound_t>> List<bird_t> list() {
return null;
}
private void test() {
List<Duck> l = list();
}
}
My Eclipse IDE does not compile any of your code examples as is. But they do compile when given additional type hints. In the second example, with or without the type parameter useless_t, the following line does not compile for me:
List<Duck> l = list();
But the following does compile for me:
List<Duck> l = this.<Sound, Quack, Duck> list();
With the useless_t factored out, the following compiles, too:
List<Duck> l = this.<Quack, Duck> list();
So it is basically a matter of the compiler not getting the type parameters right, and you need to give the types explicitly.
UPDATE : If you really came across a program where adding the useless_t made a difference, you are on unsafe terrain, and rely on unspecified compiler behaviour.
You ran into an issue where different compilers behave differently, namely Type Inference. The JLS is not entirely clear on where a compiler must infer types, and where it must refuse to infer, so there is wiggle room here. Different versions of the Eclipse compiler and different versions of javac differ in where they do infer types. For javac, this is true even when comparing different 1.5.0_x versions, and the Eclipse compiler usually can infer more than javac.
You should only rely on type inference where all common compilers succeed, and otherwise give type hints. Sometimes, that is as easy as introducing a temporary variable, but sometimes (as in your example) you must use the var.<Types>method() syntax.
Regarding the comment: what if i want method Duck.getSound() to return Quack, not Sound using generics?
Assume the Bird interface had the following method:
public interface Bird<T extends Sound> {
T getSound();
}
Then you could implement it like so:
private static class Duck implements Bird<Quack> {
public Quack getSound() { return new Quack(); }
}
This is one use case for generics - allow implementations to specify concrete types, so that even the superclass can use that type. (The Bird interface could have a setSound(T), or do other stuff with T, without knowing the concrete type of T.)
If a caller only knew that an instance was of type Bird<? extends Sound>, he would have to call getSound like so:
Sound birdSound = bird.getSound();
If the caller knew about Quack, he could perform an instanceof test. But if the caller knew that the bird was really a Bird<Quack>, or even that is was a Duck, then he can write this and it compiles as desired:
Quack birdSound = bird.getSound();
But beware: Generifying too many types used in the interface or superclass brings the risk of overcomplicating the system. As Slanec wrote, Rethink your real design to see whether it's really needed to have so many generics.
I once went too far, and ended up with a interface hierarchy and two implementation hierarchies, based on interfaces like this:
interface Tree<N extends Node<N>,
T extends Tree<N, T>> { ... }
interface SearchableTree<N extends SearchableNode<N>,
S extends Searcher<N>,
T extends SearchableTree<N, S, T>>
extends Tree<N, T> { ... }
I do not recommend to follow that example. ;-)
I'd say: AA implements A, by defining List<AA> l = list() you expect it to extend B<X> which it does not. Anyway, you see how easly you get confused by writing such code. This is just TOO complex.
You have a slight misunderstanding of Java Generics. The thing to remember, and this is a subtle thing, a List<Y> is not about the contents of the list, but a modification of the list itself.
Let's extrapolate a little bit; say I have interface Animal and interface Dog extends Animal and interface Cat extends Animal. (I'll just invent more classes and interfaces as we go along.) Now if I declare a method that returns animals as List<Animal> createList(), there's nothing wrong with the following code:
List<Animal> litter = createList();
Cat tabby = new Tabby();
litter.add(tabby);
Dog poodle = new Poodle();
litter.add(poodle);
That's because a Dog is an Animal, and a Cat is an Animal; the method signature of add on type List<Animal> is add(Animal); we can call add with any valid instance of Animal, as expected. But the type parameter on List does not modify or restrict the contents of the list, it modifies the type of the list itself; and a "list of cats" is not a "list of animals", neither is a "list of dogs". Even if the createLitter() method actually returns a new ArrayList<Animal>() that contains only instances of Parrot, the above code is fine. What you cannot do however is 'narrow' the type of the list. For example, this is a compile error:
List<Bird> birds = createList(); // does not compile
Imagine if it were allowed, and createList returned a "list of animals" that contained our tabby; the following would result in a class cast exception:
Bird leaderOfTheFlock = birds.get(0);
You also cannot 'widen' the type of list. Imagine if it were possible:
List<Object> things = createList(); // does not compile
The reason this is not allowed either is that code could now add a new Integer(0) to things - because an Integer is an Object. Clearly that's not what we want either, and for the same reason - a "list of animals" is not a "list of objects". The type parameter "Animal" on List<Animal> modifies the type of the list itself, and we are talking about two distinct types of lists. This leads us to the first consequence of that point - generic types do not follow the inheritance (is-a) hierarchy.
Without knowing more of what you want to do it's hard to go from here and stay relevant. I don't mean to be harsh, but it looks like you started throwing generics at your code to see if something would work. I struggled for years with Generics. Even after running across a blog that explained this subtle point I had to recreate quite a few variations of the above to reinforce the lesson, looking for various ways I would end up with a class-cast-exception if I broke the rules. Likely the solution to your problem is that other parts of the code are not well defined with respect to the strict type system you are trying to introduce, and the generics problems you see are only a symptom of that. Try to reduce the generics and rely more on composition and inheritance. I still shoot myself in the foot occasionally by going off the generic deep end. It's also helpful to try and remember the point of generics is not to eliminate casts, but to make type information available to the compiler as an aid to verifying the correctness of how your code deals with the types; or in other words it turns runtime errors (class cast) into source / compile-time errors, so it is important to try to keep in mind the distinction between what type information you have at compile-time (which is limited, even with generics) and what type information you have at runtime (which is the full type information of the instances).

Categories

Resources