Trouble with Java generics - java

I'm trying to do something with generics and I can't seem to figure it out. So I have this interface.
public interface Transformation<A,B> {
public B transform(A a);
}
And I have a class that implements it.
public class AveragingTransformer implements Transformation<List<Long>,Double> {
public Double transform(List<Long> a) {
return a.get(0).doubleValue()/a.get(1);
}
}
So in my main method I have this...
public static void main(String[] args){
....
Transformation<List<?>,Double> transformation = new AveraginTransformer();
....
}
But this doesn't work for some reason, can anyone help me understand why?
EDIT
So the issue is if I want to pass an array to my transformation I can't seem to get the compiler to accept it.
So say I have...
public class foo<T>{
T val;
Transformation<? extends List<?>,T> transformation; //This gets initialized by constructor, where I will pass in the averaging transformer in this case.
public void setVal(List<?> list){
val = transformation.transform(list);
}
}
If I try to do this it gives me this error
But I want to keep the left part of my transformation generic because different foos will calculate their values in different ways with potentially different data. i.e. Some foos might calculate their val from a list of Strings but if I provide the right transformer to each, then it should work.

You must match the generics exactly:
Transformation<List<Long>,Double> transformation = new AveragingTransformer();
i.e. change List<?> to List<Long>.
If you want the tool to apply to multiple types then choose an appropriate implemented interface. e.g. here Long implements Number so I will pull back to List<Number>.
public interface Transformation<A, B> {
public B transform(A a);
}
public class AveragingTransformer implements Transformation<List<Number>, Double> {
#Override
public Double transform(List<Number> a) {
return a.stream().mapToDouble(v -> v.doubleValue()).average().orElse(0);
}
}
public void test() {
Transformation<List<Number>, Double> transformation = new AveragingTransformer();
}

Ah so I finally figured it out, as OldCurmudgeon pointed out the issue was the wildcards. The problem was the compiler didn't know that all of them were going to actually be the same in the end, meaning my Foo class actually had another Type parameter I hadn't thought of, the type of the values used to calculate the end result.
public class Foo<T,I>{
T val;
Transformation<List<I>,T> transformation;
public void setVal(List<I> list>){
val = transformation.transform(list);
}
}
public static void main(String[] args){
Foo<Double,Number> foo = nee Foo(new AveragingTransformer());
List<Number> nums = new Arraylist<Number>();
nums.add(2);
nums.add(3);
foo.setValue(nums);
}
Thanks for pointing me in the right direction!

Related

Java Stream map(...) - error while passing custom Function, though accepting methodReference

For code readability I am creating Custom Function Interface, while passing it as mapper in map(...), a compilation error is coming. Need help. The below example simplified for the problem.
e.g.
#FunctionalInterface
public interface Try<K,T> {
public K apply(T t);
}
public class Concrete{
//example
public static String checkFunc(Integer integer) {
return "Vivek";
}
}
public class CustomTest {
public static void main(String[] args) {
List<Integer> integers = Arrays.asList(1,2,3);
Try<String,Integer> try1 = Concrete::checkFunc;
integers.parallelStream().map(try1); // compile error
//The method map(Function<? super Integer,? extends R>) in the type Stream<Integer> is not
//applicable for the arguments (Try<String,Integer>)
integers.parallelStream().map(Concrete::checkFunc); // this is perfectly fine
}
}
I am trying to pass mapper something like above. How to do that correctly?
You must pass in something that implements java.util.function.Function. You have two main choices:
make Try extend Function
convert Try to a Function, e.g. map(try1::apply)
You cannot get around the need to pass in a Function to map.

C# generic parent object reference which can take any child [duplicate]

Let's say I have a generic class as follows:
public class GeneralPropertyMap<T>
{
}
In some other class I have a method that takes in an array of GeneralPropertyMap<T>. In Java, in order to take in an array that contains any type of GeneralPropertyMap the method would look like this:
private void TakeGeneralPropertyMap(GeneralPropertyMap<?>[] maps)
{
}
We use the wildcard so that later we can call TakeGeneralPropertyMap passing a bunch of GeneralPropertyMap with any type for T each, like this:
GeneralPropertyMap<?>[] maps = new GeneralPropertyMap<?>[3];
maps[0] = new GeneralPropertyMap<String>();
maps[1] = new GeneralPropertyMap<Integer>();
maps[2] = new GeneralPropertyMap<Double>();
//And finally pass the array in.
TakeGeneralPropertyMap(maps);
I'm trying to figure out an equivalent in C# with no success. Any ideas?
Generics in C# make stronger guarantees than generics in Java. Therefore, to do what you want in C#, you have to let the GeneralPropertyMap<T> class inherit from a non-generic version of that class (or interface).
public class GeneralPropertyMap<T> : GeneralPropertyMap
{
}
public class GeneralPropertyMap
{
// Only you can implement it:
internal GeneralPropertyMap() { }
}
Now you can do:
private void TakeGeneralPropertyMap(GeneralPropertyMap[] maps)
{
}
And:
GeneralPropertyMap[] maps = new GeneralPropertyMap[3];
maps[0] = new GeneralPropertyMap<String>();
maps[1] = new GeneralPropertyMap<Integer>();
maps[2] = new GeneralPropertyMap<Double>();
TakeGeneralPropertyMap(maps);
While, as others have noted, there's no exact correspondence to wildcards in c#, some of their use cases can be covered with covariance/contravariance.
public interface IGeneralPropertyMap<out T> {} // a class can't be covariant, so
// we need to introduce an interface...
public class GeneralPropertyMap<T> : IGeneralPropertyMap<T> {} // .. and have our class
// inherit from it
//now our method becomes something like
private void TakeGeneralPropertyMap<T>(IList<IGeneralPropertyMap<T>> maps){}
// and you can do
var maps = new List<IGeneralPropertyMap<Object>> {
new GeneralPropertyMap<String>(),
new GeneralPropertyMap<Regex>()
};
//And finally pass the array in.
TakeGeneralPropertyMap<Object>(maps);
The caveat is that you can't use covariance with value types, so adding a new GeneralPropertyMap<int>() to our list fails at compile time.
cannot convert from 'GeneralPropertyMap<int>' to 'IGeneralPropertyMap<object>'
This approach may be more convenient than having a non-generic version of your classes/interfaces in case you want to constrain the types that GeneralPropertyMap can contain. In that case:
public interface IMyType {}
public class A : IMyType {}
public class B : IMyType {}
public class C : IMyType {}
public interface IGeneralPropertyMap<out T> where T : IMyType {}
allows you to have:
var maps = new List<IGeneralPropertyMap<IMyType>> {
new GeneralPropertyMap<A>(),
new GeneralPropertyMap<B>() ,
new GeneralPropertyMap<C>()
};
TakeGeneralPropertyMap(maps);
There is no direct equivalent to this in C#.
In C#, this would often be done by having your generic class implement a non-generic interface or base class:
interface IPropertyMap
{
// Shared properties
}
public class GeneralPropertyMap<T> : IPropertyMap
{
}
You could then pass an array of these:
IPropertyMap[] maps = new IPropertyMap[3];
// ...
TakePropertyMap(maps);
Make an interface from the members of GeneralPropertyMap (IGeneralPropertyMap), and then take an IGeneralPropertyMap[] as an argument.
Actually, you can get pretty close to a wildcard by using dynamic. This also works nicely if you have a non-generic superclass.
For example:
public class A
{
// ...
}
public class B<T> : A
{
// ...
}
public class Program
{
public static A MakeA() { return new A(); }
public static A MakeB() { return new B<string>(); }
public static void Visit<T>(B<T> b)
{
Console.WriteLine("This is B with type "+typeof(T).FullName);
}
public static void Visit(A a)
{
Console.WriteLine("This is A");
}
public static void Main()
{
A instA = MakeA();
A instB = MakeB();
// This calls the appropriate methods.
Visit((dynamic)instA);
Visit((dynamic)instB);
// This calls Visit(A a) twice.
Visit(instA);
Visit(instB);
}
}
How this works is explained in the C# documentation here.

Why does Java allow ignoring/dropping generic constraints when implementing (overriding) a method with such constraints?

Is it a limitation in Java that it allows ignoring/dropping generic constraints when implementing (overriding) a method with such constraints?
Or, is it working as intended and this is an example of misuse and not an issue expected to cause problems?
I can write an interface with a generic constraint:
public interface X
{
public <T extends Number> List<T> get();
}
I can then implement such in interface ignoring the constraint:
public static class BadX implements X
{
#Override
public List<String> get()
{
return Arrays.asList("a", "b", "c");
}
}
And now, when using such implementation, I can assign to a wrong type without any compile-time or runtime errors:
X x = new BadX();
// wooops, it's actually a list of strings,
// but no compile-time nor runtime errors
List<Double> doubles = x.get();
It seems that when overriding the method, constraints are not checked. This is a bit strange because List return type is not allowed unless generic type is defined (e.g. <T>, or <T extends OtherType>).
Full code example below:
import java.util.Arrays;
import java.util.List;
public class JavaFiddle
{
public static void main(String[] args)
{
System.out.println("STARTED");
NumberSource ns = new IntegerSource(Arrays.asList(1, 2, 3));
// wooops, it's actually a list of integers,
// but no compile-time nor runtime errors
List<Double> doubles = ns.getSource();
// works
printNumbers(doubles);
// runtime error
printDoubles(doubles);
System.out.println("DONE");
}
public static void printNumbers(List<? extends Number> numbers)
{
for (Number n : numbers)
System.out.println(n);
}
public static void printDoubles(List<Double> doubles)
{
for (Double d : doubles)
System.out.println(d);
}
public interface NumberSource
{
public <T extends Number> List<T> getSource();
}
public static class IntegerSource implements NumberSource
{
private List<Integer> source;
public IntegerSource(List<Integer> integers)
{
this.source = integers;
}
#Override
public List<Integer> getSource()
{
return source;
}
}
}
The only argument I've seen for this is backwards compatibility. For instance, if you you're using a pre-existing library interface that returns a List, but you know it only contains Integer objects, you might cast it:
List<Integer> myList = legacyObject.legacyGetList(); // returns a List
See section 6.1 from this document:
https://www.oracle.com/technetwork/java/javase/generics-tutorial-159168.pdf
You may already be thinking about this, but in your case, it might be safer/more maintainable to implement NumberSource as a generic class and use something like
NumberSource<Integer>
IntegerSource would extend NumberSource. That would allow code like:
NumberSource<Integer> ns = new IntegerSource(Arrays.asList(1, 2, 3));
// This no longer compiles
List<Double> doubles = ns.getSource();

Casting INSIDE the Generic classes in java

I know that we can skip casting by adding using the Generics in java as follows. (When we are using it outside of the Generic class.)
But if we are doing some logics on the type object (T item) inside the generic class (Container<T>) we should check the instance of and specially cast isn't it? So we can use it to skip casting out side the generic classes.
Please check the commented code in the public void setItem(T item) method.
I want to know whether my understanding is correct or am I missing something
Client.java
public class Client {
public static void main(String[] args) {
// String container
Container<String> stringContainer = new Container<String>();
stringContainer.setItem("Test");
//stringContainer.setItem(new StringBuffer("")); // compilation error, type safety checking
System.out.println(stringContainer.getItem().toUpperCase()); // No need to cast
// Integer container
Container<Integer> integerContainer = new Container<Integer>();
integerContainer.setItem(123);
//integerContainer.setItem("123"); // compilation error, type safety checking
System.out.println(integerContainer.getItem().intValue()); // No need to cast
}
}
Container class
class Container<T> {
private T item;
public T getItem(){
return item;
}
public void setItem(T item){
/* If I' doing some thing on item then I have to check the instance of and cast isn't it?
if(item instanceof String){
System.out.println("setItem().((String)item).toUpperCase() : " + ((String) item).toUpperCase());
}
*/
this.item = item;
}
}
Reference : http://nandirx.wordpress.com/category/java-2/generics-java/
As others have said, you shouldn't ever downcast a generic type as it defeats the purpose of generics.
You should use bound generics instead. A bound generics allows you to require a generic be of a specific type. This allows you to access values in the specific type without needing to cast.
This doesn't make sense with the String class as String is marked final and so cannot be extended, but for the future, try something like this.
public interface Shape{
double getArea();
}
public class Rectangle implements Shape{
double width;
double height;
public double getArea(){ return width*height;}
}
//this collection can hold Shape, or any type implementing shape.
public class MyShapeCollection<T extends Shape>{
List<T> shapes;
public double getAreaSum(){
double areaSum = 0;
for(Shape s : shapes){
areaSum += s.getArea();
}
return areaSum;
}
}
public static void main(String[] args){
MyShapeCollection<Rectangle> rectangles = new MyShapeCollection<Rectangle>();
//bad code monkey. String does not implement Shape!
//this line won't compile. including it for demonstration purposes.
MyShapeCollection<String> willNotCompile = new MyShapeCollection<String>();
}
If your collection will only hold strings, you don't need generics.
Yes, your understanding is correct.
Adding type specific code here, however, defeats the purpose of generics.
A better solution would be the following.
Client.java
public class Client {
public static void main(String[] args) {
// String container
Container<String> stringContainer = new StringContainer();
stringContainer.setItem("Test");
//stringContainer.setItem(new StringBuffer("")); // compilation error, type safety checking
System.out.println(stringContainer.getItem().toUpperCase()); // No need to cast
}
}
Container.java
class Container<T> {
private T item;
public T getItem(){
return item;
}
public void setItem(T item){
this.item = item;
}
}
StringContainer.java
class StringContainer extends Container<String> {
#Override
public void setItem(String item){
System.out.println( item.toUpperCase() );
super.setItem( item );
}
}
Right, or you could overload the setItem() method for different types of parameters, but that's actually even worse.
Yes, for your case casting is necessary. Because you are using string functions specifically.
But its like you are not using generic feature.
If you wanna to print item, then you can override toString() method of each item, and you can directly put item object in sysout(). By doing so, there will be no casting needed and all code get generic for all items.
What you say here.

Specify valid generic types with a parameter

Consider the following classes
public interface SortBy<S> {
}
public class CommentSortBy<S> implements SortBy<S> {
public static CommentSortBy<Date> CREATION = new CommentSortBy<Date>();
public static CommentSortBy<Integer> VOTES = new CommentSortBy<Integer>();
}
public class SomeQueryUnsafe {
public <M, S extends SortBy<M>> void setSort(S sortBy, M min) {
//Set relevant values
}
}
This is currently used as:
public SomeQueryUnsafe createCommentQueryUnsafe() {
return new SomeQueryUnsafe();
}
public void test() {
createCommentQueryUnsafe().setSort(CommentSortBy.CREATION, new Date());
}
While this works, the problem is that createCommentQueryUnsafe() does not specify limits on sortBy. Users are free to pass UserSortBy.NAME even though that would make no sense in this context
I can't figure out how to do write this though because just adding <B extends SortBy> to the class signature means I loose the ability to restrict the min parameter in the method. I can't use something like <M, S extends B & SortBy<M>> as its a compiler error. Other attempts with wildcard magic just result in significantly more complexity and compiler errors. Moving the sorting to the createCommentQuery() method would mean every single query needs 2 methods, which is a crazy amount of duplicated code
How can I possibly write the generics so createCommentQuery() limits the sortBy parameter to just CommentSortBy while still having min restricted to the S parameter in the SortBy class?
This is indeed a tricky issue for the reasons you've pointed out. I tried various approaches but they were all defeated by the generics limitation you cited. Ultimately it seems like you'll need to make some design changes if you want the specified type safety.
Using the inheritance hierarchy of the SortBy implementations for your generic type restrictions seems to have led to this impasse in particular. I tried decoupling that restriction into a new type parameter on SortBy, which stands for the queried object itself, e.g. Comment, User, etc. This is the design I came up with:
static class Comment { }
static class User { }
interface SortBy<T, M> { }
static class CommentSortBy<M> implements SortBy<Comment, M> {
static final CommentSortBy<Date> CREATION = new CommentSortBy<Date>();
static final CommentSortBy<Integer> VOTES = new CommentSortBy<Integer>();
}
static class UserSortBy<M> implements SortBy<User, M> {
static final UserSortBy<String> NAME = new UserSortBy<String>();
}
static class Query<T> {
public <M> void setSort(SortBy<T, M> sortBy, M min) {
//Set relevant values
}
}
public static void main(String[] args) {
new Query<Comment>().setSort(CommentSortBy.CREATION, new Date());
new Query<Comment>().setSort(UserSortBy.NAME, "Joe"); //compiler error
}
(ideone)

Categories