是否应该使用 Java 方法参数来返回多个值?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/724199/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Should Java method arguments be used to return multiple values?
提问by euphoria83
Since arguments sent to a method in Java point to the original data structures in the caller method, did its designers intend for them to used for returning multiple values, as is the norm in other languages like C ?
由于在 Java 中发送到方法的参数指向调用者方法中的原始数据结构,它的设计者是否打算让它们用于返回多个值,就像 C 等其他语言中的规范一样?
Or is this a hazardous misuse of Java's general property that variables are pointers ?
或者这是对 Java 的一般属性的危险滥用,即变量是指针?
采纳答案by TofuBeer
A long time ago I had a conversation with Ken Arnold (one time member of the Java team), this would have been at the first Java One conference probably, so 1996. He said that they were thinking of adding multiple return values so you could write something like:
很久以前,我与 Ken Arnold(Java 团队的前任成员)进行过一次对话,这可能是在第一次 Java One 会议上,所以是 1996 年。他说他们正在考虑添加多个返回值,以便您可以写一些类似的东西:
x, y = foo();
The recommended way of doing it back then, and now, is to make a class that has multiple data members and return that instead.
当时和现在推荐的做法是创建一个具有多个数据成员的类并返回它。
Based on that, and other comments made by people who worked on Java, I would say the intent is/was that you return an instance of a class rather than modify the arguments that were passed in.
基于此以及 Java 工作人员的其他评论,我会说目的是/是您返回一个类的实例,而不是修改传入的参数。
This is common practice (as is the desire by C programmers to modify the arguments... eventually they see the Java way of doing it usually. Just think of it as returning a struct. :-)
这是常见的做法(就像 C 程序员希望修改参数一样......最终他们看到了通常的 Java 方式。把它想象成返回一个结构。:-)
(Edit based on the following comment)
(根据以下评论进行编辑)
I am reading a file and generating two arrays, of type String and int from it, picking one element for both from each line. I want to return both of them to any function which calls it which a file to split this way.
我正在读取一个文件并从中生成两个类型为 String 和 int 的数组,从每一行中为两者选择一个元素。我想将它们都返回给调用它的任何函数,以这种方式拆分文件。
I think, if I am understanding you correctly, tht I would probably do soemthing like this:
我想,如果我对你的理解正确的话,我可能会做这样的事情:
// could go with the Pair idea from another post, but I personally don't like that way
class Line
{
// would use appropriate names
private final int intVal;
private final String stringVal;
public Line(final int iVal, final String sVal)
{
intVal = iVal;
stringVal = sVal;
}
public int getIntVal()
{
return (intVal);
}
public String getStringVal()
{
return (stringVal);
}
// equals/hashCode/etc... as appropriate
}
and then have your method like this:
然后让你的方法是这样的:
public void foo(final File file, final List<Line> lines)
{
// add to the List.
}
and then call it like this:
然后像这样调用它:
{
final List<Line> lines;
lines = new ArrayList<Line>();
foo(file, lines);
}
回答by Eddie
You cannot truly return multiple values, but you canpass objects into a method and have the method mutate those values. That is perfectly legal. Note that you cannot pass an object in and have the object itself become a different object. That is:
您不能真正返回多个值,但您可以将对象传递给一个方法并让该方法改变这些值。这是完全合法的。请注意,您不能传入一个对象并使该对象本身成为一个不同的对象。那是:
private void myFunc(Object a) {
a = new Object();
}
will result in temporarilyand locallychanging the value of a
, but this will not change the value of the caller, for example, from:
将导致临时和本地更改 的值a
,但这不会更改调用方的值,例如,从:
Object test = new Object();
myFunc(test);
After myFunc returns, you will have the oldObject and not the new one.
myFunc 返回后,您将拥有旧对象而不是新对象。
Legal (and often discouraged) is something like this:
合法的(通常不鼓励)是这样的:
private void changeDate(final Date date) {
date.setTime(1234567890L);
}
I picked Date
for a reason. This is a class that people widely agree should never have been mutable. The the method above willchange the internal value of any Date
object that you pass to it. This kind of code is legal when it is very clear that the method will mutate or configure or modify what is being passed in.
我选择Date
是有原因的。这是一个人们普遍认为不应该可变的类。上面的方法将更改Date
您传递给它的任何对象的内部值。当很明显该方法将改变或配置或修改传入的内容时,这种代码是合法的。
NOTE: Generally, it's said that a method should do one these things:
注意:通常,据说一个方法应该做这些事情:
- Return void and mutate its incoming objects (like
Collections.sort()
), or - Return some computation and don't mutate incoming objects at all (like
Collections.min()
), or - Return a "view" of the incoming object but do not modify the incoming object (like
Collections.checkedList()
orCollections.singleton()
) - Mutate one incoming object and return it (
Collections
doesn't have an example, butStringBuilder.append()
is a good example).
- 返回 void 并改变它的传入对象(如
Collections.sort()
),或 - 返回一些计算并且根本不改变传入的对象(如
Collections.min()
),或者 - 返回传入对象的“视图”但不修改传入对象(如
Collections.checkedList()
或Collections.singleton()
) - 改变一个传入的对象并返回它(
Collections
没有一个例子,但是StringBuilder.append()
是一个很好的例子)。
Methods that mutate incoming objects andreturn a separate return value are often doing too many things.
改变传入对象并返回单独的返回值的方法通常做了太多的事情。
回答by Jon
See this RFE launched back in 1999:
请参阅 1999 年推出的这个 RFE:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4222792
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4222792
I don't think the intention was to ever allow it in the Java language, if you need to return multiple values you need to encapsulate them in an object.
我不认为意图是在 Java 语言中允许它,如果您需要返回多个值,则需要将它们封装在一个对象中。
Using languages like Scala however you can return tuples, see:
使用像 Scala 这样的语言但是你可以返回元组,请参阅:
http://www.artima.com/scalazine/articles/steps.html
http://www.artima.com/scalazine/articles/steps.html
You can also use Generics in Java to return a pair of objects, but that's about it AFAIK.
您还可以在 Java 中使用泛型来返回一对对象,但这就是 AFAIK。
EDIT: Tuples
编辑:元组
Just to add some more on this. I've previously implemented a Pair in projects because of the lack within the JDK. Link to my implementation is here:
只是在这方面再补充一些。由于 JDK 中的缺失,我之前在项目中实现了 Pair。我的实现链接在这里:
http://pbin.oogly.co.uk/listings/viewlistingdetail/5003504425055b47d857490ff73ab9
http://pbin.oogly.co.uk/listings/viewlistingdetail/5003504425055b47d857490ff73ab9
Note, there isn't a hashcode or equals on this, which should probably be added.
请注意,这里没有哈希码或等号,可能应该添加。
I also came across this whilst doing some research into this questions which provides tuple functionality:
我在对提供元组功能的这个问题进行一些研究时也遇到了这个问题:
It allows you to create Pair including other types of tuples.
它允许您创建包含其他类型元组的 Pair。
回答by Nathan Voxland
There are certainly methods that modify an object passed in as a parameter (see java.io.Reader.read(byte[] buffer)as an example, but I have not seen parameters used as an alternative for a return value, especially with multiple parameters. It may technically work, but it is nonstandard.
肯定有一些方法可以修改作为参数传入的对象(参见 java.io.Reader.read(byte[] buffer)作为示例,但我还没有看到参数用作返回值的替代方法,尤其是多个参数。它在技术上可能有效,但它是非标准的。
回答by Neil Coffey
It's not generally considered terribly good practice, but there are very occasional cases in the JDK where this is done. Look at the 'biasRet' parameter of View.getNextVisualPositionFrom() and related methods, for example: it's actually a one-dimensional array that gets filled with an "extra return value".
这通常不被认为是非常好的做法,但在 JDK 中偶尔会有这样做的情况。看看 View.getNextVisualPositionFrom() 的 'biasRet' 参数和相关方法,例如:它实际上是一个一维数组,填充了一个“额外的返回值”。
So why do this? Well, just to save you having to create an extra class definition for the "occasional extra return value". It's messy, inelegant, bad design, non-object-oriented, blah blah. And we've all done it from time to time...
那么为什么要这样做呢?好吧,只是为了让您不必为“偶尔的额外返回值”创建额外的类定义。这是凌乱的,不雅的,糟糕的设计,非面向对象的,等等。而且我们都时不时地这样做...
回答by Miserable Variable
I do wish there was a Pair<E,F>
class in JDK, mostly for this reason. There is Map<K,V>.Entry
, but creating an instance was always a big pain.
我确实希望Pair<E,F>
JDK 中有一个类,主要是出于这个原因。有Map<K,V>.Entry
,但创建一个实例总是一个很大的痛苦。
Now I use com.google.common.collect.Maps.immutableEntry
when I need a Pair
现在我com.google.common.collect.Maps.immutableEntry
在需要时使用Pair
回答by javashlook
In my opinion, if we're talking about a public method, you should create a separate class representing a return value. When you have a separate class:
在我看来,如果我们谈论的是公共方法,您应该创建一个单独的类来表示返回值。当你有一个单独的类时:
- it serves as an abstraction (i.e. a
Point
class instead of array of two longs) - each field has a name
- can be made immutable
- makes evolution of API much easier (i.e. what about returning 3 instead of 2 values, changing type of some field etc.)
- 它作为一个抽象(即一个
Point
类而不是两个长整型数组) - 每个字段都有一个名称
- 可以不可变
- 使 API 的演变更容易(即返回 3 而不是 2 个值,更改某些字段的类型等怎么样)
I would always opt for returning a new instance, instead of actually modifying a value passed in. It seems much clearer to me and favors immutability.
我总是选择返回一个新实例,而不是实际修改传入的值。这对我来说似乎更清晰,并且有利于不变性。
On the other hand, if it is an internal method, I guess any of the following might be used:
另一方面,如果它是内部方法,我想可能会使用以下任何一种方法:
- an array (
new Object[] { "str", longValue }
) - a list (
Arrays.asList(...)
returns immutable list) - pair/tuple class, such as this
- static inner class, with public fields
- 一个数组 (
new Object[] { "str", longValue }
) - 一个列表(
Arrays.asList(...)
返回不可变列表) - 对/元组类,例如这个
- 静态内部类,具有公共字段
Still, I would prefer the last option, equipped with a suitable constructor. That is especially true if you find yourself returning the same tuple from more than one place.
不过,我更喜欢最后一个选项,配备一个合适的构造函数。如果您发现自己从多个地方返回同一个元组,则尤其如此。
回答by Kevin Peterson
Generally what Eddie said, but I'd add one more:
大体上是 Eddie 说的,但我还要补充一句:
- Mutate one of the incoming objects, and return a status code. This should generally only be used for arguments that are explicitly buffers, like Reader.read(char[] cbuf).
- 改变传入对象之一,并返回状态代码。这通常只用于显式缓冲区的参数,如 Reader.read(char[] cbuf)。
回答by sudr
I had a Result object that cascades through a series of validating void methods as a method parameter. Each of these validating void methods would mutate the result parameter object to add the result of the validation.
我有一个 Result 对象,它通过一系列验证 void 方法作为方法参数进行级联。这些验证 void 方法中的每一个都会改变结果参数对象以添加验证结果。
But this is impossible to test because now I cannot stub the void method to return a stub value for the validation in the Result object.
但这是不可能测试的,因为现在我无法存根 void 方法来返回 Result 对象中验证的存根值。
So, from a testing perspective it appears that one should favor returning a object instead of mutating a method parameter.
因此,从测试的角度来看,似乎应该倾向于返回一个对象而不是改变方法参数。