如何从 Java 方法返回多个对象?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/457629/
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
How to return multiple objects from a Java method?
提问by Jagmal
I want to return two objects from a Java method and was wondering what could be a good way of doing so?
我想从 Java 方法返回两个对象,并且想知道这样做的好方法是什么?
The possible ways I can think of are: return a HashMap
(since the two Objects are related) or return an ArrayList
of Object
objects.
我能想到的可能的方法是:回报HashMap
(因为这两个对象是相关的),或者返回ArrayList
的Object
对象。
To be more precise, the two objects I want to return are (a) List
of objects and (b) comma separated names of the same.
更准确地说,我想返回的两个对象是(a)List
对象和(b)逗号分隔的相同名称。
I want to return these two Objects from one method because I dont want to iterate through the list of objects to get the comma separated names (which I can do in the same loop in this method).
我想从一个方法返回这两个对象,因为我不想遍历对象列表来获取逗号分隔的名称(我可以在此方法的同一循环中执行此操作)。
Somehow, returning a HashMap
does not look a very elegant way of doing so.
不知何故,返回 aHashMap
看起来不是一种非常优雅的方式。
回答by Joachim Sauer
If you want to return two objects you usually want to return a single object that encapsulates the two objects instead.
如果您想返回两个对象,您通常希望返回一个封装了这两个对象的对象。
You could return a List of NamedObject
objects like this:
您可以NamedObject
像这样返回一个对象列表:
public class NamedObject<T> {
public final String name;
public final T object;
public NamedObject(String name, T object) {
this.name = name;
this.object = object;
}
}
Then you can easily return a List<NamedObject<WhateverTypeYouWant>>
.
然后你可以轻松地返回一个List<NamedObject<WhateverTypeYouWant>>
.
Also: Why would you want to return a comma-separated list of names instead of a List<String>
? Or better yet, return a Map<String,TheObjectType>
with the keys being the names and the values the objects (unless your objects have specified order, in which case a NavigableMap
might be what you want.
另外:为什么要返回以逗号分隔的名称列表而不是List<String>
? 或者更好的是,返回 a Map<String,TheObjectType>
,键是对象的名称和值(除非您的对象已指定顺序,在这种情况下 aNavigableMap
可能是您想要的。
回答by Bombe
All possible solutions will be a kludge (like container objects, your HashMap idea, “multiple return values” as realized via arrays). I recommend regenerating the comma-separated list from the returned List. The code will end up being a lot cleaner.
所有可能的解决方案都是杂乱无章的(比如容器对象、你的 HashMap 想法、通过数组实现的“多个返回值”)。我建议从返回的列表中重新生成逗号分隔的列表。代码最终会干净很多。
回答by kipz
Before Java 5, I would kind of agree that the Map solution isn't ideal. It wouldn't give you compile time type checking so can cause issues at runtime. However, with Java 5, we have Generic Types.
在 Java 5 之前,我同意 Map 解决方案并不理想。它不会为您提供编译时类型检查,因此可能会在运行时导致问题。但是,在 Java 5 中,我们有泛型类型。
So your method could look like this:
所以你的方法可能是这样的:
public Map<String, MyType> doStuff();
MyType of course being the type of object you are returning.
MyType 当然是您要返回的对象类型。
Basically I think that returning a Map is the right solution in this case because that's exactly what you want to return - a mapping of a string to an object.
基本上我认为在这种情况下返回 Map 是正确的解决方案,因为这正是您想要返回的 - 字符串到对象的映射。
回答by tvanfosson
As I see it there are really three choices here and the solution depends on the context. You can choose to implement the construction of the name in the method that produces the list. This is the choice you've chosen, but I don't think it is the best one. You are creating a coupling in the producer method to the consuming method that doesn't need to exist. Other callers may not need the extra information and you would be calculating extra information for these callers.
在我看来,这里确实有三个选择,解决方案取决于上下文。您可以选择在生成列表的方法中实现名称的构造。这是您选择的选择,但我认为这不是最好的选择。您正在将生产者方法中的耦合创建到不需要存在的消费方法。其他来电者可能不需要额外的信息,您将为这些来电者计算额外的信息。
Alternatively, you could have the calling method calculate the name. If there is only one caller that needs this information, you can stop there. You have no extra dependencies and while there is a little extra calculation involved, you've avoided making your construction method too specific. This is a good trade-off.
或者,您可以让调用方法计算名称。如果只有一个呼叫者需要此信息,您可以停在那里。您没有额外的依赖项,虽然涉及一些额外的计算,但您已避免使您的构造方法过于具体。这是一个很好的权衡。
Lastly, you could have the list itself be responsible for creating the name. This is the route I would go if the calculation needs to be done by more than one caller. I think this puts the responsibility for the creation of the names with the class that is most closely related to the objects themselves.
最后,您可以让列表本身负责创建名称。如果计算需要由多个调用者完成,这就是我要走的路线。我认为这将使用与对象本身最密切相关的类来创建名称的责任。
In the latter case, my solution would be to create a specialized List class that returns a comma-separated string of the names of objects that it contains. Make the class smart enough that it constructs the name string on the fly as objects are added and removed from it. Then return an instance of this list and call the name generation method as needed. Although it may be almost as efficient (and simpler) to simply delay calculation of the names until the first time the method is called and store it then (lazy loading). If you add/remove an object, you need only remove the calculated value and have it get recalculated on the next call.
在后一种情况下,我的解决方案是创建一个专门的 List 类,该类返回它包含的对象名称的逗号分隔字符串。使类足够智能,以便在添加和删除对象时动态构造名称字符串。然后返回这个列表的一个实例,并根据需要调用名称生成方法。尽管简单地将名称的计算延迟到第一次调用该方法然后存储它(延迟加载)可能几乎同样有效(并且更简单)。如果您添加/删除一个对象,您只需要删除计算值并在下次调用时重新计算它。
回答by kgiannakakis
In C++ (STL) there is a pair class for bundling two objects. In Java Generics a pair class isn't available, although there is some demandfor it. You could easily implement it yourself though.
在 C++ (STL) 中有一个用于捆绑两个对象的配对类。在 Java 泛型中,虽然有一些需求,但配对类不可用。不过,您可以轻松地自己实现它。
I agree however with some other answers that if you need to return two or more objects from a method, it would be better to encapsulate them in a class.
然而,我同意其他一些答案,即如果您需要从一个方法返回两个或更多对象,最好将它们封装在一个类中。
回答by David Hanak
If you know you are going to return two objects, you can also use a generic pair:
如果您知道要返回两个对象,也可以使用泛型对:
public class Pair<A,B> {
public final A a;
public final B b;
public Pair(A a, B b) {
this.a = a;
this.b = b;
}
};
EditA more fully formed implementation of the above:
编辑上述更完整的实现:
package util;
public class Pair<A,B> {
public static <P, Q> Pair<P, Q> makePair(P p, Q q) {
return new Pair<P, Q>(p, q);
}
public final A a;
public final B b;
public Pair(A a, B b) {
this.a = a;
this.b = b;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((a == null) ? 0 : a.hashCode());
result = prime * result + ((b == null) ? 0 : b.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
@SuppressWarnings("rawtypes")
Pair other = (Pair) obj;
if (a == null) {
if (other.a != null) {
return false;
}
} else if (!a.equals(other.a)) {
return false;
}
if (b == null) {
if (other.b != null) {
return false;
}
} else if (!b.equals(other.b)) {
return false;
}
return true;
}
public boolean isInstance(Class<?> classA, Class<?> classB) {
return classA.isInstance(a) && classB.isInstance(b);
}
@SuppressWarnings("unchecked")
public static <P, Q> Pair<P, Q> cast(Pair<?, ?> pair, Class<P> pClass, Class<Q> qClass) {
if (pair.isInstance(pClass, qClass)) {
return (Pair<P, Q>) pair;
}
throw new ClassCastException();
}
}
Notes, mainly around rustiness with Java & generics:
注释,主要是关于 Java 和泛型的生锈:
- both
a
andb
are immutable. makePair
static method helps you with boiler plate typing, which the diamond operator in Java 7 will make less annoying. There's some work to make this really nice re: generics, but it should be ok-ish now. (c.f. PECS)hashcode
andequals
are generated by eclipse.- the compile time casting in the
cast
method is ok, but doesn't seem quite right. - I'm not sure if the wildcards in
isInstance
are necessary. - I've just written this in response to comments, for illustration purposes only.
- 这两个
a
和b
是不可变的。 makePair
静态方法可以帮助您进行样板输入,Java 7 中的菱形运算符将减少烦人。有一些工作可以使它变得非常好:泛型,但现在应该没问题了。(参见 PECS)hashcode
并且equals
是由eclipse生成的。- 方法中的编译时转换
cast
没问题,但似乎不太正确。 - 我不确定是否需要通配符
isInstance
。 - 我只是为了回应评论而写这篇文章,仅供说明之用。
回答by Ulrik Rasmussen
I almost always end up defining n-Tuple classes when I code in Java. For instance:
当我用 Java 编码时,我几乎总是最终定义 n-Tuple 类。例如:
public class Tuple2<T1,T2> {
private T1 f1;
private T2 f2;
public Tuple2(T1 f1, T2 f2) {
this.f1 = f1; this.f2 = f2;
}
public T1 getF1() {return f1;}
public T2 getF2() {return f2;}
}
I know it's a bit ugly, but it works, and you just have to define your tuple types once. Tuples are something Java really lacks.
我知道这有点难看,但它确实有效,而且您只需定义一次元组类型。元组是 Java 真正缺乏的东西。
EDIT: David Hanak's example is more elegant, as it avoids defining getters and still keeps the object immutable.
编辑:David Hanak 的例子更优雅,因为它避免了定义 getter 并且仍然保持对象不可变。
回答by Ulrik Rasmussen
Alternatively, in situations where I want to return a number of things from a method I will sometimes use a callback mechanism instead of a container. This works very well in situations where I cannot specify ahead of time just how many objects will be generated.
或者,在我想从方法中返回许多东西的情况下,我有时会使用回调机制而不是容器。这在我无法提前指定将生成多少对象的情况下非常有效。
With your particular problem, it would look something like this:
对于您的特定问题,它看起来像这样:
public class ResultsConsumer implements ResultsGenerator.ResultsCallback
{
public void handleResult( String name, Object value )
{
...
}
}
public class ResultsGenerator
{
public interface ResultsCallback
{
void handleResult( String aName, Object aValue );
}
public void generateResults( ResultsGenerator.ResultsCallback aCallback )
{
Object value = null;
String name = null;
...
aCallback.handleResult( name, value );
}
}
回答by Brian Agnew
Why not create a WhateverFunctionResult
object that contains your results, andthe logic required to parse these results, iterate over then etc. It seems to me that either:
为什么不创建一个WhateverFunctionResult
包含结果的对象,以及解析这些结果所需的逻辑,然后迭代等等。在我看来,要么:
- These results objects are intimately tied together/related and belong together, or:
- they are unrelated, in which case your function isn't well defined in terms of what it's trying to do (i.e. doing two different things)
- 这些结果对象紧密联系在一起/相关并且属于一起,或者:
- 它们是不相关的,在这种情况下,您的功能在尝试做什么(即做两件不同的事情)方面没有很好地定义
I see this sort of issue crop up again and again. Don't be afraid to create your own container/result classes that contain the data and the associated functionality to handle this. If you simply pass the stuff around in a HashMap
or similar, then your clients have to pull this map apart and grok the contents each time they want to use the results.
我看到这种问题一次又一次地出现。不要害怕创建自己的容器/结果类,其中包含数据和相关的处理功能。如果您只是在 aHashMap
或类似内容中传递这些内容,那么您的客户每次想要使用结果时都必须将这张地图拆开并仔细阅读内容。
回答by l_39217_l
PASS A HASH INTO THE METHOD AND POPULATE IT......
将哈希传递给方法并填充它......
public void buildResponse(String data, Map response);
public void buildResponse(String data, Map response);