Java два varargs одним способом
Есть ли какой-либо способ в java, чтобы создать метод, который ожидает два разных varargs?
Я знаю, что с тем же видом объекта это невозможно, потому что компилятор не знает, с чего начать или до конца. Но почему это также невозможно с разными типами объектов?
Например:
public void doSomething(String... s, int... i){
//...
//...
}
Есть ли способ создать такой метод?
Спасибо!
Ответы
Ответ 1
Только один вараг, извините. Но использование 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));
Ответ 2
В Java допускается только один аргумент varargs
, и он должен быть последним параметром подписи.
Но все равно он преобразует его в массив, так что вам нужно просто сделать ваши два параметра явными массивами:
public void doSomething(String[] s, int[] i){
Ответ 3
Возможная конструкция API, в которой код вызова выглядит как
doSomething("a", "b").with(1,2);
через "свободный" 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)
{
...
}
Опасность заключается в том, что программист забыл называть with(...)
doSomething("a", "b"); // nothing is done
Может быть, это немного лучше
with("a", "b").and(1, 2).doSomething();
Ответ 4
Разрешен только один vararg
. Это связано с тем, что несколько аргументов vararg
неоднозначны. Например, что, если вы передали два varargs одного класса?
public void doSomething(String...args1, String...args2);
Где заканчивается args1 end и args2? Или как насчет чего-то более запутанного здесь.
class SuperClass{}
class ChildClass extends SuperClass{}
public void doSomething(SuperClass...args1, ChildClass...args2);
ChildClass расширяет SuperClass, и, следовательно, может существовать законно в args1 или args2. Эта путаница заключается в том, что разрешено использовать только один varargs
.
varargs
также должен появиться в конце объявления метода.
Просто объявите конкретный тип вместо 2 массивов.
Ответ 5
Хотя такая вещь иногда бывает полезна, обычно, если вы обнаружите, что используете ограничение на Java, вы, вероятно, можете что-то перепроектировать и выйти намного лучше. Вот несколько возможных способов взглянуть на это...
Если два списка связаны вообще, вы, вероятно, хотите создать класс-оболочку для двух разных списков и передать в оболочку. Обертки вокруг коллекций - почти всегда хорошая идея - они дают вам место для добавления кода, относящегося к коллекции.
Если это способ инициализации данных, проанализируйте его из строки. Например, "abc, 123: def, 456: jhi, 789" почти смутно легко разделить с помощью двух разделенных операторов и цикла (2-3 строки кода). Вы даже можете создать небольшой пользовательский класс парсера, который анализирует такую строку в структуре, которую вы подаете в свой метод.
Хмм - честно соглашайтесь с инициализацией данных, я даже не знаю, почему вы хотели бы сделать это в любом случае, в любом другом случае, и я ожидаю, что вы пройдете в 2 сборниках и не будете интересоваться varags at все.
Ответ 6
Вы можете сделать что-то подобное, тогда вы можете использовать и добавлять дополнительную логику внутри этого метода.
public void doSomething(Object... stringOrIntValues) {
...
...
}
И используйте этот метод следующим образом:
doSomething(stringValue1, stringValue2, intValue1, intValue2,
intValue3);
Ответ 7
Это старый поток, но я думал, что это будет полезно независимо.
Решение, которое я нашел, не очень аккуратно, но оно работает. Я создал отдельный класс для тяжелого подъема. У него есть только две переменные, которые мне нужны, и их геттеры. Конструктор самостоятельно обрабатывает установленные методы.
Мне нужно было передать объекты направления и соответствующий объект Data. Это также решает возможную проблему неравных пар данных, но это, вероятно, только для моих нужд использования.
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;
}
}
Я бы просто передал этот класс как vararg для метода
public void method(DataDirectionPair... ndPair){
for(DataDirectionPair temp : ndPair){
this.node = temp.getNode();
this.direction = temp.getDir();
//or use it however you want
}
}
Ответ 8
Я просто прочитал еще один вопрос об этом "шаблоне", но он уже удален, поэтому я хотел бы предложить другой подход к этой проблеме, поскольку я не видел здесь этого решения.
Вместо того, чтобы заставить разработчика обернуть параметр ввода в List или Array, будет полезно использовать подход "карри" или лучше шаблон построения.
Рассмотрим следующий код:
/**
* 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();
}
}
Как вы можете видеть вас таким образом, вы можете добавить новые элементы, которые вам нужны, когда вам нужно.
Вся реализация завершена.
Ответ 9
Если вы не собираетесь передавать большое количество строк в большинстве случаев для первого аргумента, вы можете предоставить кучу перегрузок, которые принимают разные номера строк и переносят их в массив, прежде чем вызывать метод, который принимает массив как первый аргумент.
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) {
// ...
// ...
}
Ответ 10
follwing на Лемуэля Адане (не могу прокомментировать сообщение, из-за отсутствия репутации:))
если вы используете
public void f(Object... args){}
то вы можете использовать цикл Как определить класс объекта (на Java)?
например,
{
int i = 0;
while(i< args.length && args[i] instanceof String){
System.out.println((String) args[i]);
i++ ;
}
int sum = 0;
while(i< args.length){
sum += (int) args[i];
i++ ;
}
System.out.println(sum);
}
или все, что вы намереваетесь сделать.
Ответ 11
Вы можете преобразовать ваши varargs в массивы
public void doSomething(String[] s, int[] i) {
...
}
затем с помощью некоторых вспомогательных методов для преобразования ваших varargs в массив следующим образом:
public static int[] intsAsArray(int... ints) {
return ints;
}
public static <T> T[] asArray(T... ts) {
return ts;
}
Затем вы можете использовать эти вспомогательные методы для преобразования ваших переменных.
doSomething(asArray("a", "b", "c", "d"), intsAsArray(1, 2, 3));