Dynamic Return Type in Java method

前端 未结 5 1927
隐瞒了意图╮
隐瞒了意图╮ 2021-02-02 14:20

I\'ve seen a question similar to this multiple times here, but there is one big difference.

In the other questions, the return type is to be determined by the parameter.

相关标签:
5条回答
  • 2021-02-02 14:48

    This CAN be done. The following code will work:

    public byte BOOLEAN = 1;
    public byte FLOAT = 2;
    public static <Any> Any getParam(byte[] data) {
        if (data[0] == BOOLEAN) {
            return (Any)((Boolean)(boolean)(data[1] != 0));
        } else if (data[0] == FLOAT) {
            return (Any)((Float)(float)data[1]);
        } else {
            return null;
        }
    }
    

    By using a generic for the return type any Java method can dynamically return any object or primitive types. You can name the generic whatever you want, and in this case I called it 'Any'. Using this code you avoid casting the return type when the method is called. You would use the method like so:

    byte[] data = new byte[] { 1, 5 };
    boolean b = getParam(data);
    data = new byte[] { 2, 5 };
    float f = getParam(data);
    

    The best you can do without this trick is manually casting an Object:

    float f = (float)getParam(data);
    

    Java dynamic return types can reduce boilerplate code.

    0 讨论(0)
  • 2021-02-02 14:50

    If you are really only returning a boolean or a float, then the best you can do is Object.

    If you are returning variable objects, you have to choose a return type with the least common superclass. Primitives don't have a superclass, but they will be boxed into Object representations (like Boolean and Float) which have a common superclass of Object.

    0 讨论(0)
  • 2021-02-02 14:57

    I don't know what these people are talking about. You lose type safety, which is a concern, but you could easily accomplish this with generics...something like:

    public <T> T getSomething(...) { }
    

    or

    interface Wrapper<T> { T getObject(); }
    
    public <T> Wrapper<T> getSomething(...) { }
    

    The latter promotes the possibility of a strategy pattern. Pass the bytes to the strategy, let it execute and retrieve the output. You would have a Byte strategy, Boolean strategy, etc.

    abstract class Strategy<T> {
        final byte[] bytes;
    
        Strategy(byte[] bytes) { this.bytes = bytes; }
    
        protected abstract T execute();
    }
    

    then

    class BooleanStrategy extends Strategy<Boolean> {
        public BooleanStrategy(byte[] bytes) { super(bytes); }
    
        @Override
        public Boolean execute() {
            return bytes[0] != 0;
        }
    
    }
    

    Your example code is a bad use case though and I wouldn't recommend it. Your method doesn't make much sense.

    0 讨论(0)
  • 2021-02-02 14:57

    My 2 cents with an example with Google HTTP client:

    static public <Any> Any getJson(final String url, final Class<Any> parseAs) throws IOException {
            HttpRequestFactory requestFactory
                    = HTTP_TRANSPORT.createRequestFactory(
                    (HttpRequest request) -> {
                        request.setParser(new JsonObjectParser(JSON_FACTORY));
                    });
    
            HttpRequest request = requestFactory.buildRequest(HttpMethods.GET, new GenericUrl(url), null);
    
            return request.execute().parseAs(parseAs);
        }
    

    Can be use like this:

    HashMap<String, Object> out = HttpUtils.getJson( "https://api.qwant.com", HashMap.class);
    
    0 讨论(0)
  • 2021-02-02 15:04

    You can't do it. Java return types have to be either a fixed fundamental type or an object class. I'm pretty sure the best you can do is return a wrapper type which has methods to fetch various possible types of values, and an internal enum which says which one is valid.

    --- edit --- after Danieth's correction!

    public <Any> Any getParam(boolean b){
    return((Any)((Boolean)(!b)));
    }
    public <Any> Any getParam(float a) {
     return((Any)((Float)(a+1)));
    }
    public <Any> Any getParam(Object b) {
     return((Any)b);
    }
    public void test(){
      boolean foo = getParam(true);
      float bar = getParam(1.0f);
      float mumble = getParam(this); // will get a class cast exception
    }
    

    You still incur some penalties for boxing items and type checking the returned values, and of course if your call isn't consistent with what the implementations of getParam actually do, you'll get a class cast exception.

    0 讨论(0)
提交回复
热议问题