方法参数泛型_无参数泛型方法反模式

本文讨论了在Java中无参数泛型方法的问题,指出(几乎)不应仅在返回类型上使用泛型。作者通过例子说明了这种方法可能导致的不安全性,并提到了函数式编程中对无副作用的期望。文章还提供了代码示例,帮助开发者识别并避免此类反模式。
摘要由CSDN通过智能技术生成

方法参数泛型

最近,有关Java泛型的一个非常有趣的问题发布到Stack Overflow和reddit上。 请考虑以下方法:

<X extends CharSequence> X getCharSequence() {
    return (X) "hello";
}

尽管这种不安全的转换看起来有些古怪,并且您可能会猜这里有些问题,但是您仍然可以继续并在Java 8中编译以下赋值:

Integer x = getCharSequence();

这显然是错误的,因为Integerfinal ,因此没有可能也可以实现CharSequence Integer子类型。 但是,Java的泛型类型系统并不关心类是否为final final,因此,在将交集类型转换回Integer之前,它会推断X的交集类型Integer & CharSequence 。 从编译器的角度来看,一切都很好。 在运行时: ClassCastException

尽管上面的内容“显然是可疑的”,但真正的问题出在其他地方。

(几乎)永远不会使方法仅在返回类型上通用

此规则有例外。 这些异常是类似的方法:

class Collections {
    public static <T> List<T> emptyList() { ... }
}

此方法没有参数,但返回通用List<T> 。 无论<T>的具体推论如何,为什么都能保证正确性? 由于其语义。 无论您要查找的是一个空的List<String>还是一个空的List<Integer> ,由于是空的(并且是不可变的!)语义,尽管擦除,都可以为这些T中的任何一个提供相同的实现。

另一个例外是构建器,例如javax.persistence.criteria.CriteriaBuilder.Coalesce< ,它是通过通用的无参数方法创建的:

<T> Coalesce<T> coalesce();

生成器方法是最初构造空对象的方法。 空虚是关键。

但是,对于大多数其他方法,这是不正确的,包括上述的getCharSequence()方法。 此方法唯一保证的正确返回值是null

<X extends CharSequence> X getCharSequence() {
    return null;
}

…因为在Java中, null是可以分配(和强制转换)给任何引用类型的值。 但这不是该方法作者的意图。

考虑函数式编程

方法是函数(大部分是函数),因此,预期不会有任何副作用。 无参数函数应始终返回完全相同的返回值。 就像emptyList()一样。

但是实际上,这些方法并不是没有参数的。 它们确实具有类型参数<T><X extendds CharSequence> 。 同样,由于泛型类型擦除,此参数在Java中“并未真正计数”,因为缺乏规范化,因此无法从方法/函数内部进行自省。

因此,请记住以下几点:

(几乎)永远不会使方法仅在返回类型上通用

最重要的是,如果您的用例只是为了避免Java 5之前的版本转换,例如:

Integer integer = (Integer) getCharSequence();

是否想在您的代码中找到令人讨厌的方法?

我正在使用番石榴来扫描类路径,您可能还会使用其他东西。 此代码段将在类路径上生成所有通用的无参数方法:

import java.lang.reflect.Method;
import java.util.Comparator;
import java.util.stream.Stream;
 
import com.google.common.reflect.ClassPath;
 
public class Scanner {
 
    public static void main(String[] args) throws Exception {
        ClassPath
           .from(Thread.currentThread().getContextClassLoader())
           .getTopLevelClasses()
           .stream()
           .filter(info -> !info.getPackageName().startsWith("slick")
                        && !info.getPackageName().startsWith("scala"))
           .flatMap(info -> {
               try {
                   return Stream.of(info.load());
               }
               catch (Throwable ignore) {
                   return Stream.empty();
               }
           })
           .flatMap(c -> {
               try {
                   return Stream.of(c.getMethods());
               }
               catch (Throwable ignore) {
                   return Stream.<Method> of();
               }
           })
           .filter(m -> m.getTypeParameters().length > 0 && m.getParameterCount() == 0)
           .sorted(Comparator.comparing(Method::toString))
           .map(Method::toGenericString)
           .forEach(System.out::println);
    }
}

翻译自: https://www.javacodegeeks.com/2016/04/parameterless-generic-method-antipattern.html

方法参数泛型

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值