Eu tenho medo de varargs. Não sei para que usá-los.
Além disso, parece perigoso deixar as pessoas passarem quantos argumentos quiserem.
Qual é o exemplo de um contexto que seria um bom lugar para usá-los?
Eu tenho medo de varargs. Não sei para que usá-los.
Além disso, parece perigoso deixar as pessoas passarem quantos argumentos quiserem.
Qual é o exemplo de um contexto que seria um bom lugar para usá-los?
Respostas:
Varargs são úteis para qualquer método que precise lidar com um número indeterminado de objetos . Um bom exemplo é String.format
. A string de formato pode aceitar qualquer número de parâmetros, portanto, você precisa de um mecanismo para transmitir qualquer número de objetos.
String.format("This is an integer: %d", myInt);
String.format("This is an integer: %d and a string: %s", myInt, myString);
Uma boa regra geral seria:
"Use varargs para qualquer método (ou construtor) que precise de uma matriz de T (qualquer que seja o tipo T) como entrada".
Isso facilitará as chamadas para esses métodos (não é necessário fazer new T[]{...}
).
Você pode estender esta regra para incluir métodos com um List<T>
argumento, desde que esse argumento seja apenas para entrada (ou seja, a lista não é modificada pelo método).
Além disso, eu evitaria usá-lo f(Object... args)
porque ele desliza para um caminho de programação com APIs pouco claras.
Em termos de exemplos, eu o usei no DesignGridLayout , onde posso adicionar vários JComponent
s em uma chamada:
layout.row().grid(new JLabel("Label")).add(field1, field2, field3);
No código acima, o método add () é definido como add(JComponent... components)
.
Finalmente, a implementação de tais métodos deve cuidar do fato de que pode ser chamado com um vararg vazio! Se você deseja impor pelo menos um argumento, use um truque feio, como:
void f(T arg1, T... args) {...}
Considero esse truque feio porque a implementação do método será menos direta do que ter apenas T... args
em sua lista de argumentos.
Espero que isso ajude a esclarecer o ponto sobre as variáveis.
if (args.length == 0) throw new RuntimeException("foo");
? (Desde o chamador estava violando o contrato)
void f(T arg1, T... args)
isso sempre garante que nunca seja chamada sem argumento, sem a necessidade de esperar até o tempo de execução.
Uso varargs frequentemente para enviar para os logs para fins de depuração.
Praticamente todas as classes no meu aplicativo têm um método debugPrint ():
private void debugPrint(Object... msg) {
for (Object item : msg) System.out.print(item);
System.out.println();
}
Então, dentro dos métodos da classe, tenho chamadas como as seguintes:
debugPrint("for assignment ", hwId, ", student ", studentId, ", question ",
serialNo, ", the grade is ", grade);
Quando estou convencido de que meu código está funcionando, comento o código no método debugPrint () para que os logs não contenham muitas informações estranhas e indesejadas, mas posso deixar as chamadas individuais para debugPrint () descomentadas. Mais tarde, se eu encontrar um bug, apenas descomente o código debugPrint () e todas as minhas chamadas para debugPrint () serão reativadas.
Claro, eu poderia facilmente evitar varargs e fazer o seguinte:
private void debugPrint(String msg) {
System.out.println(msg);
}
debugPrint("for assignment " + hwId + ", student " + studentId + ", question "
+ serialNo + ", the grade is " + grade);
No entanto, nesse caso, quando eu comento o código debugPrint (), o servidor ainda precisa enfrentar o problema de concatenar todas as variáveis em todas as chamadas para debugPrint (), mesmo que nada seja feito com a sequência resultante. Se eu usar varargs, no entanto, o servidor só precisará colocá-los em uma matriz antes de perceber que não precisa deles. Muito tempo é economizado.
Varargs pode ser usado quando não temos certeza sobre o número de argumentos a serem passados em um método. Ele cria uma matriz de parâmetros de comprimento não especificado em segundo plano e esse parâmetro pode ser tratado como uma matriz em tempo de execução.
Se temos um método que está sobrecarregado para aceitar um número diferente de parâmetros, em vez de sobrecarregar o método em tempos diferentes, podemos simplesmente usar o conceito varargs.
Além disso, quando o tipo de parâmetro variar, o uso de "Objeto ... teste" simplificará muito o código.
Por exemplo:
public int calculate(int...list) {
int sum = 0;
for (int item : list) {
sum += item;
}
return sum;
}
Aqui, indiretamente, uma matriz do tipo int (lista) é passada como parâmetro e é tratada como uma matriz no código.
Para um melhor entendimento, siga este link (me ajudou muito a entender claramente esse conceito): http://www.javadb.com/using-varargs-in-java
PS: Até eu tinha medo de usar varargs quando não sabia disso. Mas agora estou acostumado. Como é dito: "Nos apegamos ao conhecido, com medo do desconhecido", então use-o o máximo que puder e você também começará a gostar :)
Varargs é o recurso adicionado na versão 1.5 do java.
Por que usar isso?
Como isso funciona?
Ele cria uma matriz com os argumentos fornecidos e passa a matriz para o método
Exemplo:
public class Solution {
public static void main(String[] args) {
add(5,7);
add(5,7,9);
}
public static void add(int... s){
System.out.println(s.length);
int sum=0;
for(int num:s)
sum=sum+num;
System.out.println("sum is "+sum );
}
}
Resultado :
2
soma é 12
3
soma é 21
Também tenho um medo relacionado a varargs:
Se o chamador passar em uma matriz explícita para o método (em oposição a vários parâmetros), você receberá uma referência compartilhada para essa matriz.
Se você precisar armazenar essa matriz internamente, convém cloná-la primeiro para evitar que o chamador possa alterá-la mais tarde.
Object[] args = new Object[] { 1, 2, 3} ;
varArgMethod(args); // not varArgMethod(1,2,3);
args[2] = "something else"; // this could have unexpected side-effects
Embora isso não seja realmente diferente de transmitir qualquer tipo de objeto cujo estado possa ser alterado posteriormente, uma vez que a matriz é geralmente (no caso de uma chamada com vários argumentos em vez de uma matriz) uma nova criada pelo compilador internamente que você pode com segurança uso, esse certamente é um comportamento inesperado.
Uso varargs frequentemente para construtores que podem receber algum tipo de objeto de filtro. Por exemplo, grande parte do nosso sistema baseado no Hadoop é baseada em um Mapper que lida com serialização e desserialização de itens no JSON e aplica vários processadores que cada um pega um item de conteúdo e o modifica e devolve, ou retorna nulo rejeitar.
No Java doc do Var-Args, é bastante claro o uso de var args:
http://docs.oracle.com/javase/1.5.0/docs/guide/language/varargs.html
sobre o uso, diz:
"Então, quando você deve usar varargs? Como cliente, você deve tirar proveito deles sempre que a API os oferecer. Os usos importantes nas principais APIs incluem reflexão, formatação de mensagens e o novo recurso de impressão. Como designer de API, você deve usá-los moderadamente, apenas quando o benefício é realmente atraente. De um modo geral, você não deve sobrecarregar um método varargs, ou será difícil para os programadores descobrir qual sobrecarga é chamada ".