Java接受不同类型的参数而不会重载

时间:2018-08-06 18:04:21

标签: java java-8

这是一个非常简单的示例:

private boolean f(List x) {
    return x != null && !x.isEmpty();
}

private boolean f(Map x) {
    return x != null && !x.isEmpty();
}

两个函数中的代码相同,它们只是在不同的对象上操作。我想将它们合并为一个函数,以避免代码重复。

我尝试了以下方法:

private <T> boolean f(T x) {
    return x != null && !x.isEmpty();
}

但是它给x.isEmpty()

带来了错误

6 个答案:

答案 0 :(得分:13)

两个类都实现的接口覆盖了要使用的部分时,请使用该接口。

但是在您的情况下,$a[0]= "google"; $a[1]= "yahoo"; $a[2]= "Bing"; $b= "Bing is Good"; strpos($b, $a[0]); // false strpos($b, $a[1]); // false strpos($b, $a[2]); // true as Bing found List不共享提供Map的接口,因此您可以选择:

  1. 重载(以下代码不变)

    isEmpty
  2. 接受private boolean f(List x) { return x != null && !x.isEmpty(); } private boolean f(Map x) { return x != null && !x.isEmpty(); } 并使用Object分支

    instanceof
  3. 接受private boolean f(Object x) { // (roughly) if (x == null) { return false; } if (x instanceof List) { return !((List)x).isEmpty(); } if (x instanceof Map) { return !((Map)x).isEmpty(); } throw new IllegalArgumentException(); // Or whatever } 并使用反射来获取Object方法(如果有)并调用它

    isEmpty

在这些方法中,重载对我来说似乎是最干净的方法,这尤其重要,因为如果您尝试在其中使用private boolean f(Object x) { // (roughly) try { return x != null && !(boolean)x.getClass().getMethod("isEmpty").invoke(x); } catch (Exception e) { throw new IllegalArgumentException(); // Or whatever } } ,则会给您一个编译时错误一种无法处理的类型(而其他类型则是运行时错误,很容易出错),但这(至少是轻微的)是一种见解。

答案 1 :(得分:3)

您想使用一个共同的祖先接口来多态地同时引用列表和地图,但遗憾的是不存在。由于Java是严格类型化的,因​​此编译器正在寻找与该签名匹配的方法定义,该签名无法找到。

您不能完全按照要求的方式来做。

看看Apache commons如何使用instanceof将此类型转换为相关类型org.apache.commons.collections.CollectionUtils#sizeIsEmpty

来解决此问题。
public static boolean sizeIsEmpty(Object object) {
    if (object instanceof Collection) {
        return ((Collection) object).isEmpty();
    } else if (object instanceof Map) {
        return ((Map) object).isEmpty();
    } else if (object instanceof Object[]) {
        return ((Object[]) object).length == 0;
    } else if (object instanceof Iterator) {
        return ((Iterator) object).hasNext() == false;
    } else if (object instanceof Enumeration) {
        return ((Enumeration) object).hasMoreElements() == false;
    } else if (object == null) {
        throw new IllegalArgumentException("Unsupported object type: null");
    } else {
        try {
            return Array.getLength(object) == 0;
        } catch (IllegalArgumentException ex) {
            throw new IllegalArgumentException("Unsupported object type: " + object.getClass().getName());
        }
    }
}

答案 2 :(得分:1)

您可以尝试以下操作:

private Object boolean f(Object x) {
    if (x instanceof List) {
        List l = (List)x;
        return !l.isEmpty();
    } else if (x instanceof Map) {
        Map m = (Map)x;
        return !m.isEmpty();
    }
    return false;
}

答案 3 :(得分:1)

由于isEmpty()并非从公共接口继承而来,所以您不能做到。一种解决方法是接受确定为空的谓词:

private static <T> boolean isNonEmpty(T value, Predicate<T> isEmpty) {
    return value != null && !isEmpty.test(value);
}

样品使用:

isNonEmpty(Arrays.asList(1, 2, 3), List::isEmpty)
isNonEmpty(new HashMap<>(), Map::isEmpty)
isNonEmpty("foo", String::isEmpty)

可以说,这种辅助方法并不是全部有用。

答案 4 :(得分:0)

自从标记了以来,您就可以成为Optional类。

public class BaseController : Controller
{
    public ApplicationDbContext _db;

    public BaseController(ApplicationDbContext db)
    {
        _db = db;
        ViewData["MyKey"] = _db.MyTable.ToList();
    }
}

一些例子:

private static boolean isEmpty(Optional<Collection> collection){
    return collection.map(Collection::isEmpty).orElse(false);
}

输出:

public static void main(String[] args) {
    ArrayList arrayList = null;
    System.out.println(isEmpty(Optional.ofNullable(arrayList)));

    Map map = null;
    //Convert Map entries to entryset (Collection) via Optional::map
    System.out.println(isEmpty(Optional.ofNullable(map).map(Map::entrySet)));
}

答案 5 :(得分:0)

我喜欢T.J.Crowder's answer中的第3点,但是我会使用稍微不同的方法(并且速度更快):

private static boolean f(Object x) {
    MethodType methodType = MethodType.methodType(boolean.class);
    Lookup l = MethodHandles.lookup();
    try {
        MethodHandle handle = l.findVirtual(x.getClass(), "isEmpty", methodType);
        return (boolean) handle.invoke(x);
    } catch (Throwable e) {
        throw new RuntimeException(e);
    }
}