使用数组作为参数返回多个值是不好的做法

时间:2013-02-11 20:18:49

标签: java

我有时(实际上,经常)发现自己使用单元素数组从方法返回多个值。像这样:

public static int foo(int param1, int param2[], String param3[])
{
    // method body
    ....
    // set return values
    param2[0] = <some value>;
    param3[0] = <some value>;

    return <some value>;
}

这是一种不好的做法吗? (好像是因为我的一些朋友说他们不知道它在做什么2秒!) 但我首先使用它的原因是因为它看起来与C ++中的pass-by-reference最接近。 C++并没有气馁这种做法,所以......

但如果这确实是一种错误的做事方式,那么任何想法如何以干净的方式重写它?

由于

7 个答案:

答案 0 :(得分:6)

创建一个包含要返回的数据的对象。

然后您可以返回该对象的实例。

class FooData {
    private int someInt;
    private int anotherInt;
    private String someString;

    public FooData(int a, int b, String c) {
        someInt = a;
        anotherInt = b;
        someString = c;
    }
}

public FooData foo() {
    // do stuff
    FooData fd = new FooData(blah, blahh, blahhh);
    return fd;
}

答案 1 :(得分:5)

虽然我同意这里的一般意见,为此目的使用数组是不好的做法,但我想补充一些内容。 您确定首先通过“参考传递”确实是您所需要的吗? 很多人说你的代码风格不好,但现在让我告诉你为什么那是恕我直言。 “通过引用传递”主要是“通过副作用编程”的同义词,这是你总是想要避免的事情。它使代码更难以调试和理解,并且在多线程环境中,这种态度的不良影响确实会给你带来困难。 要在Java中编写可伸缩且线程安全的代码,您应该尽可能地使对象“只读”,即理想情况下,您创建一个对象并同时对其进行初始化,然后在整个应用程序中使用此不可修改的状态。对状态的逻辑变化几乎总是被认为是新状态的“创建”,即创建初始化为当时所需状态的新实例。许多现代脚本语言只允许您以这种方式工作,它使事情更容易理解。 与C ++相反,Java在分配和释放短期对象方面效率更高,因此其他人建议的内容实际上没有任何问题:创建一个特殊类的实例来保存函数结果,仅用于此目的返回结果。即使你在循环中这样做,JVM也足够聪明,可以有效地处理它。 Java只会在需要时以非常大的块分配来自操作系统的内存,并且将在内部处理对象创建和释放,而不会产生C / C ++等语言的开销。 “通过引用传递”对Java非常有用。

编辑:我建议你在这个论坛或网上搜索术语“副作用”,“函数式编程”或“不变性”。这很可能会为您的问题打开一个新的视角。

答案 2 :(得分:4)

我认为使用作为方法参数的单元素数组“返回”值是不好的做法。

这是关于此主题的another SO question。简而言之,它的可读性非常糟糕。

有一个简单的解决方法:在您专门为此目的定义的类中包装您希望返回的所有值,并返回该类的实例。

return new ValueHolder(someValue1, someValue2, someValue3);

答案 3 :(得分:3)

这不是非常惯用的java。通常有更好的软件设计方法。

你真正用“单元素数组”做的是创建一个可变对象(因为String是不可变的,就像int这样的基元)并通过引用传递它。修改此可变对象称为该方法的“副作用”。通常,您应该最小化可变性(Effective Java Item 15),并且您的方法应该是无副作用的。这里有几种方法。

1。将方法拆分为两个(或三个)方法,所有方法都采用相同的参数:

public static int foo1(int param1)
{
    // method body
    ....
    return <some value>;
}

同样,你可能有

public static int foo2(int param1) { ... }

public static String foo3(int param1) { ... }

2。返回一个复合对象。

public Container {
    private final int originalReturn;
    private final int param2;
    private final String param3;

    public Container(int originalReturn, int param2, String param3) {
        this.originalReturn = originalReturn;
        this.param2 = param2;
        this.param3 = param3;
    }

    // getters
}

public static Container foo(int param1, int param2[], String param3[])
{
    // method body
    ....
    // set return values
    return new Container(<some value>, <some value>, <some value>);
}

答案 4 :(得分:2)

如果值不相关,这确实是不好的做法。这通常是一个指示器,您可以将该函数拆分为两个,每个函数返回一个值。

编辑:

我假设您要返回在数组中的方法中计算的两个值。情况不是这样吗?

e.g。

public int[] getStatistics(int[] nums)
{
    //code

    int[] returns = new int[2];
    returns[0] = mean;
    returns[1] = mode;

    return returns;
}

上述功能可以分为getMean()getMode()

答案 5 :(得分:1)

通过引用传递变量允许函数“合法地”改变它们的值。请参阅this article以清除Java中何时可能存在的混淆,以及何时不能......

答案 6 :(得分:1)

如果值具有不同类型和不同实体,则这是不好的做法,例如名称和地址等。创建一个具有相同数据类型的数组,例如地址列表。