一文读懂《Effective Java》第42条:慎用可变参数

本文介绍了Java 1.5引入的可变参数机制,包括其实现原理、使用示例及注意事项,探讨了可变参数对性能的影响,并给出了优化建议。

点击上方「蓝字」关注我们

在Java1.5发行版中,加入了可变参数列表方法,称为variable arity method(可匹配不同长度的变量的方法)。

可变参数机制:通过创建一个数组,数组的大小为在调用位置所传递的参数数量,然后将参数值传到数组中,最后将数组传递给方法。

可变参数使用

我们通过例子简单了解可变参数的使用:

private static int sum (int... args){
  int sum = 0;
  for (int arg : args){
  sum += arg;
  }
  return sum;
}

再看一个例子,我们可以在代码运行时检测可变参数数组长度:

  private int min (int... args) throws IllegalAccessException {
    if (args.length == 0){
      throw new IllegalAccessException("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 初始化为 Integer.MAX_VALUE,否则无法进行for-each 循环。

有种更好的方法实现上面没有的效果:方法参数改为,一个是指定类型的正常参数,另一个是这种类型的varagas参数。

  private int min(int firstArg, int... args){
    int min = firstArg;
    for (int i = 1; i < args.length; i++){
      if (args[i] < min){
        min = args[i];
      }
    }
    return min;
  }

可变参数对Arrays.asList的影响

在Java1.5发行版之前,打印数组内容常用做法是:

List<String> homophones = Arrays.asList("a", "b");
System.out.println(homophones);

因为数组的元素类型是包装类 String,因此从Object 继承了它们的toString 实现,这是有效的。

int[] args = {3,1,4,1,5,9,2,6,5,4};
System.out.println(Arrays.asList(args));

但如果数组元素是基本类型,我们尝试这么做,在java发行版1.4会抛出异常。

如果是java发行版1.5之后,程序运行结果会产生无意义字符串:[[I@27bc2616]。

  private static void testArraysAsList(){
    int[] args = {3,1,4,1,5,9,2,6,5,4};
    System.out.println(Arrays.toString(args));
  }

对此,java1.5 发行版给Arrays 类补充完整的 Arrays.toString 方法(不是可变参数!),专门为了将任何类型的数组转变为字符串而设计。

可变参数与性能

在重视性能的情况下,使用可变参数机制要特别小心。可变参数方法的每次调用都会导致进行一次数组分配和初始化。

如果凭借经验无法承受这一成本,但又需要可变参数的灵活性,有一种模式可以实现:

假设某个方法95% 调用会有3个或者更少的参数,就声明该方法的5个重载,每个重载方法带有1至3个普通参数,当参数的数目超过3个时,就使用一个可变参数方法。

public interface VarargsInterface {
  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);  
}

EnumSet 类对它的静态工厂就是使用了这个方法,以最大限度的减少创建枚举集合的成本。

总结

简而言之,在定义参数数目不定的方法时,可变参数是一种方便的方式。但是,我们不应该滥用可变参数,使用不当会产生混乱结果。

—END—

扫描二维码

获取知识干货

后台技术汇

点个“在看”表示朕

已阅

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

后台技术汇

对你的帮助,是对我的最好鼓励。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值