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.
Related
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.
First, read the code below.
I want to call the invoke method of the SuperClass, without having to cast the return value to the corresponding type.
The problem is that the SuperClass implementation is located one project and the SuperClassImpl1 and 2, are in another project.
In runtime these are in different classloaders, i.e. ClassLoader 1 knows about SuperClass but not about SuperclassImpl1. I have a "SuperClassLoader" which gives ClassLoader 1 a class object of e.g. SuperClassImpl2, but I can only use it as a SuperClass object.
Right now my code looks like the one below, and i have to cast it to e.g. a Map if i know that the method name I give to invoke returns a Map.
What I would want is that depending on the return type of the method given by the methodName, the return type of the invoke method should change accordingly.
E.g. invoke("getMyMap") should return a Map. Note, I dont want this:
Map m = invoke("getMyMap");
m.get(...);
I want this:
invoke("getMyMap").get(...);
Is it possible?
public abstract class SuperClass(){
public Object invoke(String methodName){
Method method = this.getClass().getDeclaredMethod(methodName);
return method.invoke(this);
}
}
public class SuperClassImpl1() extends SuperClass{
Map<String,String> myMap;
public SuperClassImpl1(){
myMap = new HashMap<String,String>();
}
public Map<String,String> getMyMap(){
return myMap;
}
}
public class SuperClassImpl2() extends SuperClass{
List<String> myList;
public SuperClassImpl2(){
myList = new ArrayList<String>();
}
public ArrayList<String> getMyList(){
return myList;
}
}
public class MainClass(){
public static void main(String[] args){
SuperClass mySuperClass1 = new SuperClassImpl1();
SuperClass mySuperClass2 = new SuperClassImpl2();
System.out.println("Something in my map: "+mySuperClass1.invoke("getMyMap").get("Some value"));
// something similar using mySuperClass2 here...
}
}
The problem is that, in the definition of invoke(), the return type is always an object. This is just the way things are.(documentation)
If you want to use reflection, you will have to use casting at some point. You could create a wrapper method that does the casting for you, but there is no getting around it.
The way I got it to work was like this:
System.out.println("Something in my map: "+((Map<?, ?>) mySuperClass1.invoke("getMyMap")).get("Some value"));
The return type of the method can not depend on the String that you pass to it, because the type is resolved at compile time while the argument is only known at run time.
You can, however add parameter to your classes.
public abstract class SuperClass<T> {
public T invoke(String methodName){
Method method = this.getClass().getDeclaredMethod(methodName);
return (T) method.invoke(this);
}
}
public class SuperClassImpl1() extends SuperClass<Map<String, String>> {
...
}
public class MainClass(){
public static void main(String[] args){
SuperClass<Map<String, String>> mySuperClass1 = new SuperClassImpl1();
SuperClass<ArrayList<String>> mySuperClass2 = new SuperClassImpl2();
System.out.println("Something in my map: "+mySuperClass1.invoke("getMyMap").get("Some value"));
// something similar using mySuperClass2 here...
}
}
You can't do it because generic types are checked at compile time, and the actual return type of the methods you invoke is not known until run time.
Map m = invoke("getMyMap"); // checked at compile time
return method.invoke(this); // resolved at run time
In the code below, when I call getList() I am not able to specify <T>. getList<T>() does not compile.
Instead, I may only call getList() - but then <T> is always simply <Event> .
Why is this?
class Foo
{
public static void main (String[] args) throws java.lang.Exception
{
// For the sake of a complete example - the next method has
// my question.
Foo f = new Foo();
f.register(new Subscriber<MyEvent>() {
public void handle(MyEvent event){};
});
}
public <T extends Event> void register(Subscriber<T> subscriber) {
// Below won't work. I can't specify <T>, so getList()
// will return a HashSet<Subscriber<Event>>, to which I cannot
// add the Subscriber<T>!
getList().add(subscriber);
// Why can't I call getList<T>().add(subscriber) ?
}
private <T extends Event> HashSet<Subscriber<T>> getList() {
// For the sake of example, simply return a new HashSet.
return new HashSet<Subscriber<T>>();
}
}
interface Subscriber<T extends Event> {
public void handle(T event);
}
interface Event { }
class MyEvent implements Event { }
It appears that Java won't accept a <T> as the type argument to a simple name such as getList(). But it will accept it if you explicitly state this. when calling the method:
this.<T>getList().add(subscriber);
I believe the right answer is to make Foo into Foo<T extends Event> so that when in Foo T is defined.
Otherwise, try this.<T>getList(). This is how this is done for statics MyClass.<String>someMethod(). Not sure if it will also work for an instance method. Again, the best answer is to make Foo generic.
The T from you example is extending Event in both methods of Foo class. Well that implicitly means you Foo class is working only with <T extends Event> type inference. Unfortunately, your T is defined only at method scope. For humans all looks alright. But compiler is a bit different. Compiler doesn't believe you and it's not able to figure out implicit informations, however they are just fine, logically. You did not define your T at Class scope and the compiler did not figure out you are using the same type inference in both methods. So, compiler wont let you mix these method together.
So, the solution should explicitly define type inference is for Class scope use not only for method scope.
class Foo<T extends Event>
{
public static void main (String[] args) throws java.lang.Exception
{
// For the sake of a complete example - the next method has
// my question.
Foo<MyEvent> f = new Foo<MyEvent>();
f.register(new Subscriber<MyEvent>() {
public void handle(MyEvent event){};
});
}
public void register(Subscriber<T> subscriber) {
// Below won't work. I can't specify <T>, so getList()
// will return a HashSet<Subscriber<Event>>, to which I cannot
// add the Subscriber<T>!
getList().add(subscriber);
// Why can't I call getList<T>().add(subscriber) ?
}
private HashSet<Subscriber<T>> getList() {
// For the sake of example, simply return a new HashSet.
return new HashSet<Subscriber<T>>();
}
}
interface Subscriber<T extends Event> {
public void handle(T event);
}
class MyEvent extends Event {
}
class Event {
}
Perhaps you need to be a little more gentle with Java. This seems to work without warnings:
HashSet<Subscriber<T>> list = getList();
list.add(subscriber);
I have an interface
interface Inter extends Blah {
public void someMethod();
}
class Dummy {
Class<Blah> interfaceType;
public setInterfaceType( Class<Blah> input ) {
this.interfaceType = input;
}
}
class tester {
public void init() {
Dummy dummyObj = new DummyObj();
dummyObj.setInterfaceType( Inter.class ); //This complains that the type is not suitable
}
}
Compilation error:
The method setInterfaceType(Class) in the type Dummy is not applicable for the arguments (Class)
I tried casting input to Class<Blah> while calling setter but that isnt allowed either. Im not understanding why it doesnt accept a class of sub-class-type. Can anyone tell me whats happening here and how the setter can be invoked. The Dummy class is external so i cannot change it.
Generics are not covariant so you can't set to Class<Blah> object of type Class<Inter>. Think about it. If you would be able to use List<Fruit> list = new ArrayList<Apple>() then via list you would be able to add not only Apples but also other Fruits. Would that be OK?
To solve this problem try changing Class<Blah> to Class<? extends Blah>
You can also change your Dummy class to use generic type T
class class Dummy<T extends Blah> {
Class<T> interfaceType;
public void setInterfaceType(Class<T> input) {
this.interfaceType = input;
}
}
and use it like
Dummy<Inter> dummyObj = new Dummy();
dummyObj.setInterfaceType(Inter.class);
You most certainly means
Class<? extends Blah> interfaceType;
public setInterfaceType( Class<? extends Blah> input ) {
this.interfaceType = input;
}
Update
If the Dummy class can't be modified, then it is pretty dubius WHY there is such a setter method. But anyway, you may avoid the "generic type" check, by casting your argument to Class (without type argument), as in: dummyObj.setInterfaceType( (Class) Inter.class )
For a better understanding of my question, see the following classes:
public interface Invoker<R> {
public String getName();
public R getResult();
}
Implementation:
public class RepairFetcher implements Invoker<List<String>> {
#Override
public String getName() {
return this.getClass().getSimpleName();
}
#Override
public List<String> getResult() {
return new ArrayList<String>();
}
}
The class where it goes wrong:
public class OperationService {
public <R> R invoke(Class<R> invoker, Object... parameters) {
WebserviceOperation<R> operation = new WebserviceOperation<R>(invoker);
Invoker<R> instance = operation.getInstance();
return instance.getResult();
}
}
The main class:
public class Main {
public static void main(String[] args) {
OperationService operationService = new OperationService();
operationService.invoke(RepairFetcher.class, new Object[] {});
}
}
The problem:
At this moment the method
operationService.invoke(RepairFetcher.class, new Object[] {});
returns an RepairFetcher, which is not so weird because of the argument in the invoke method:
Class invoker
Which returns R, which is a RepairFetcher.class.
What I want
I don't want the invoke method to return the RepairFetcher class, but I want it to return the declared Type, which is List< String>.
Is this possible, and if so, how to implement this?
Thanks in advance!
Not sure, but try:
public <T, R extends Invoker<T>> T invoke(Class<R> invoker, Object... parameters) {
The code you posted doesn't compile in the current shape (it misses some parts), but judging from what you're trying to do, you should be aware that Class is parameterized with the type of the class; so, the type of the String.getClass() is Class<String>.
That said, your function definition
public <R> R invoke(Class<R> invoker, Object... parameters) {
should probably be something like
public <R> R invoke(Class<Invoker<R>> invoker, Object... parameters) {
so you can be sure to return the same type that your invoker returns.
RepairFetcher implement Invoker<List<String>> so RepairFetcher is a Invoker<List<String>> and the return is good.
If you test this:
RepairFetcher instanceof Invoker<List<String>>, the answer must be true.
PS: I replace < by ( because the editor has a problem with <