传递参数与从函数返回参数

时间:2012-05-01 20:18:02

标签: java parameter-passing pass-by-reference

从标题中可以清楚地看出我们应该采用哪种方法?

意图是传递一些方法参数并获得输出。我们可以传递另一个参数,方法会更新它,方法现在不需要返回任何东西,方法只会更新输出变量,它会反映给调用者。

我只想通过这个例子来构建问题。

List<String> result = new ArrayList<String>();

for (int i = 0; i < SOME_NUMBER_N; i++) {
    fun(SOME_COLLECTION.get(i), result);
}

// in some other class
public void fun(String s, List<String> result) {
    // populates result
}

List<String> result = new ArrayList<String>();

for (int i = 0; i < SOME_NUMBER_N; i++) {
    List<String> subResult = fun(SOME_COLLECTION.get(i));
    // merges subResult into result
    mergeLists(result, subResult);
}

// in some other class
public List<String> fun(String s) {
    List<String> res = new ArrayList<String>();
    // some processing to populate res
    return res;
}

我知道一个人通过了参考而另一个没有。

我们应该选择哪一种(在不同情况下)以及为什么?

更新:仅考虑可变对象。

6 个答案:

答案 0 :(得分:16)

从函数返回值通常是编写代码的更简洁方法。由于创建和销毁指针的性质,传递值并修改它是更多的C / C ++风格。

开发人员通常不希望通过传递函数来修改它们的值,除非函数明确指出它修改了值(我们经常浏览文档)。

但也有例外。

考虑一下Collections.sort的例子,它实际上确实做了一个列表。想象一下包含100万件物品的清单,你正在对它进行分类。也许你不想创建另外有100万个条目的第二个列表(即使这些条目指向原始条目)。

支持使用不可变对象也是一种好习惯。不可变对象在开发的大多数方面(例如线程)导致的问题要少得多。因此,通过返回一个新对象,您不会强制参数变为可变。

重要的是要明确你对方法的意图。我的建议是尽可能避免修改参数,因为它不是Java中最典型的行为。

答案 1 :(得分:7)

你应该退货。你提供的第二个例子是要走的路。

首先,它更清晰。当其他人阅读您的代码时,他们可能没有注意到参数被修改为输出。您可以尝试命名变量,但是当涉及到代码可读性时,它更可取。

BIG原因为什么你应该返回它而不是传递它,是不可变对象。 你的例子,List,是可变的,所以它可以正常工作。 但是如果你试图以这种方式使用String,那么就行不了。

由于字符串是不可变的,如果你将一个字符串作为参数传入,然后函数说:

public void fun(String result){
    result = "new string";
}

您在中传递的结果值不会被更改。相反,本地范围变量'result'现在指向fun中的新字符串,但调用方法中的结果仍然指向原始字符串。

如果您致电:

String test = "test";
fun(test);
System.out.println(test);

它将打印:“test”,而不是“new string”!

所以当然,它优于回归。 :)

答案 2 :(得分:1)

返回它将使代码更清晰,并减少方法/类之间的耦合。

答案 3 :(得分:1)

根据伙计们的推荐和Java代码约定以及语法限制,这是一个坏主意,使代码更难以理解 但是您可以通过实现引用持有人类来做到这一点

public class ReferenceHolder<T>{
        public T value;
}

,并将ReferenceHolder对象传递到要由方法填充或修改的方法参数中。 另一方面,该方法必须将其返回值分配给Reference值,而不是返回它。 这是通过ReferenceHolder而不是函数return来获取平均方法结果的代码。

public class ReferenceHolderTest {
    public static void main(String[] args) {
        ReferenceHolder<Double> out = new ReferenceHolder<>();
        average(new int[]{1,2,3,4,5,6,7,8},out);
        System.out.println(out.value);
    }

    public static void average(int[] x, ReferenceHolder<Double> out ) {
        int sum=0;
        for (int a : x) {
            sum+=a;
        }
        out.value=sum/(double)x.length;
    }
}

答案 4 :(得分:0)

这更多是关于最佳实践和您自己的编程方法。我想说如果你知道这将是一个值返回类型函数,如:

function IsThisNumberAPrimeNumber {}

然后你知道这只会返回一个布尔值。我通常使用函数作为帮助程序而不是大的子程序。我还应用命名约定来帮助指示我期望sub \ function将返回的内容。 例子:

GetUserDetailsRecords GetUsersEmailAddress IsEmailRegistered

如果你看看这3个名字,你可以告诉第一个是给你一些列表或类的多个用户详细记录,第二个会给你一个电子邮件的字符串值,第三个可能会给你一个布尔值。如果您更改名称,则更改含义,因此我会另外考虑这一点。

答案 5 :(得分:0)

我认为我们不理解的原因是这两种行为完全不同。将变量传递给函数是一种提供函数数据的方法。从函数返回它是一种将数据传递出函数的方法。

如果你的意思是这两个行动之间的区别:

public void doStuff(int change) {
    change = change * 2;
}

public void doStuff() {
    int change = changeStorage.acquireChange();
    change = change * 2;
}

然后第二个通常更干净,但有几个原因(安全性,功能可见性等)可能会阻止您以这种方式传递数据。

这也是首选,因为它使重用代码更容易,并使其更加模块化。