【问题标题】:Passing a parameter versus returning it from function传递参数与从函数返回参数
【发布时间】:2012-05-11 08:06:54
【问题描述】:

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

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

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

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

我知道一个通​​过引用而另一个不通过。

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

更新:只考虑可变对象。

【问题讨论】:

  • 我不确定你在问什么。您是否问在什么情况下应该将变量传递给方法,而不是在方法中使用 getArg() 或任何可能调用的方法获取它?
  • 不,你误会了,或者我无法传达。我在问:我们应该将变量作为引用传递给函数还是从函数中返回?在什么情况下我们应该使用其中任何一个?希望,我很清楚!

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


【解决方案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;
    }
}

【讨论】:

    【解决方案2】:

    你应该把它退回来。你提供的第二个例子就是要走的路。

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

    您应该返回它而不是传递它的重要原因在于不可变对象。 您的示例 List 是可变的,因此可以正常工作。 但是,如果您要尝试以这种方式使用字符串,就行不通了。

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

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

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

    如果你打电话:

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

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

    因此,返回当然更好。 :)

    【讨论】:

    • 是的!据我了解,问题仅针对可变对象!谢谢你的回复!
    • 没问题。是的,对于可变对象它可以工作,并且在某些情况下它会更好(你不能在不使用元组的情况下返回多个对象)但通常如果它们都相同,返回是更好的代码风格。
    【解决方案3】:

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

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

    但也有例外。

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

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

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

    【讨论】:

      【解决方案4】:

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

      如果你指的是这两个动作的区别:

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

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

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

      它也更可取,因为它可以更轻松地重用代码,并使其更加模块化。

      【讨论】:

        【解决方案5】:

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

        函数 IsThisNumberAPrimeNumber{ }

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

        GetUserDetailsRecords 获取用户电子邮件地址 IsEmailRegistered

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

        【讨论】:

          【解决方案6】:

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

          【讨论】:

            猜你喜欢
            • 2018-04-09
            • 2018-11-27
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多