I have been using a Collection of number values and have implemented some related functionality (mapping x->y values, etc). So far I have made use of generics to allow any subclass of Number in the Collection.
In this particular class I keep running into the problem that there is no easy way to cast to the generic. The usual methods like Double.valueOf() cannot be invoked because Number does not provide such a method.
Is there a good way around this?
I have found this post and thought that would solve it, but I cannot pass the Class.class parameter to it.
public class myList<T extends Number> extends Collection<T> {
#Override
public boolean add(T value){
// this is no problem
}
// What I want to do:
public boolean add(double value){
return this.add(T.valueOf(value));
}
// Using the example I found:
public void add(double value){
return this.add( (T) Ideone.parse(value, T.class) ); // no such option
}
}
Thanks in advance.
There's no way for the myList class to be able to convert double to T, because T is unknown.
One way you can solve this is to let the caller provide a function that converts from double to T. Here's an example:
public class myList<T extends Number> implements Collection<T> {
private DoubleFunction<T> fromDoubleFunction;
public myList(DoubleFunction<T> function) {
this.fromDoubleFunction = function;
}
public boolean add(double value) {
return this.add(this.fromDoubleFunction.apply(value));
}
//rest of code
}
That can then be used in this way:
myList<Integer> intList = new myList(d -> Double.valueOf(d).intValue());
Provide a DoubleFunction<T> to your class as a constructor parameter.
public class myList<T extends Number> extends Collection<T> {
private final DoubleFunction<T> theDoubleFn;
public myList(DoubleFunction<T> theDoubleFn) {
this.theDoubleFn = theDoubleFn;
}
// ...
Then invoke:
return this.add(theDoubleFn.apply(value));
in the method.
Related
I'm new to Java and I'm trying to learn about generics. I tried to implement a simple version of binarySearch() method that is also found in the Collections class. I looked up the method signature and it's something like this:
public static <T> int binarySearch(List<? extends Comparable<? super T>> list, T key) {
// definition
}
I was wondering if the method above still accepts the same data types if you were to change the method definition to this:
public static <T extends Comparable<? super T>> int binarySearch(List<T> list, T key) {
// definition
}
If not, what are the differences between the two? Thank you!
Consider these classes:
class A extends Comparable<A> { /* ... */ }
class B extends A { /* ... */ }
Now define a key and a list with these types:
A key = new B();
List<B> list = List.of(key);
You can invoke the first form with these arguments, but not the second.
For example:
static class NonComparable {
}
static class MyComparable implements Comparable<NonComparable> {
#Override
public int compareTo(NonComparable o) {
return 0; // irrelevant for the example
}
}
And then declare the parameters:
List<MyComparable> list = Arrays.asList(new MyComparable());
NonComparable nonComparable = new NonComparable();
binarySearch(list, nonComparable);
One of your method definitions allows an invocation, the other does not.
I have kind of problem with generics inheritance. Below is the dependency tree:
public class Attributes {
}
public abstract class Feature<T extends Attributes> {
private T attributes;
public T getAttributes() {
return attributes;
}
public void setAttributes(T attributes) {
this.attributes = attributes;
}
}
public abstract class AbstractFeatureRepository<T extends Feature<? extends Attributes>> {
public abstract String getType();
public abstract boolean create(T feature);
}
And I have implementations of these feature repositories, like this:
public class NodeAttributes extends Attributes {
private String startPoint;
public String getStartPoint() {
return startPoint;
}
public void setStartPoint(String startPoint) {
this.startPoint = startPoint;
}
}
public class Node extends Feature<NodeAttributes> {
}
public class NodeRepository extends AbstractFeatureRepository<Node> {
public String getType() {
return "Node";
}
public boolean create(Node node) {
return true;
}
}
public class LinkAttributes extends Attributes {
private String uri;
public String getUri() {
return uri;
}
public void setUri(String uri) {
this.uri = uri;
}
}
public class Link extends Feature<LinkAttributes> {
}
public class LinkRepository extends AbstractFeatureRepository<Link> {
public String getType() {
return "Link";
}
public boolean create(Link link) {
return true;
}
}
I'm injecting these repositories with Spring to Controller via constructor (but in this example I'm manually creating in constructor for the sake of simplicity):
public class Controller {
private final Map<String, AbstractFeatureRepository<? extends Feature>> featureRepositories;
public Controller() {
this.featureRepositories = Arrays.asList(new NodeRepository(), new LinkRepository()).stream()
.collect(Collectors.toMap(AbstractFeatureRepository::getType, Function.identity()));
}
public Node createNode() {
Node newNode = new Node();
newNode.getAttributes().setStartPoint("Berlin");
createFeature("Node", newNode);
return newNode;
}
public Link createLink() {
Link newLink = new Link();
newLink.getAttributes().setUri("/home/local");
createFeature("Link", newLink);
return newLink;
}
private void createFeature(String type, Feature<? extends Attributes> feature) {
featureRepositories.get(type).create(feature);
}
}
All is good untill I want to call "create" method in generic "createFeature" where I'm getting compilation error that
The method create(capture#5-of ? extends Feature) in the type AbstractFeatureRepository<capture#5-of ? extends Feature> is not applicable for the arguments (Feature<capture#6-of ? extends Attributes>)
What I'm doing wrong? Is this because potentially I can pass some other kind of "Feature" than particular "Repository" can work with? How then should I change my map Repositories in Controller so compiler doesn't complain? I though I should operate exact classes as a key for map but have no idea how to make all of this working. Any suggestions?
Thank you.
Update 1. I changed Map to
private final Map<Class<?>, AbstractFeatureRepository<? extends Feature>> featureRepositories;
Changed AbstractFeatureRepository so it now looks this way:
public abstract class AbstractFeatureRepository<T extends Feature> {
public abstract Class<T> getClazz();
public abstract boolean create(T feature);
}
And changed the methods in controller:
public Link createLink() {
Link newLink = new Link();
createFeature(Link.class, newLink);
return newLink;
}
private <T extends Feature> void createFeature(Class<T> class1, T feature) {
AbstractFeatureRepository<? extends Feature> abstractFeatureRepository = featureRepositories.get(feature.getClass());
abstractFeatureRepository.create(abstractFeatureRepository.getClazz().cast(feature));
}
It still doesn't allow me to do that.
This code:
featureRepositories.get(type)
returns an object whose type is the V in Map<K, V>, as per the docs of java.util.Map. In your code, that means that expression is of type AbstractFeatureRepository<? extends Feature<? extends Attributes>>.
Let's simplify matters a tad, and assume we have List<? extends Number> instead.
This is valid java code:
List<? extends Number> list = new ArrayList<Integer>();
that's sort of the point of ? extends, really. This does not compile:
List<Number> list = new ArrayList<Integer>();
Now, imagine you called, on your List<? extends Number>:
List<? extends Number> list = new ArrayList<Integer>();
Number n = Double.valueOf(5.0);
list.add(n);
uhoh. There is a non-integer in my list of integers. Whoops.
That's why you can't call add() here, at all. You cannot call add on a List<? extends whatever>, at all. Any method that takes as argument a T where your type is Foo<? extends T> cannot be invoked*.
Let's go back to your code now:
You have a AbstractFeatureRepository<? extends Feature<? extends Attributes>> - therefore any method that AbstractFeatureRepository has that takes a T cannot be invoked from this. at all. And create is such a method.
The solution is a bit tricky. You can use a type-safe container, if you somehow have a reference to a class representing T (careful; things can be a T that cannot be a Class: List<Integer> is a T, but only List.class exists, you can't write List<Integer>.class! - You can use that:
public <T extends Attribute> void createFeature(Class<T> typeDesired, Feature<T> feature) {
featureRepositories.get(type).create(typeDesired.cast(feature));
}
is one way.
In general your method signature is problematic: There is just no guarantee that your stringly-typed String type implies that the kind of feature desired Feature<? extends Attribute> is handled by the repository matching that type.
A second option is to have each AbstractFeatureRepository responsible to deal with type mismatches. In that case, you can update the interface to read create(Object feature) throws TypeMismatchException instead. Or, have it return a type (public Class<T> getType()) and you can go back to the cast construct.
*) Well, you can invoke it, if you pass literally null, as null is all data types. But that clearly isn't what you intend to do here, thus, not relevant.
If you've only got 2 things in a Map (or N things, where N is a small number, you mention 4 in a comment), and you use fixed keys to indicate a particular type, using a Map is making it harder than necessary.
Maps are necessarily homogeneously typed, that is, all the keys have a common supertype, and all the values have a common supertype. The issue that you're facing is that you want a key's type to relate to the value's type: this can be done with a type-safe heterogeneous container (essentially: a map which you construct such that you can impose the constraints on the relationships between the types). But even this is overly-complex for the problem described.
Use two (N) fields instead:
public class Controller {
private final NodeRepository nodeRepository = new NodeRepository();
private final LinkRepository linkRepository = new LinkRepository();
This is still sort-of a map: the key is the field, the value is the field value.
But the advantage of this is that you've retained the concrete types of the repositories, so you can pass these to the method:
private <A extends Attributes> void createFeature(AbstractFeatureRepository<A> repo, Feature<A> feature) {
repo.create(feature);
}
e.g.
public Node createNode() {
Node newNode = new Node();
newNode.getAttributes().setStartPoint("Berlin");
// Or, easier, nodeRepository.create(newNode);
createFeature(nodeRepository, newNode);
return newNode;
}
public Link createLink() {
Link newLink = new Link();
newLink.getAttributes().setUri("/home/local");
// Or, easier, linkRepository.create(newNode);
createFeature(linkRepository, newLink);
return newLink;
}
To arrive at a working solution that is as close to your original code as I could get it, I made three or four relatively minor refactors.
The most significant change though was in Controller.createFeature()…
private <T extends Feature<?>> void createFeature(Class<T> class1, T feature) {
AbstractFeatureRepository<T> abstractFeatureRepository = (AbstractFeatureRepository<T>)featureRepositories.get(feature.getClass());
abstractFeatureRepository.create(feature);
}
The cast there is the simplest, most type safe solution in my opinion. The reason I'm convinced the cast is type safe is because of the compilation error you'd get if the cast weren't there:
Controller.java:31: error: incompatible types: AbstractFeatureRepository<CAP#1> cannot be converted to AbstractFeatureRepository<T>
AbstractFeatureRepository<T> abstractFeatureRepository = featureRepositories.get(feature.getClass());
where T is a type-variable:
T extends Feature<?> declared in method <T>createFeature(Class<T>,T)
where CAP#1 is a fresh type-variable:
CAP#1 extends Feature<?> from capture of ? extends Feature<?>
1 error
If you read the bottom part of the error message carefully, you'll see that the only difference between T extends Feature<?> and CAP#1 extends Feature<?> is the names of the two type variables. They both have the same upper bounds (extends Feature<?>). That tells me it's reasonable to infer that a cast would be type safe.
So, I annotated that method with SuppressWarnings("unchecked").
To confirm that the solution is usable, I fleshed out Node and Link classes with toString(). Calling Controller.createNode() and Controller.createLink() in the solution demo gets you…
Node: [NodeAttributes - Start Point: 'Berlin']
Link: [LinkAttributes - URI: 'urn::foo::bar']
I have to admit that what problem you're trying to solve isn't crystal clear to me. So I've made some assumptions based on only my general Java knowledge. Please let me know if the solution meets your requirements?
Here is the approach I used:
public class Controller {
private final Map<Class<?>, AbstractFeatureRepository<? extends Feature>> featureRepositories;
public Controller3(List<AbstractFeatureRepository<? extends Feature>> featureRepositories) {
this.featureRepositories = featureRepositories.stream()
.collect(Collectors.toMap(AbstractFeatureRepository::getClazz, Function.identity()));
}
public Node createNode() {
Node newNode = new Node();
createFeature(Node.class, newNode);
return newNode;
}
public Link createLink() {
Link newLink = new Link();
createFeature(Link.class, newLink);
return newLink;
}
private <T extends Feature> void createFeature(Class<T> clazz, T feature) {
AbstractFeatureRepository<T> repository = getRepository(clazz);
repository.create(feature);
}
#SuppressWarnings("unchecked")
private <T extends Feature, V extends AbstractFeatureRepository<T>> V getRepository(Class<T> clazz) {
return (V) featureRepositories.get(clazz);
}
public static void main(String[] args) {
Controller3 controller = new Controller3();
controller.createLink();
}
}
It doesn't satisfy completely no-cast approach(especially no #SuppressWarnings) but it is the least evil for me, since cast is done only in one method in controller, all the rest methods work no cast and no #SuppressWarnings.
Try
private static <T extends AbstractFeatureRepository> void createFeature(Class<T> clazz, Feature<? extends Attributes> feature) {
((T) featureRepositories.get(clazz)).create(feature);
}
You should modify the featureRepositories accordingly
private static final Map<Class<?>, AbstractFeatureRepository<? extends Feature>> featureRepositories
But I don't recommend using generics like this.
Consider the following Java method:
<T extends List<T>> List<T> getMyList() {
return Collections.emptyList();
}
I can assign its output to a variable with a raw type, like so:
List x = getMyList();
List<List> y = getMyList();
But, I can't think of any way to assign its output to a fully parameterized type. In particular, I can't think of a non-raw, concrete type T that would satisfy List<T> z = getMyList();
Can we create such a T ?
If not, why not?
For context, I created this question while trying to understand how Enums are implemented in Java.
Here's an example of a concrete type that both works and starts to hint at a possible use-case (registration of some sort). The type consists acts like both an instance of some type, and as a container for all instances of that type.
public class WeirdEnum extends AbstractList<WeirdEnum> {
private static List<WeirdEnum> underlyingList = new ArrayList<>();
#Override
public WeirdEnum get(int index) { return underlyingList.get(index); }
#Override
public int size() { return underlyingList.size(); }
static <T extends List<T>> List<T> getAList() {
return Collections.emptyList();
}
public WeirdEnum() {
underlyingList.add(this); // Sufficient for our example but not a good idea due to concurrency concerns.
}
static List<WeirdEnum> foo = WeirdEnum.getAList();
}
Not sure if I fully understand your question, but here's an example:
class Example<T> implements List<Example<T>> {
...
}
...
List<Example<String>> list = getMyList();
Every enum in Java extends from the base-enum-class Enum<T extends Enum<T>>, where T is the actual type of the implementing enum.
When writing SomeClass<T extends SomeClass<T>> you can enforce that the type-parameter is always the implementing class itself.
Let's say you have this interface:
public interface MyInterface<T extends MyInterface<T>> {
T getSelf();
}
And this implementing class:
public class MyClass implements MyInterface<MyClass> {
public MyClass getSelf() {
return this;
}
}
In MyClass it is not possible to use any other type-parameter than MyClass itself.
My goal is pretty simple. I've a SetInterface<T>:
public interface SetInterface<T>
{
public T duplicateSet();
}
I then also have an ExerciseInterface <T extends SetInterface<?>>
public interface ExerciseInterface <T extends SetInterface<?>>
{
public T getSet(int pos);
public void addSet(T set);
}
Everything works great up to this point.
The problem comes where I try to create a Generic Collection containing different classes which all implement the ExerciseInterface.
I am fairly new to Generics and I keep thinking I have solved something but all I am doing is pushing the error about.
The problem is pretty much summed by my addA() and addB() methods
public class Workout {
private String name;
private List <? extends ExerciseInterface<SetInterface<?>>> exerciseList;
// Constructor
public Workout(String name)
{
this.name = name;
exerciseList = new ArrayList<ExerciseInterface<SetInterface<?>>>();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void addExerciseA(ExerciseInterface<SetInterface<?>> exercise {
exerciseList.add(exercise);
}
public <T extends ExerciseInterface<SetInterface<?>>> void addExerciseB(T exercise {
exerciseList.add(exercise);
}
public ExerciseInterface<SetInterface<?>> getExercise(int pos) {
return exerciseList.get(pos);
}
}
The first add() gives the following error..
The method add(capture#2-of ? extends ExerciseInterface<SetInterface<?>>) in the type List<capture#2-of ? extends ExerciseInterface<SetInterface<?>>> is not applicable for the arguments (ExerciseInterface<SetInterface<?>>)
The second add() gives this error..
The method add(capture#2-of ? extends ExerciseInterface<SetInterface<?>>) in the type List<capture#2-of ? extends ExerciseInterface<SetInterface<?>>> is not applicable for the arguments (ExerciseInterface<SetInterface<?>>)
Just to reiterate, I have a SetInterface that different types of Sets implement.
I also have different exercises which mirror the Sets. For example:
BodyWeightExercise implements <SetInterface<BodyweightSet>>
and
WeightsExercise implements <SetInterface<WeightsSet>>
So my goal is to have a Collection of different exercises and a method that allows me to add to that collection.
Any help would be sincerely appreciated, I have lost a few hairs to this already.
Cheers.
EDIT: If this is not doable any pointers in a more feasible direction would be just appreciated.
EDIT2: I changed the List to List <ExerciseInterface<SetInterface<?>>> exerciseList; and the error on the add() methods both dissappear.
However, using this test code..
WeightsSet weightsSet = new WeightsSet();
WeightsExercise weightsExercise = new WeightsExercise();
weightsExercise.addSet(weightsSet);
Workout workout = new Workout("Wok");
workout.addExerciseA(weightsExercise); <-- ERROR
I am trying to add a WeightsExercise to Workout's List, but I get this error now..
Bound mismatch: The generic method addExerciseB(T) of type Workout is not applicable for the arguments (WeightsExercise). The inferred type WeightsExercise is not a valid substitute for the bounded parameter <T extends ExerciseInterface<SetInterface<?>>>
EDIT 3: Example classes extending ExerciseInterface and SetInterface (Concrete methods update in the interfaces above as well)
public class WeightsExercise implements ExerciseInterface<SetInterface<WeightsSet>>
{
#Override
public SetInterface<WeightsSet> getSet(int pos) {return null;}
#Override
public void addSet(SetInterface<WeightsSet> set) {}
}
public class WeightsSet implements SetInterface<WeightsSet>
{
#Override
public WeightsSet duplicateSet() {return null;}
}
SOLVED: This solution seems to encompass everything correctly.
public class Workout
{
private String name;
private List <ExerciseInterface<? extends SetInterface<?>>> exerciseList;
// Constructor
public Workout(String name)
{
this.name = name;
exerciseList = new ArrayList<ExerciseInterface<? extends SetInterface<?>>>();
}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public void addExerciseA(ExerciseInterface<? extends SetInterface<?>> exercise) {exerciseList.add(exercise);}
public ExerciseInterface<? extends SetInterface<?>> getExercise(int pos) {return exerciseList.get(pos);}
}
You should change your list declaration to:
List<ExerciseInterface<SetInterface<?>>> exerciseList;
When you use upper bounded wildcards, which I don't think you really need here, you can't add anything to the list, apart from null, and elements previously fetched from it.
That's because, you don't know exactly what concrete parameterized type of list it actually references. For e.g.: List<? extends CharSequence> can reference a ArrayList<String> or ArrayList<StringBuffer>. So, you can't add anything to that list, because it's not type safe. You might possibly be adding a StringBuffer object to ArrayList<String>, that will fail at runtime.
After update:
I guess you are trying to create a parallel class hierarchy, and got messed up in that. Perhaps, you wanted your ExerciseInterface to look like:
// Notice the use of `T` in `SetInterface<T>` instead of `SetInterface<?>`
interface ExerciseInterface<T extends SetInterface<T>> {
SetInterface<T> getSet(int pos);
void addSet(SetInterface<T> set);
}
and then your class WeightsExercise would be modified as such:
class WeightsExercise implements ExerciseInterface<WeightsSet> {
#Override
public SetInterface<WeightsSet> getSet(int pos) {return null;}
#Override
public void addSet(SetInterface<WeightsSet> set) {}
}
You would also need to make your Workout class generic like this:
public class Workout<U extends SetInterface<U>, T extends ExerciseInterface<U>> {
}
Then replace all occurrence of ExerciseInterface<SetInterface<?>> with ExerciseInterface<U> in your Workout class.
And create the instance of Workout like this:
Workout<WeightsSet, WeightsExercise> workout = new Workout<>("Wok");
workout.addExerciseA(weightsExercise);
This will what make a correct design IMO.
Recommended post:
What is a difference between <? super E> and <? extends E>?
What is PECS (Producer Extends Consumer Super)?
References:
Java Generics FAQ - Angelika Langer
What is bounded Wildcards?
Do generics help designing parallel class hierarchies?
Objective: What I need is to create a function or functions to handle different types of List parameter, and I will be iterating through the list in the function.
Attempts:
1- Multiple functions with different type of List
public static int update(List<MyClass> myClasses){};
public static int update(List<Project> rojects){};
public static int update(List<Time> times){};
But that deemed to be in-compilable as due to multiple functions with same parameter type List.
2- Generic type of list, and using (instanceof) However, I failed to completely do this as I am not sure how, and as much as I read, this seems to be an unfavorable way of such action.
My question: what is the Java way of implementing such requirement? I need a clean code, I don't care if it is complicated, I care mostly about accuracy and proper coding.
PS: if the instanceof the correct way, then would you please provide me with a small example on how to iterate the list with the different types.
Thanks in advance :)
EDIT: The different objects have no relation with each other, as in, they do not extend each other nor do they extend a super class. The blocks of each function are generating an SQLite statements which would be different for each type.
Respond to 'harsh's answer:
So I ended up using a combination of your suggestions, and that is to implement a base class with a function of getClassType() which returns a string of the class name, then I would check the returned value in the update(List<T> list) function.
public static <T extends Item> int update(List<T> list){
...
// Loop through the list and call the update function
for (T item: list){
if (item.getClassType() == MyClass.CLASS_TYPE)
update((MyClass) item);
}
...
}
public interface Item {
/**
* #return Return the class type, which is the name of the class
*/
public String getClassType();
}
public class ClassProject implements Item{
public static final String CLASS_TYPE = "ClassProject";
#Override
public String getClassType() {
return CLASS_TYPE;
}
...
}
public class ClassTime implements Item{
public static final String CLASS_TYPE = "ClassTime";
#Override
public String getClassType() {
return CLASS_TYPE;
}
...
}
public class MyClass implements Item{
public static final String CLASS_TYPE = "MyClass";
#Override
public String getClassType() {
return CLASS_TYPE;
}
...
}
Reason for doing this whole interface is because I don't like istanceof and not sure about it's performance and cost, so I attempted to make one of my own. Now is this a terrible way of doing this?
Can you do something like this:
public class Update<T>
{
public static int update(List<T> objects){};
}
OR
public static <T> int update(List<T> objects){};
whichever is more appropriate in your case.
So if you go by second approach and due to type erasure at runtime, you are left with instanceof checking:
public static <T> int update(List<T> objects){
for(T object : objects)
{
if(object.getClass().isInstance(Pair.class))
{
//do something
}else if(object.getClass().isInstance(Time.class))
{
}
}
return 0;
}
But that's doesn't look a good design, you can improve above by using a factory method:
static Handler getHandler(Class<?> handlerClass)
{
if(handlerClass.isInstance(Project.class))
{
//return ProjectHandler
}else if(handlerClass.isInstance(Time.class))
{
//return TimeHandler
}
//return errorHandler
}
interface Handler {
int handle();
}
public static <T> int update(List<T> objects){
for(T object : objects)
{
getHandler(object.getClass()).handle();
}
return 0;
}
Now a nicer approach IMO would be to designate your classes under update via marker interface and then cleanly handle update in each of the classes:
interface Updateable {
int update();
}
public static <T extends Updateable> int update2(List<T> objects){
for(T object : objects)
{
object.update();
}
return 0;
}
Based on your answer to my comment you are left with two approaches. The first would be to try to come up with an interface that all the possible types that would be passed to this method implement. If your interface was called Foo you could define the method as something like:
public int update(List<Foo> list)
Then your code inside would be based on the methods available in Foo.
If you can't do this then you will need separate methods per possible type. You can't do instanceof at runtime due to Type Erasure. The underlying type if the list is erased in the compiled code and therefor will not be available for instanceof logic.
EDIT:
To clear up a little confusion on my above answer. You can do instanceof on a per element basis when iterating the list, something like this:
for(Object item:list){
if (item instanceof A){
//do A based logic
}
else if (item instanceof B){
//do B based logic
}
}
You can't however check the list type at runtime like so:
if (list instanceof List<A>)
Your best bet really would be to try and generalize the types supported via an interface as suggested in my first solution. Doing the instanceof approach will lead to code that will constantly need to be modified as you add more supported types.
Expanding harsh's answer, can't you do:
public class Update
{
public static <T> int update(List<T> objects, Class<T> clazz){};
}
And then, in your implementation, vary behavior according to the passed Class instance?