varargs - aplicação prática  XML
Índice dos Fóruns » Java Básico
Autor Mensagem
roadhouse
JavaBaby

Membro desde: 26/01/2007 15:24:31
Mensagens: 99
Offline

Pessoal,

Alguém poderia me dar um exemplo de aplicação prática de varargs?

Digo isso porque não vejo muita diferença disso:



pra isso:



é uma questão de semântica da linguagem (ficar mais legível) ou há uma vantagem que eu não estou enxergando?


Não alimente os trolls.
[MSN] [ICQ]
thingol
Moderador

Membro desde: 29/07/2004 16:10:13
Mensagens: 17543
Offline

Isso na verdade foi muito discutido antes da sua adoção na linguagem.
Como você sabe, varargs na verdade é uma abreviação de uma passagem de um parâmetro array. Por exemplo:

é uma abreviação de


Havia gente que propunha não haver varargs (porque eles acarretam algumas ambiguidades sintáticas que são difíceis de entender). Em seu lugar essas pessoas propunham que o inicializador de arrays (new Object[]{}) pudesse ser abreviado para {}. Por exemplo:

Só que foram voto vencido - afinal de contas, varargs permitem que você construa algo parecido com o printf, e como você deve saber é difícil para alguém que programou em C alguma vez na vida deixar de usar o printf.
[WWW]
roadhouse
JavaBaby

Membro desde: 26/01/2007 15:24:31
Mensagens: 99
Offline

entendi...

nesse caso seria algo mais "cosmético" por assim dizer né?

Não alimente os trolls.
[MSN] [ICQ]
thingol
Moderador

Membro desde: 29/07/2004 16:10:13
Mensagens: 17543
Offline

Isso é o que o pessoal chama de "syntatic sugar" (açúcar sintático).

Eu confesso que uso bastante, já que muitas vezes eu preciso passar um array de objetos ou strings, e tenho preguiça de usar "new String[]{}" ou "new Object[]{}".

Só que varargs está mais para "syntatic sweetener" (adoçante sintático) porque ele pode ter um sabor amargo às vezes. Por exemplo, quando você faz isto:

System.out.printf ("%s", null);

o que você está fazendo?

a) Estou passando um array, cujo valor é new Object[]{null}
b) Estou passando o valor null .

Vou checar aqui na JLS o que foi definido nesse caso.
[WWW]
roadhouse
JavaBaby

Membro desde: 26/01/2007 15:24:31
Mensagens: 99
Offline

eu acho que nesse caso é: Object[]{null} não?

já que essa sintaxe é um atalho pra um array...

Não alimente os trolls.
[MSN] [ICQ]
Mantu
GUJ Ranger
[Avatar]

Membro desde: 27/03/2006 09:05:16
Mensagens: 961
Localização: São Paulo/SP
Offline

No Eclipse, eu fiz o seguinte teste:

Na linha 7, o Eclipse dá o seguinte warning:
Eclipse Calisto wrote:The argument of type null should explicitly be cast to String[] for the invocation of the varargs method m(String...) from type VarargsTest. It could alternatively be cast to String for a varargs invocation

Quando você passa somente null, ele encara que vc está passando null mesmo. Se vc quer mandar um elemento String null, você deve dar um cast no null para String.
Mas assim, essas verificações são empíricas... Vai saber se isso é coisa da JLS ou se é só do Eclipse mesmo...

[]'s
Mantu

"Vou lançar o 'Caguei'. Caguei para o 'Cansei'". Luciano Camargo
"O povo votou contra a opinião pública". Um certo jornalão da mídia golpista, a respeito da vitória de um certo cadidato a presidente do Brasil.

[Email] [MSN] [ICQ]
thingol
Moderador

Membro desde: 29/07/2004 16:10:13
Mensagens: 17543
Offline

Bom, ele dá um warning e passa "null", não "new Object[]{null}". Que legal

[WWW]
roadhouse
JavaBaby

Membro desde: 26/01/2007 15:24:31
Mensagens: 99
Offline

seguir a lógica mesmo... nada né? =:/

bom com certeza isso é uma questão da prova de certificação né? então niguém erra mais ela hehehehe

Não alimente os trolls.
[MSN] [ICQ]
thingol
Moderador

Membro desde: 29/07/2004 16:10:13
Mensagens: 17543
Offline

Mantu, você que sabe ler língua de advogado, perdão, definições formais de linguagens, deve estar entendendo aqui que:

(Só para lhe ajudar, "Variable arity" = varargs)

Digamos que apareça apenas um argumento. Se ele for "assignment compatible" com o tipo T[] - no seu exemplo, T = String, pois você declarou "String... strings", então ele é passado diretamente, em vez de ser encapsulado em um new T[]{} . Portanto, você poderia usar:
m (new String[] {"a", "b", "c"}) ou m ("a", "b", "c". Ambas as formas são equivalentes.

O problema é que a constante "null" é "assignment compatible" com qualquer tipo, se você olhar na JLS em algum outro lugar. Portanto você teria de passar null e não new String[]{null}.

Na JLS não se diz que é recomendado emitir um warning no caso do valor "null". Mas como esse caso é realmente difícil de entender, tanto o Eclipse quanto o javac emitem esse warning.


JLS wrote:
15.12.4.2 Evaluate Arguments
The process of evaluating of the argument list differs, depending on whether the method being invoked is a fixed arity method or a variable arity method (§8.4.1).
If the method being invoked is a variable arity method (§8.4.1) m, it necessarily has n>0 formal parameters. The final formal parameter of m necessarily has type T[] for some T, and m is necessarily being invoked with k0 actual argument expressions.

If m is being invoked with kn actual argument expressions, or, if m is being invoked with k=n actual argument expressions and the type of the kth argument expression is not assignment compatible with T[], then the argument list (e1, ... , en-1, en, ...ek) is evaluated as if it were written as (e1, ..., en-1, new T[]{en, ..., ek}).

The argument expressions (possibly rewritten as described above) are now evaluated to yield argument values. Each argument value corresponds to exactly one of the method's n formal parameters.

The argument expressions, if any, are evaluated in order, from left to right. If the evaluation of any argument expression completes abruptly, then no part of any argument expression to its right appears to have been evaluated, and the method invocation completes abruptly for the same reason.The result of evaluating the jth argument expression is the jth argument value, for 1jn. Evaluation then continues, using the argument values, as described below.

[WWW]
Mantu
GUJ Ranger
[Avatar]

Membro desde: 27/03/2006 09:05:16
Mensagens: 961
Localização: São Paulo/SP
Offline

thingol wrote:Mantu, você que sabe ler língua de advogado, perdão, definições formais de linguagens, deve estar entendendo aqui que:

(Só para lhe ajudar, "Variable arity" = varargs)


Língua de advogado? Por quê?
Língua de perdão: Eita memória boa da muléstia!!!
Definições formais de linguagens? Quem me dera...
Aridade (Arity): A grosso modo, é a quantidade de parâmetros de um método (linguagens imperativas), de uma função(linguagens funcionais, tipo Lisp), ou de uma regra(linguagens ??????, tipo Prolog). Aprendi isso graças a uma excelente professora na facul

Estou dando uma lida na parte da JSL que trata sobre como o Java deve avaliar invocações de métodos... Até agora, acho que tem algo a ver com o fato dele especificar que o método mais específico é o que deve ser escolhido para a execução... mas ainda estou lendo...
[Email] [MSN] [ICQ]
thingol
Moderador

Membro desde: 29/07/2004 16:10:13
Mensagens: 17543
Offline

Eu digo que é "linguagem de advogado" porque definições de linguagens se assemelham àquelas letras miúdas que aparecem em contratos. Só eles conseguem entender essas coisas, e olhe lá.
E isso que a JLS contém alguns exemplos, para ajudar a clarificar o que está escrito formalmente mas não está escrito muito claramente.
[WWW]
Mantu
GUJ Ranger
[Avatar]

Membro desde: 27/03/2006 09:05:16
Mensagens: 961
Localização: São Paulo/SP
Offline

Bom, é meio complicado juntar as pecinhas das especificações da JLS (Java Language Specification), então posso ter comido bola em algum ponto...
O que eu consegui "montar" foi mais ou menos isso:
.
JLS 5.2 wrote:A value of the null type (the null reference is the only such value) may be assigned to any reference type, resulting in a null reference of that type.

Isso nos diz, basicamente, que o null pode ser atribuido a qualquer tipo de referência.
.
JLS 8.4.1 wrote:If the last formal parameter is a variable arity parameter of type T, it is considered to define a formal parameter of type T[]. The method is then a variable arity method. Otherwise, it is a fixed arity method. Invocations of a variable arity method may contain more actual argument expressions than formal parameters. All the actual argument expressions that do not correspond to the formal parameters preceding the variable arity parameter will be evaluated and the results stored into an array that will be passed to the method invocation (§15.12.4.2).

Parâmetro formal é o parâmetro da declaração do método. Argumento é a expressão passada por parâmetro quando se invoca um método. Esta expressão, quando resolvida, deve retornar um valor de tipo compatível com o parâmetro formal correspondente.
O que a 8.4.1 nos diz é que:
Se o último parâmetro formal de um método é um parâmetro de aridade variável de um determinado tipo T, este parâmetro formal será tratado como se fosse um vetor de T.
Verificada a flexinha acima, dizemos que o método é um método de aridade variável.
Todos os argumentos que não correspondem aos parâmetros formais que antecedem o parâmetro de aridade variável, serão resolvidos e seus respectivos retornos serão armazenados em um vetor o qual será passado para a invocação do método. Esta parte que parece meio confusa, contraditória até, como veremos mais adiante...
.
A JLS 15 trata de como resolver expressões
A JLS 15.12 trata de como resolver expressões que são invocação de método
A JLS 15.12.2 trata de como determinar qual a assinatura de método "casa" com uma determinada invocação de método. Esse tópico apresenta alguns subtópicos que representam as fases que se deve percorrer para encontrar a assintura que se aplica à tal invocação. A impressão trivial que se tem é que estas fases têm uma ordem a ser obedecida pela jvm.
A JLS 15.12.2.3 é uma das fases mencionadas acima (a terceira), e ela trata, basicamente, de verificar se o método invocado "casa" em termos de aridade com algum dos métodos da classe (Classe do objeto que está invocando o método). Neste tópico, resumidamente, ele diz o seguinte:
Suponha que m é um método potencialmente aplicável(ver JLS 15.12.2.1) ao método invocado.
Suponha também que e_1, ..., e_n são os argumentos da método invocado.
Suponha que A_i, onde 1<=i<=n, seja o tipo de e_i
Suponha que S_1, ..., S_n, sejam os tipos dos n parâmetros formais de m
Dadas as suposições acima, o método m será considerado, por assim dizer, aplicável ao método invocado se, e somente se:
Para 1<=i<=n, o tipo do argumento e_i - que é A_i - pode ser convertido para S_i
Uma condição doida que se aplica caso m seja um método genérico. Para o caso deste tópico aqui do GUJ, não é - aparentemente - relevante...
Se as condições acima não forem satisfeitas, a busca pelo método aplicável vai para a fase seguinte, que é especificada pela JLS 15.12.2.4.
A JLS 15.12.2.4 é a que verifica se o método invocado "casa" com algum método de aridade variável. Como creio que a explicação pra aquela problemática do null citada nos posts anteriores reside na JLS 15.12.2.3, não vou explanar esta JSL 15.12.2.4. Basta sabermos que esta é "checada" depois daquela.
.
Bom, Tendo em mente que:
null pode ser atribuído a qualquer referência (JLS 5.2), e Um parâmetro de aridade variável do tipo T de um método de aridade variável é tratado como um vetor do tipo T (JLS 8.4.1)
Se temos um método de aridade variável, por exemplo, declarado como segue:

E uma invocação deste método da seguinte forma:

Uma JVM que implementa corretamente (!) o que reza a JLS 15.12.2.3, não precisará executar as instruções especificadas pela JLS 15.12.2.4.
Esta afirmação se justifica nos termos da JLS 15.12.2.3, a qual diz, em termos resumidos, que a invocação "casa" com um determinado método m se este tem uma correspondência de aridade com a aridade da invocação.
Isto de fato acontece no caso acima descrito! Comparemos os argumentos da invocação com os parâmetros formais do método foo

Esse é o motivo pelo qual as JVMs mais conhecidas não tratam a invocação acima como algo do tipo

Pois a resolução desta instrução se encaixa na JLS 15.12.2.3 antes mesmo de passar por uma JLS que especifique a verificação de se o método é de aridade variável.
Se não há protestos... No further questions, your honor..

[]'s
Mantu

"Vou lançar o 'Caguei'. Caguei para o 'Cansei'". Luciano Camargo
"O povo votou contra a opinião pública". Um certo jornalão da mídia golpista, a respeito da vitória de um certo cadidato a presidente do Brasil.

[Email] [MSN] [ICQ]
thingol
Moderador

Membro desde: 29/07/2004 16:10:13
Mensagens: 17543
Offline

Pois é, seu Mantu, é por isso que mesmo os caras que efetuam a manutenção do compilador (o Peter van der Ahé no caso do Javac, não sei quem no caso do Eclipse Compiler) se embananam um pouco para entender a JLS.
Pelo menos ambos os compiladores emitem um warning no caso de varargs, quando a especificação diz uma coisa que não é intuitiva, como é o caso de passar apenas um parâmetro "null".
[WWW]
plentz
Moderador
[Avatar]

Membro desde: 28/01/2004 07:34:12
Mensagens: 1584
Localização: Porto Alegre, RS
Offline

varargs pode ser bastante útil pra tornar mais legível algumas implementações. Por exemplo, normalmente quando uso DAO genérico + Hibernate, eu crio um método como o abaixo:


Facilitando a escrita de outros métodos que usem Criteria.

Diego Plentz - Twitter
"Provide options, don't make lame excuses."
[Email] [WWW]
roadhouse
JavaBaby

Membro desde: 26/01/2007 15:24:31
Mensagens: 99
Offline

Valeu Plentz!

era exatamente esse tipo de exemplo que eu queria.

Claro que isso não desmerece em nenhum momento thingol e Mantu que participaram da thread, escovar bits nunca é demais

Não alimente os trolls.
[MSN] [ICQ]
 
Índice dos Fóruns » Java Básico
Ir para:   
Powered by JForum 2.1.8 © JForum Team