Java方法返回对象还是直接操作对象?

8

我遇到了这段(对我来说有点奇怪)的代码。我从未见过它被使用,也从未使用过它,因此它让我感到相当困惑... 大致如下:

  • 这里以哈希表为例,但其他对象会表现相同
public static void fillData(HashMap<Object, Object> dataMap){
    dataMap.put("key","value");
}

现在这很令人困惑,因为我学习的方法更像是这样
public static HashMap<Object, Object> fillData(){
    HashMap<Object, Object> dataMap = new HashMap<>();
    dataMap.put("key","value");
    return dataMap;
}

现在有没有一种情况,我应该使用其中一种?我还是编程新手,但我没找到关于这种结构的太多信息。

我也进行了实验,并发现这仅适用于对象,而不适用于基本类型...


2
通常情况下,您应该尽量避免修改参数,但有些情况下这是不可能的。 - Peter Lawrey
这个问题和答案也可能有所帮助:https://dev59.com/WVzUa4cB1Zd3GeqP5q8- - Nick DeFazio
顺便提一下:基本数据类型是按值传递的,因此在方法中您只能操作副本,对调用方没有影响。 - Arne Burmeister
5个回答

3

好的,考虑一下方法操作一个已有非空映射的情况。在这种情况下,第一个示例是完全有意义的。


2
我遵循的做法基于两种情况:
情况1. 如果调用方法对传递给该方法的复杂对象进行更改,则修改传递的对象并从方法返回空(void)更有意义。在Java中,对象是按值传递的(这里的“值”指复制并传递的对象引用信息),因此任何修改都将更新对象的主副本,并且不需要从方法返回任何内容。
情况2. 如果调用方法利用传递的复杂对象,运行一些逻辑并准备另一种类型的复杂对象,则从方法创建并返回此新对象更有意义。
回到你的问题 - 这是一个静态方法,因此与实例无关。我再想到了两种可能的情况:
情况1- 如果您的“dataMap”可以在此方法调用之前初始化,并且它可能已经具有其他键值对,则更简单的方法是传递此“dataMap”并让方法使用附加的键值对更新此同一映射。在这种情况下不会返回任何内容。

场景2- 如果您的“dataMap”在此方法调用之前始终应该是一个新的空映射,那么我不认为有任何理由创建Map实例并将其传递给该方法。如果该方法创建此映射并将其作为方法返回参数返回,则代码行数将更少,更简单。

两种方式根据给定的情况具有它们各自的适用性,我不会说哪一种比另一种更好。


2

今天早上我在谷歌搜索了这个主题,发现了这篇讨论。其中提到第一种形式的修改参数是反模式。

public static void fillData(HashMap<Object, Object> dataMap){
    dataMap.put("key","value");
}

被视为“一种不良实践,遗迹或面向过程编程(pre-OOP)时代的产物。”


1
在Java中,方法参数可以持有指向对象的非原始类型引用。以您的示例为例。
public static void fillData(HashMap<Object, Object> dataMap){
    dataMap.put("key","value");
}

dataMap引用一个对象,对该对象的任何更改都会影响到整个系统引用该对象的部分。

例如:

public static void fillAll(){
        HashMap<Object, Object> dataMap1 = new HashMap<>();
        HashMap<Object, Object> dataMap2 = dataMap;
        HashMap<Object, Object> dataMap3 = dataMap;
        //dataMap1, dataMap2, dataMap3 are same object's references.
        fillData1(dataMap1);
        fillData2(dataMap2);
        fillData3(dataMap3);
        //here dataMap1 holds 3 different values in it.
        //dataMap2, dataMap3 still same as dataMap1 
        dataMap3 = new HashMap<>();
        //here dataMap3 have a new object's reference but dataMap1 and dataMap2 still have 3 values in the map object.
        //primitive types are different they are holding values directly.
        int x = 5;
        int y = x;
        x++; //now x value is 6 but y value is still 5
}

public static void fillData1(HashMap<Object, Object> dataMap){
    dataMap.put("key1","value1");
}

public static void fillData2(HashMap<Object, Object> dataMap){
    dataMap.put("key2","value2");
}

public static void fillData3(HashMap<Object, Object> dataMap){
    dataMap.put("key3","value3");
}

0
让我们来看看这些API的用法(将HashMap替换为Map,使用接口而不是具体实现总是更好的):
Map<Object, Object> data = new Map<>();
fillData(data);

这样的传递参数会创建API中看不到的副作用代码。因此最好让方法返回结果,这样它可以变得更加流畅:

Map<Object, Object> data = fillData(new HashMap<>());

如果在地图中已经存在“key”的值会发生什么?它会被替换还是不会被替换?该方法也可以通过返回原始地图的副本使其摆脱副作用:

public static Map<Object, Object> filledData(Map<Object, Object> original) {
    Map<Object, Object> result = new HashMap<>(original);
    result.put("key","value");
    return result;
}

函数式编程方法与初始状态无关:

Map<Object, Object> data = createFilledData();

使用什么取决于要求,一如既往。这是公共API还是内部辅助方法?谁会使用它,新手还是专家?性能如何?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接