Say I have a 3 generic parameters:
public static interface Mapper<V,T,E> {
public void map(KeyValue<V> v, AsyncCallback<T,E> cb);
}
How can I make the parameters optional? How can I give the parameters default values if the user only supplies the first parameter?
Using TypeScript, that would look like:
public static interface Mapper<V,T = any,E = any> {
public void map(KeyValue<V> v, AsyncCallback<T,E> cb);
}
so if the user doesn't supply T and E, they default to any. Is there a way to do this with Java?
If what you have in mind is something along the lines:
Having a method that takes 3 (generic) parameters
But at times you'll want it to have 2 parameters
Then, the following is the way to approach this. Since otherwise making parameters optional is not allowed in my opinion.
interface InterfaceA<T, T> {
boolean myMEthod(T clazz, UserRef user, String type, T clazz2) {
return false;
}
}
interface InterfaceB<T> extends InterfaceA<T, T> {
default boolean myMEthod(T clazz, UserRef user, String type) {
return myMEthod(clazz, user, type, clazz);
}
}
This allows you to implement the InterfaceB whereever you want to skip a parameter.
You could pass same parameter (of same type) twice, pass null, or some default value.
I hope this works for your case.
I'd say no. Java enjoys it when all of it's variables are set as a certain type and never change. If you want to find the most flexibility, try finding the biggest possible superclass, as in maybe T = Object and E = Object. Later when you need to use the object you can typecast it into what you want? Maybe?
I see two ways of doing it (or at least workaround the problem):
The first way is to implement a method with all your parameters and pass null instead of the parameter if you don't need it. Then handle it in your method's body. This should look like this:
public void myMethod(Sometype param1, Sometype param2, Sometype param3) {
//Test if your paramaters are null or not then do what you want
}
And you can call your method like this (if you don't need the second parameter for example):
myInstance.myMethod(param1, null, param2);
You could do it like this, but I DON'T recommand using this trick, because it's
counterintuitive for the user, and your method will be verbose, and "unclean"...
There's a second way to do it. even if it's way more verbose than TypeScript or Kotlin, you can simply define several methods with the required parameters. For example one method with only the second parameter, one with the first and the third parameter, etc... It's just basic method overloading, but it works perfectly! I think it's one of the most "java-friendly" way to do it.
I hope I helped you
Like many languages, there is no optional or gradual typing in Java. The typing rules are probably complicated enough as it is. Nor are there default type arguments, but that doesn't seem to be the major issue here.
In your case, it looks like making the typing more client friendly solves the problem without having to go further. I am assuming the E in AsyncCallback is for "exception" and T is, as in GWT's AsyncCallback, for a method parameter.
public static interface Mapper<V,T,E> {
public void map(KeyValue<V> v, AsyncCallback<? super T,? extends E> cb);
}
That allows any particular Mapper to take any applicable AsyncCallback.
We can be more explicit about the exception - useful if we need to define a throws anywhere.
public static interface Mapper<V,T,E extends Throwable> {
If a reference to a Mapper could take any AsyncCallback, declare it of type Mapper<V,Object,Throwable> for some V.
If you desperately wanted a short form of Mapper with a concise declaration for you could introduce an adapter.
public class MapperAny<V> implements Mapper<V,Object,Throwable> {
private final Mapper<V,Object,Throwable> target;
// A static creation method would be nicer, but ctor conventional.
public MapperAny(Mapper<V,Object,Throwable> target) {
this.target = target;
}
public void map(KeyValue<V> v, AsyncCallback<T,E> cb) {
target.map(v, cp);
}
// unwrap
public Mapper<V,Object,Throwable> mapper() {
return target;
}
}
If you wanted the same thing for AsyncCallback, it's a bit more difficult. There is no denotable opposite of Object (i.e. the type of null).
You can´t do it with one class, but you can partially solve it using inheritance. Say you have
interface Mapper<V,T,E> {
public void map(KeyValue<V> v, AsyncCallback<T,E> cb);
}
You can then have interfaces that specialize this, like so:
interface MapperWithObjectValue<T,E> extends Mapper<Object, T, E> {
}
interface MapperWithObjectResult<V,E> extends Mapper<V, Object, E> {
}
etc.
It´s not all that useful in this way, as the user could just as well pass Object as the type parameter, but it does have its uses for retroactively generifying an interface. Say you have
interface Foo {
Object getFoo();
}
You then realize that you´d like that return type be a generic type, but you´ve already committed this interface as part of your stable API. You can then use specialization via inheritance to solve it, like so:
interface GenericFoo<T> {
T getFoo();
}
interface Foo extends GenericFoo<Object> {
}
Existing code can keep using Foo just like before, and code that has a need for a different return type can use GenericFoo instead.
Related
I'm refactoring a generic method which has been overloaded many times to reduce the overloads. I've removed all overloads leaving only one method, opting instead to use a single params object encapsulating all parameters passed to the overloaded methods.
Is it possible to encapsulate the Supplier<T> func inside CompleteParams params for complete(CompleteParams params) whilst preserving the semantics of complete(Supplier<T> func, String param1, boolean param2)?
I'm not sure this is possible from what I've read in the Java Docs
Generic methods are methods that introduce their own type parameters. This is similar to declaring a generic type, but the type parameter's scope is limited to the method where it is declared.
Previous code:
// multiple overloads
public static <T> T complete(Supplier<T> func, String param1) {
complete(func, null);
}
//original
public static <T> T complete(Supplier<T> func, String param1, boolean param2) {
final T = func.get();
}
Current code:
public static <T> complete(CompleteParams params) {
final T = params.getFn().get();
}
CompleteParams.java
#Value
#Builder
public class CompleteParams {
Supplier func;
String param1;
Boolean param2;
}
Leaving aside that this is a terrible idea altogether (see my comment above, and sorry again =/), you want to parametrize your parameters class:
public class CompleteParams<T> {
Supplier<T> func;
String param1;
Boolean param2;
}
public static <T> complete(CompleteParams<T> params) {
final T = params.func.get();
}
Notice that the language "type parameter's scope is limited to the method where it is declared" doesn't mean that you can't use the a type variable in one scope as an argument to another type! Generics would not be very useful if this were the case...
(I'm not sure what your anotations (ie. #Builder) are doing there or what library they are part of. Is that Spring? Lombok? You may need to design in specific ways to satisfy whatever contracts they imply, as well...)
[edit: Ok, you've edited the question to indicate this is in fact Lombok. My proposed solution will work fine with Lombok's #Builder, so game on. But, check out the readability mess, stack trace fat, and performance hit that happens for every call now when you do something like WhateverClassItIs.complete(CompleteParams.<TYPE>.builder().param1("foo")....). Do you think writing this every call is really cleaner than invoking the old overloaded methods?]
Without any introduction to generics, I will post my question straight away. Why is this correct:
static<T extends Object> void m1(List<T> list){
//some code
}
And this is not (doesn't compile):
static void m2 (List<T extends Object> list){
//some code
}
Remember that we could use wildcards in the same approach, which would compile just fine:
static void m2 (List<? extends Object> list){
//some code
}
To sum up, why can we use wildcards declaration in parameters, while using type parameter we must declare it before return type?
There are two main points.
First off, as #akuzminykh said in the comments to the question, the ? wildcard is basically just a way to tell the compiler "I don't know what this is gonna be, just assume it could be anything that derives from this class/interface, kthxbye". It doesn't declare any parameter that you could make use of within the method, no identifier you can call upon, nothing. However, type parameters do exactly that, and if you declare a new one, it's a different story than just "calling" the wildcard which you don't have to declare.
Secondly, think of how you would declare a type parameter for a generic class. Do you think this would be enough?
public class Foo {
public T extends CharSequence getBar() {...}
}
public class Foo {
public <T extends CharSequence> getBar() {...}
}
No, none of these two options would work. In order to use a generic type parameter within a class, you have to declare it along with the type itself, not along with the methods/fields that use them. Like this:
public class Foo<T extends CharSequence> {
public T getBar() {...}
}
And in order to use a generic type parameter within a method, you have to declare it along with the method itself or the type that contains the method, not along with the method parameters that use them.
I have the following method:
public <T> T getObjectFromMessage(Class<T> clazz) {
return gson.fromJson(compressor.decompress(message.getJsonInputs(s3)), clazz);
}
I want to pass getObjectFromMessage as a parameter into a lambda that's supplied to me. The lambda can then supply the class of the object that it expects to find in the message, and get an instance of it back. Is there a way to do this without losing the type information?
I can force it to work with casting and some Object bounds, but I'd really like the consumer to know that if it passes in a Class<T> it will get a T back, much like any method with generic bounds.
In the consuming lambda, I'm currently forced to do declaration gymnastics like:
public void consume(Function<Class<Object>, Object> getInputs){
MyType type = (MyType)getInputs.apply(MyType.class);
}
but there are cases where I want to try to parse the inputs, and if I fail, try a different class. The generics really need to be inferred per-call, as a method would.
You can define a custom function interface with a generic method:
interface TypeFunction {
<T> T apply(Class<T> clazz);
}
public void consume(TypeFunction getInputs) {
MyType type = getInputs.apply(MyType.class);
}
Some thoughts on this... does a function that invokes another function add anything?
For example:
<T> T consume(ReadType<T> typeFunction) {
T type = typeFunction.read();
return type;
}
There are generic types being managed in at least 3 entities here:
The class that contains the message string.
The function that deserializes the message string to an object.
The function that calls the deserializer function.
I expect from the question that the Object that holds the message string is also responsible for deserialization? If so you could consider declaring the generic type there. That would prevent the need of passing the type to the deserializer function, for example this could be simplified further:
<T> ReadType<T> readObjectFromMessage(Class<T> clazz) {
return () -> readValue(clazz);
}
I've declared ReadType as:
interface ReadType<T> {
T read();
}
Also implemented a simple test to check outputs and visualise how this might be used:
#Test
public void consumeTypeTest() throws Exception {
String message = "{\"foo\":\"hello\",\"bar\":\"world\"}";
GenericFunctions genericFunctions = new GenericFunctions(message);
ReadType<MyType> myTypeFromMessage = genericFunctions.readObjectFromMessage(MyType.class);
MyType myType = genericFunctions.consume(myTypeFromMessage);
Assert.assertThat(myType, equalTo(new MyType().setFoo("hello").setBar("world")));
}
In my project I see the interface like this. All the model extend the interface. I am wondering what is the use ?
public interface IModel {
<T> T modelTo(Class<T> clazz);
}
public interface IPerson extends IModel {
public String getFirstName();
public void setFirstName(String firstName);
public String getMiddleName();
public void setMiddleName(String middleName);
}
Then in some places in the code I see like
#Override
public void modelJoin(IModel parent, IModel sample) {
//Some code
IPerson sample= sample.modelTo(IPerson.class);
IPerson person = parent.modelTo(IPerson.class);
//Some code
}
Can you explain me the insight of it ?
It looks like the use of the Adapter pattern. The idea is to create a "view" of a class given another class, or adapt one type of class to act as another.
A simple real world example can be that of electrical sockets. In different countries different types of sockets are used. So you use adapters to plug in your phone into an electrical socket it normally doesn't "recognize".
This can of course be modelled using object oriented programming and the adapter pattern as well. Using your IModel interface but naming it IAdaptable it could be used like this.
public interface IAdaptable {
<T> T adaptAs(Class<T> clazz);
}
public interface IChargeAmerican { void chargePhoneInAmerica(); }
public interface IChargeEurope { void chargePhoneInEurope(); }
public class EuropeanSocket implements IAdaptable, IChargeEurope {
public <T> T adaptAs(Class<T> clazz) {
if (clazz.equals(IChargeAmerican.class)) {
return new EuropeanSocketToAmericanSocketAdapter(this);
}
throw new RuntimeException("unknown");
}
public void chargePhoneInEurope() {
;
}
}
public class AmericanSocket implements IChargeAmerican {
public void chargePhoneInAmerica() {
;
}
}
public class EuropeanSocketToAmericanSocketAdapter implements IChargeAmerican {
private EuropeanSocket socket;
public EuropeanSocketToAmericanSocketAdapter(EuropeanSocket socket) {
this.socket = socket;
}
public void chargePhoneInAmerica() {
socket.chargePhoneInEurope();
}
}
And to use it one would simply adapt the european socket to an american one, sort of like plugging in an adapter in between the two.
public void foo() {
EuropeanSocket europe = new EuropeanSocket();
IChargeAmerican murica = europe.adaptAs(IChargeAmerican.class);
murica.chargePhoneInAmerica();
}
This example shows how the adaptAs method creates a link between the two interfaces IChargeAmerican and IChargeEurope. Even though they don't have anything in common the adapter can act as they do.
Now, the EuropeanSocket implements the IAdaptable interface in order to "convert" itself to another known socket. Usually though the class should not be responsible for this. As the example at wikipedia shows, a factory or provider is better suited for this.
I think that you ask why the method signature
<T> T modelTo(Class<T> clazz);
is used.
The parameter clazz is used to have the type information inside the method implemented. You can then access the type information very easy.
You can then create an object and return it from the implemented method that has the given class.
The method signature looks a bit clumsy but is helpful as the generic information is missing after compilation (type erasure) and the parameters give you the possibility to access the type information (and thereforethe expected return type).
I can imagine it may have been made that way to allow type casting by passing a Class object as a parameter of other methods calling the modelTo(Class clazz) method, or in other words : having other methods casting IModel objects to any class without even knowing which class they will cast it into (nothing even prevents from passing a Class instance to this method which isn't even a subtype of IModel...)
It would be interesting to know how this modelTo method is implemented. Is there a single, final implementation in an abstract skeleton class ? How does it respond to errors (like passing null as the clazz parameter, or triggering a ClassCastException) ? In other words : could this be an attempt to encapsulate all class casts into a single method, to replace ClassCastExceptions with a custom Exception or something like that ? (ClassCastException being a RuntimeException, it could have been a way to make sure a checked exception is thrown instead to enforce explicit exception handling everywhere in the code, I've already seen projects using such an approach...)
I want to receive a function in parameter and call it with one parameter as:
public static <T> T foo(Callable<T> func)
{
return func.call("bar");
}
But it call doesn't take any parameter. Any idea on how can I do this?
No matter how much I search, I dont find anything that help me...
A Callable<T> only has one method: T call().
If you want something different, you will need to use a different parameter type, for example:
public interface CallableWithString<T> {
T call(String arg); //Assuming you want a string argument
}
Then your function can do:
public static <T> T foo(CallableWithString<T> func) {
return func.call("bar");
}
The call method defined in Callable has no parameters defined so you cannot pass anything to it.
Depending on what you want to do exactly you can write your own interface for that:
public interface CallableWithParameters<T> {
public T call(Object... arguments);
}
Then you call it in different ways:
call();
call(someObject);
call("someString", 42);