8

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

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

我只是想通过这个例子来阐述这个问题。

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;
}

我知道一个通​​过参考,另一个没有。

我们应该更喜欢哪一个(在不同的情况下),为什么?

更新:仅考虑可变对象。

4

6 回答 6

17

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

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

不过也有例外。

考虑 的例子Collections.sort,它实际上做了一个就地排序的列表。想象一下包含 100 万个项目的列表,而您正在对其进行排序。也许您不想创建另一个包含 100 万个条目的列表(即使这些条目指向原始条目)。

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

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

于 2012-05-01T20:58:23.810 回答
7

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

首先,它更清楚。当其他人阅读您的代码时,他们可能不会注意到参数正在被修改为输出。您可以尝试命名变量,但在代码可读性方面,它更可取。

您应该返回它而不是传递它的重要原因是使用不可变对象。 您的示例 List 是可变的,因此可以正常工作。但是,如果您尝试以这种方式使用 String,它将无法正常工作。

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

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

您传入的结果值不会被更改。相反,局部范围变量“result”现在指向 fun 内部的一个新字符串,但调用方法中的结果仍然指向原始字符串。

如果您致电:

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

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

因此,绝对是返回是优越的。:)

于 2012-05-01T20:59:07.103 回答
1

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

函数 IsThisNumberAPrimeNumber{ }

然后你知道这只会返回一个布尔值。我通常将函数用作辅助程序而不是大型子程序。我还应用了命名约定,这些约定有助于规定我期望 sub\function 将返回的内容。例子:

GetUserDetailsRecords GetUsersEmailAddress IsEmailRegistered

如果您查看这 3 个名称,您会发现第一个名称将为您提供多个用户详细记录的列表或类别,第二个将为您提供电子邮件的字符串值,第三个可能会为您提供布尔值。如果你改变名字,你就会改变意思,所以我想说另外考虑一下。

于 2012-05-01T20:26:17.930 回答
1

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

如果您的意思是这两个动作之间的区别:

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

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

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

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

于 2012-05-01T20:29:34.553 回答
1

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

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

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

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;
    }
}
于 2020-05-09T03:20:04.170 回答
0

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

于 2012-05-01T20:24:08.790 回答