第53项:慎用可变参数

  可变参数方法,一般称作可匹配不同长度的变量的方法(variable arity methods)[JLS, 8.4.1],可接受零个或者多个指定类型的参数。可变参数机制通过先创建一个数组,数组的大小为在调用位置所传递的参数数量,然后将参数值传递到数组中,最后将数组传递给方法。

  例如,下面就是一个可变参数方法,带有int参数的一个序列,并返回它们的总合。正如你所期望的,sum(1, 2, 3)的值为6,sum()的值为0:

// Simple use of varargs
static int sum(int... args) {
    int sum = 0;
    for (int arg : args)
        sum += arg;
    return sum;
}

  有时候,有必要编写需要一个或者多个某种类型参数的方法,而不是需要零个或者多个。例如,假设想要设计多个int参数的最小值。如果客户端没有传递参数,那这个方法的定义就不太好了。你可以在运行时检查数组长度:

// The WRONG way to use varargs to pass one or more arguments!
static int min(int... args) {
    if (args.length == 0)
        throw new IllegalArgumentException("Too few arguments");
    int min = args[0];
    for (int i = 1; i < args.length; i++)
        if (args[i] < min)
            min = args[i];
    return min;
}

  这种解决方案有几个问题。其中最严重的问题是,如果客户端调用这个方法时,并没有传递参数进去,它就会在运行时失败,而不是在编译时失败,另一个问题是,这段代码很不美观。你必须在args中包含显示的有效性检查,除非将min初始化为Inerger.MAX_VALUE,否则将无法使用for-each循环,这样的代码也不美观。

  幸运的是,有一种更好的方法可以实现想要的这种效果。声明该方法带有两个参数,一个是指定类型的正常参数,另一个是这种类型的可变参数。这种解决方案解决了前一个示例中的所有不足:

// The right way to use varargs to pass one or more arguments
static int min(int firstArg, int... remainingArgs) {
    int min = firstArg;
    for (int arg : remainingArgs)
        if (arg < min)
            min = arg;
    return min;
}

  如你所见,当你真正需要让一个方法带有不定数量的参数时,可变参数就非常有效。可变参数是为printf(跟可变参数同时添加到平台)和改装后的反射机制的核心(第65项)而设计的,printf和反射都从可变参数中获益匪浅( Varargs were designed for printf, which was added to the platform at the same time as varargs, and for the core reflection facility (Item 65), which was retrofitted. Both printf and reflection benefited enormously from varargs)。

  在性能要求高的情况下要小心使用可变参数。每次调用可变参数方法都会导致数组分配【内存】和初始化。如果你根据经验确定你不能承担这笔花费【代价】,但你需要可变参数的灵活性,有一种模式可以让你吃掉这块蛋糕(there is a pattern that lets you have your cake and eat it too)。假设您已确定95%的方法调用具有三个或更少的参数。 然后声明方法的五个重载,一个用零到三个普通参数,并且当参数个数超过三个时使用单个可变参数方法:

public void foo() { }
public void foo(int a1) { }
public void foo(int a1, int a2) { }
public void foo(int a1, int a2, int a3) { }
public void foo(int a1, int a2, int a3, int... rest) { }

  现在您知道,只有在参数数量超过3的所有调用的5%中,您才需要支付数组创建的成本。 像大多数性能优化一样,这种技术通常是不合适的,但是当它成功时,它就是救星。

  EnumSet的静态工厂使用此技术将创建枚举集的成本降至最低。这是合适的,因为提供一种具有性能竞争力的【做法】来替代位域是至关重要的(第36项)。

  总之,当您需要定义参数数量不确定的方法时,可变参数非常有用。在可变参数前加上任何必需的参数,并注意使用可变参数的性能后果。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值