Java 在一种方法中使用两个可变参数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17868059/
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
Java two varargs in one method
提问by T_01
Is there any way in java, to create a method, which is expecting two different varargs? I know, with the same object kind it isn't possible because the compiler does'nt know where to start or to end. But why it also is'nt possible with to different Object types?
java中有什么方法可以创建一个需要两个不同可变参数的方法吗?我知道,使用相同的对象类型是不可能的,因为编译器不知道从哪里开始或结束。但是为什么对于不同的对象类型也不可能呢?
For example:
例如:
public void doSomething(String... s, int... i){
//...
//...
}
Is there any way to create method like this? Thank you!
有没有办法创建这样的方法?谢谢!
回答by rec
Only one vararg, sorry. But using asList() makes it almost as convenient:
只有一个vararg,抱歉。但是使用 asList() 几乎同样方便:
public void myMethod(List<Integer> args1, List<Integer> args2) {
...
}
-----------
import static java.util.Arrays.asList;
myMethod(asList(1,2,3), asList(4,5,6));
回答by rgettman
In Java, only one varargs
argument is allowed and it must be the last parameter of the signature.
在 Java 中,只varargs
允许一个参数,并且它必须是签名的最后一个参数。
But all it does it convert it to an array anyway, so you should just make your two parameters explicit arrays:
但它所做的一切都是将它转换为数组,所以你应该让你的两个参数显式数组:
public void doSomething(String[] s, int[] i){
回答by ZhongYu
A possible API design in which the calling code looks like
一种可能的 API 设计,其中调用代码如下所示
doSomething("a", "b").with(1,2);
through "fluent" API
通过“流畅”的 API
public Intermediary doSomething(String... strings)
{
return new Intermediary(strings);
}
class Intermediary
{
...
public void with(int... ints)
{
reallyDoSomething(strings, ints);
}
}
void reallyDoSomething(String[] strings, int[] ints)
{
...
}
The danger is if the programmer forgot to call with(...)
危险是如果程序员忘记调用 with(...)
doSomething("a", "b"); // nothing is done
Maybe this is a little better
也许这会好一点
with("a", "b").and(1, 2).doSomething();
回答by William Morrison
Only one vararg
is allowed. This is because multiple vararg
arguments are ambiguous. For example, what if you passed in two varargs of the same class?
只vararg
允许一个。这是因为多个vararg
参数是不明确的。例如,如果您传入同一个类的两个可变参数怎么办?
public void doSomething(String...args1, String...args2);
Where does args1 end and args2 begin? Or how about something more confusing here.
args1 在哪里结束,args2 在哪里开始?或者这里有什么更令人困惑的事情。
class SuperClass{}
class ChildClass extends SuperClass{}
public void doSomething(SuperClass...args1, ChildClass...args2);
ChildClass extends SuperClass, and so is can legally exist in args1, or args2. This confusion is why only one varargs
is allowed.
ChildClass 扩展了 SuperClass,因此它可以合法地存在于 args1 或 args2 中。这种混淆就是为什么只varargs
允许一个。
varargs
must also appear at the end of a method declaration.
varargs
还必须出现在方法声明的末尾。
Just declare the specific type instead as 2 arrays.
只需将特定类型声明为 2 个数组。
回答by Bill K
Although this kind of thing is occasionally useful, usually if you find that you are hitting a restriction in Java you could probably redesign something and come out much better. Here are some possible other ways to look at it...
虽然这种东西偶尔有用,但通常如果你发现你在 Java 中遇到了一个限制,你可能会重新设计一些东西并得到更好的结果。这里有一些可能的其他方式来看待它......
If the two lists are related at all you probably want to create a wrapper class for the two different lists and pass in the wrapper. Wrappers around collections are almost always a good idea--they give you a place to add code that relates to the collection.
如果这两个列表完全相关,您可能希望为两个不同的列表创建一个包装器类并传入包装器。集合周围的包装器几乎总是一个好主意——它们为您提供了一个添加与集合相关的代码的地方。
If this is a way to initialize data, parse it from a string. For instance, "abc, 123:def, 456:jhi,789" is almost embarassingly easy to split up with 2 split statements and a loop (2-3 lines of code). You can even make a little custom parser class that parses a string like that into a structure you feed into your method.
如果这是一种初始化数据的方法,请从字符串中解析它。例如,"abc, 123:def, 456:jhi,789" 用 2 个拆分语句和一个循环(2-3 行代码)拆分几乎非常容易。您甚至可以制作一个小的自定义解析器类,将这样的字符串解析为您提供给方法的结构。
Hmm--honestly asside from initializing data I don't even know why you'd want to do this anyway, any other case and I expect you'd be passing in 2 collections and wouldn't be interested in varags at all.
嗯——老实说,除了初始化数据,我什至不知道你为什么要这样做,任何其他情况,我希望你会传入 2 个集合并且根本不会对 varags 感兴趣。
回答by LEMUEL ADANE
You can do something like this, then you can cast and add additional logic inside that method.
你可以做这样的事情,然后你可以在该方法中转换和添加额外的逻辑。
public void doSomething(Object... stringOrIntValues) {
...
...
}
And use this method like so:
并像这样使用这种方法:
doSomething(stringValue1, stringValue2, intValue1, intValue2,
intValue3);
回答by user3709234
This is an old thread, but I thought this would be helpful regardless.
这是一个旧线程,但我认为无论如何这都会有所帮助。
The solution I found isn't very neat but it works. I created a separate class to handle the heavy lifting. It only has the two variables I needed and their getters. The constructor handles the set methods on its own.
我发现的解决方案不是很整洁,但它有效。我创建了一个单独的类来处理繁重的工作。它只有我需要的两个变量和它们的吸气剂。构造函数自行处理 set 方法。
I needed to pass direction objects and a respective Data object. This also solves the possible problem of uneven data pairs, but that is probably only for my usage needs.
我需要传递方向对象和相应的数据对象。这也解决了可能出现的数据对不均匀的问题,但这可能仅适用于我的使用需求。
public class DataDirectionPair{
Data dat;
Directions dir;
public DataDirectionPair(Data dat, Directions dir) {
super();
this.dat = dat;
this.dir = dir;
}
/**
* @return the node
*/
public Node getNode() {
return node;
}
/**
* @return the direction
*/
public Directions getDir() {
return dir;
}
}
I would then just pass this class as the vararg for the method
然后我将这个类作为方法的可变参数传递
public void method(DataDirectionPair... ndPair){
for(DataDirectionPair temp : ndPair){
this.node = temp.getNode();
this.direction = temp.getDir();
//or use it however you want
}
}
回答by Mark Rotteveel
It is not possible because the Java Language Specification says so (see 8.4.1. Formal Parameters):
这是不可能的,因为 Java 语言规范是这样说的(见8.4.1. 形式参数):
The last formal parameter of a method or constructor is special: it may be a variable arity parameter, indicated by an ellipsis following the type.
Note that the ellipsis (...) is a token unto itself (§3.11). It is possible to put whitespace between it and the type, but this is discouraged as a matter of style.
If the last formal parameter is a variable arity parameter, the method is a variable arity method. Otherwise, it is a fixed arity method.
方法或构造函数的最后一个形参是特殊的:它可能是一个可变的 arity parameter,由类型后面的省略号表示。
请注意,省略号 (...) 本身就是一个标记(第 3.11 节)。可以在它和类型之间放置空格,但出于风格的考虑,不鼓励这样做。
如果最后一个形参是可变元参数,则方法是可变元方法。否则,它是一个固定的 arity 方法。
As to why only one and only the last parameter, that would be a guess, but probably because allowing that could lead to undecidable or ambiguous problems (eg consider what happens with method(String... strings, Object... objects)
), and only allowing non-intersecting types would lead to complications (eg considering refactorings where previously non-intersecting types suddenly are), lack of clarity when it does or does not work, and complexity for the compiler to decide when it is applicable or not.
至于为什么只有一个且只有最后一个参数,那将是一个猜测,但可能是因为允许它可能会导致无法确定或模棱两可的问题(例如,考虑会发生什么method(String... strings, Object... objects)
),并且只允许非相交类型会导致并发症(例如考虑到以前突然不相交的类型的重构),它何时起作用或不起作用时缺乏清晰度,以及编译器决定何时适用或不适用的复杂性。
回答by Mario Santini
I just read another question about this "pattern", but it is already removed, so I would like to propose a different approach to this problem, as I didn't see here this solution.
我刚刚阅读了关于这个“模式”的另一个问题,但它已经被删除了,所以我想提出一种不同的方法来解决这个问题,因为我在这里没有看到这个解决方案。
Instead to force the developer to wrapping the inputs parameter on List or Array, it will be useful to use a "curry" approach, or better the builder pattern.
与强制开发人员将输入参数包装在 List 或 Array 上不同,使用“curry”方法或更好的构建器模式会很有用。
Consider the following code:
考虑以下代码:
/**
* Just a trivial implementation
*/
public class JavaWithCurry {
private List<Integer> numbers = new ArrayList<Integer>();
private List<String> strings = new ArrayList<String>();
public JavaWithCurry doSomething(int n) {
numbers.add(n);
return this;
}
public JavaWithCurry doSomething(String s) {
strings.add(s);
return this;
}
public void result() {
int sum = -1;
for (int n : numbers) {
sum += n;
}
StringBuilder out = new StringBuilder();
for (String s : strings) {
out.append(s).append(" ");
}
System.out.println(out.toString() + sum);
}
public static void main(String[] args) {
JavaWithCurry jwc = new JavaWithCurry();
jwc.doSomething(1)
.doSomething(2)
.doSomething(3)
.doSomething(4)
.doSomething(5)
.doSomething("a")
.doSomething("b")
.doSomething("c")
.result();
}
}
As you can see you in this way, you could add new elements of which type you need when you need.
如您所见,您可以在需要时添加所需类型的新元素。
All the implementation is wrapped.
所有的实现都被包装了。
回答by Alex
If you are not going to be passing a large number of Strings most of the time for the first argument you could provide a bunch of overloads that take different numbers of Strings and wrap them in an array before calling a method that takes the array as the first argument.
如果您大部分时间不打算为第一个参数传递大量字符串,您可以提供一堆重载,这些重载采用不同数量的字符串并将它们包装在一个数组中,然后再调用将数组作为第一个论点。
public void doSomething(int... i){
doSomething(new String[0], i);
}
public void doSomething(String s, int... i){
doSomething(new String[]{ s }, i);
}
public void doSomething(String s1, String s2, int... i){
doSomething(new String[]{ s1, s2 }, i);
}
public void doSomething(String s1, String s2, String s3, int... i){
doSomething(new String[]{ s1, s2, s3 }, i);
}
public void doSomething(String[] s, int... i) {
// ...
// ...
}