domingo, 11 de novembro de 2012

Jdk 1.8 e projeto lambda

Vamos ao Java 8.

public class TestLambda {

    public interface Acceptor {
        public boolean accept(int num);
    }

    public static void main(String[] args){
        System.out.println("123");
        printNumbers( i -> i % 3 == 0);
    }

    public static void printNumbers(Acceptor acceptor){
        for(int i = 0; i < 10; i++)
            if (acceptor.accept(i))
                System.out.println("Accept " + i );
    }
}

Observe a linha 9.

printNumbers( i -> i % 3 == 0);

É a chamada expressão lambda. A leitura é funcional, na verdade é uma instancia da interface Acceptor sendo criada na hora da compilação. Costumo fazer a leitura desse tipo de código da seguinte forma: Para um i, de tal forma que i dividido por tres seja zero.

Para que esse código funcione será necessário que os parâmetros da expressão lambda sejam aderentes ao único método da interface Acceptor, que criamos para declarar a expectativa da função printNumbers.

O mais interessante desse código está no arquivo .class compilado. Os primeiros testes do projeto Lambda criava uma classe anonima para a expressão da linha nove mas as últimas verões já estão usando a nova instrução invokeDinamic, veja.

Compiled from "TestLambda.java"
public class TestLambda {
  public TestLambda();
    Code:
       0: aload_0       
       1: invokespecial #1                  
       4: return        

  public static void main(java.lang.String[]);
    Code:
       0: getstatic     #2                  
       3: ldc           #3                  
       5: invokevirtual #4                  
       8: invokedynamic #5,  0              
      13: invokestatic  #6                  
      16: return        

  public static void printNumbers(TestLambda$Acceptor);
    Code:
       0: iconst_0      
       1: istore_1      
       2: iload_1       
       3: bipush        10
       5: if_icmpge     49
       8: aload_0       
       9: iload_1       
      10: invokeinterface #7,  2 
      15: ifeq          43
      18: getstatic     #2            
      21: new           #8                  
      24: dup           
      25: invokespecial #9                  
      28: ldc           #10                  
      30: invokevirtual #11                 
      33: iload_1       
      34: invokevirtual #12                 
      37: invokevirtual #13                 
      40: invokevirtual #4                  
      43: iinc          1, 1
      46: goto          2
      49: return        
}

O código pode parecer que não muda muito, mas agora é possível alguma coisa funcional com java. Quando essa implementação estiver completa será possível fazer ordenação de lista de forma muito fácil, basta passar uma assinatura de método que implemente comparable com o exemplo de código a seguir.

listaDeClientes.sort( cliente -> cliente.getNome() );
// Ou uma passando a própria referencia 
// para o método que retorna um comparable.
listaDeClientes.sort( Cliente::getNome );
De uma olhada na página do JDK8 para baixar o preview ou na página do projeto lambda.