Mostrando postagens com marcador Java. Mostrar todas as postagens
Mostrando postagens com marcador Java. Mostrar todas as postagens

terça-feira, 6 de maio de 2014

Recursividade

  Estava assistindo uma aula de Scala e em um dos exercícios tinhamos que implementar um método para descobrir a soma de uma lista de inteiros, porém o exercicio dava a sugestão de usar recursividade ao invés de fazer um loop.
  Neste post vou mostrar o raciocinio que utilizei para resolver o exercicio e mostrar como eles seriam resolvidos passo a passo em Java.

  Mas antes um pouco de teoria:
  • Para entender recursividade, você precisa entender recursividade.
  • PHP é um acronimo recursivo que significa: PHP: Hypertext Processor
  • WINE é outro exemplo de recursividade, a sigla significa: Wine Is Not an Emulator
  • outro exemplo é GNU que significa: Gnu's Not Unix
Deu pra ver onde quero chegar? em todos os casos acima você acaba criando um laço de repetição, pra entender recursividade, você tem que entender recursividade, então vá entender recursividade, pra isso você tem que entender recursividade... Ok parei.
Parece complicado, mas  na verdade é simples. Recursividade nada mais é do que chamar o metodo que está sendo declarado dentro de seu próprio corpo. Como exemplo, temos um metodo para ver o N numero da sequencia de Fibonacci:

    public static long fibonacci (int i) {
        if (i == 1) return 0;
        if (i == 2) return 1;

        long numero = fibonacci(i - 1) + fibonacci(i - 2);
        return numero;
    }

Olhos atentos perceberam que o metodo fibonacci, chama o metodo fibonacci logo antes de dar o return, isso é chamado de metodo recursivo.
  O que ocorre ali é o seguinte: A sequencia de fibonacci define que
  • primeiro termo da sequencia é 0
  • o segundo termo da sequencia é 1
  • a partir daí, o termo n é igual ao termo n-1 somado do termo n-2
Viu como é simples enxergar estas regras no codigo acima? Na hora que o metodo fosse executado com o argumento 5, ele se expandiria, e aconteceria algo +- assim:
fibonacci(5) = fibonacci(4) + fibonacci(3)

sabemos que fibonacci de 4 é igual a fibonacci de 3 + fibonacci de 2 então:

fibonacci(5) = fibonacci(3) + fibonacci(2) + fibonacci(3)

sabemos que fibonacci de 3 é igual a fibonacci de 2 + fibonacci de 1 se substituirmos isso na nossa igualdade temos:

fibonacci(5) = fibonacci(2) + fibonacci(1) + fibonacci(2) + fibonacci(2) + fibonacci(1)

pela definição da sequencia de fibonacci, sabemos que fibonacci(2) = 1 e fibonacci(1) = 0. subsitituindo isto na igualdade temos:

fibonacci(5) = 1 + 0 + 1 + 1 + 0
fibonacci(5) = 3

Pronto. Recursivamente descobrimos que o quinto termo da sequencia de fibonacci é 3, o que bate com a sequencia mostrada na wikipedia (linkada ali em cima)

Agora vamos implementar o método para descobrir a soma da lista.
Se fossemos utilizar a solução com o loop, seria mais ou menos assim:


    public static int somaLista(ArrayList<Integer> lista){
        int total=0;
        for (int i=0; i < lista.size(); i++){
            total = total + lista.get(i);
        }
        return total;
    }

Agora vamos pensar recursivamente:
primeiro precisamos definir uma regra para nos tirar do loop, assim, alguma hora vamos parar de invocar o método. Queremos somar os elementos da lista, então, se a lista estiver vazia, a soma será 0. Logo nossa regra é:
  • Se a lista estiver vazia, o resultado da soma é zero
Para que nossa regra nos ajude, a lista deverá diminuir a cada chamada do método, assim uma hora ela ficará vazia e terminaremos nossa execução. Então na hora de implementar o código vamos remover o primeiro elemento da lista, e somar com o resto da lista. O código fica assim:

    public static int somaListaRecursivo(List<Integer> lista){
                
        if (lista.isEmpty()) return 0;
        
        int aux=lista.get(0);
        lista.remove(0);
        
        return aux + somaListaRecursivo(lista);
    }

Ao executarmos o código

    public static void main(String[] args) {
        ArrayList<Integer> l = new ArrayList<>();
        l.add(2);
        l.add(3);
        l.add(3);
        System.out.println(somaListaRecursivo(l));
    }

temos a saida 8.

Como sempre, se tiver alguma dúvida, sugestão ou critica, deixe nos comentarios.

sábado, 26 de abril de 2014

Construtores



   Os construtores são utilizados para inicializar uma classe, apesar de serem simples de se utilizar e entender, algumas pessoas tem dúvidas e/ou acabam utilizando sem saber sobre sua existencia, com este post eu pretendo mostrar o conceito de construtor com um exemplo prático. A linguagem utilizada será o Java, os construtores serão utilizados para inicializar um JFrame já com algumas informações da nossa entidade.


Sobre a sintaxe dos construtores:
  • Construtores DEVEM ter o exato nome da classe, lembrando que Java é case sensitive
  • Construtores NUNCA terão retorno, nem mesmo void. Se for colocado algum tipo de retorno ele deixará de ser um construtor e se tornará um metodo normal.
  • Construtores podem ter qualquer visibilidade (public, default, protected ou private) porem construtores private podem dificultar herança (veja a seguir)
 Algumas coisas que você deve saber sobre construtores:
  • Usa-se o comando this() para chamar um construtor sem parametros
  • Usa-se o comando this("construtor") para chamar um construtor que pede uma String como parametro
  • Usa-se o comando super() para chamar o construtor da classe pai que não pede nenhum parâmetro
  • Usa-se o comando super("construtor pai") para chamar o construtor da classe pai que pede uma String como parâmetro.
  • Se você não definir um construtor, será criado um construtor padrão pela JVM: um construtor sem parametros e que apenas chama super()
  •  Todo construtor, por padrão, chama o construtor sem parâmetros da classe pai, então mesmo que você escreva código para isso, está implicito que na primeira linha depois de sua declaração existe o comando super(). O único jeito de alterar isto é você declarar explicitamente a chamada de algum outro consstrutor com this ou super.
  • Pelo item anterior, podemos observar que quando uma classe é instanciada, pelo menos um construtor de cada nivel da hierarquia é chamado até chegarmos no construtor da classe Object (pois nossas classes implicitamente herdam de Object)
  • Se você definir apenas um construtor com visibilidade private, sua classe não poderá ser instanciada fora da própria classe, isto é utilizado no padrão Singleton por exemplo.
A seguir está um exemplo simples de utilização de construtores:
 
  Primeiro eu criei um POJO de cliente:
public class Cliente {
    private String nome;
    private String tel;

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    public String getTel() {
        return tel;
    }

    public void setTel(String tel) {
        this.tel = tel;
    }
} 
  Nada de novo por aqui, uma classe de entidade com dois atributos, 2 getters e 2 setters.
    
  Depois eu criei um JFrame, este JFrame tem dois campos de texto, um para exibir o nome do cliente e outro para exibir o telefone:

  
public class ClienteFrame extends JFrame{
    
    private JTextField txtNome = new JTextField();
    private JTextField txtTel = new JTextField();

    public ClienteFrame() {
        this.setLayout(new GridLayout(4, 1));
        this.add(new JLabel("Nome"));
        this.add(txtNome);
        this.add(new JLabel("Telefone"));
        this.add(txtTel);
        this.setSize(300, 300);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public ClienteFrame(Cliente c){
        this();
        this.txtNome.setText(c.getNome());
        this.txtTel.setText(c.getTel());
    }    
    
}
  O JFrame tem dois atributos privados, que são os campos de texto que exibirão as informações. Além destes atributos, a classe ClienteFrame tem dois “métodos” que tem o mesmo nome da classe, estes são os construtores desta classe. O construtor sem argumentos monta o layout no nosso frame, enquanto, o construtor que pede um argumento chama o construtor sem argumentos (para que o layout seja montado) e depois adiciona as informações que recebeu como parametro.

SEMPRE que uma classe é instanciada, seu construtor é chamado. Perceba:
JTextField txt = new JTextField();
Cliente c = new Cliente(); //outro construtor
JTextField txt2 = new JTextField("caixa com texto"); //construtor para inicializar o campo contendo um texto

Para finalizar, vamos instanciar nossa classe ClienteFrame com os dois construtores e ver a diferença:
primeiro instanciamos o Frame sem passar nenhum argumento:

public class Main {
    public static void main (String[] args){
        ClienteFrame frame = new ClienteFrame();
        frame.setVisible(true);
    }
}

o resultado é um frame com os campos em branco, como mostra a figura:



Mas podemos também instanciar nosso frame passando um objeto do tipo Cliente como parâmetro:

public class Main {
    public static void main (String[] args){
        //criamos o objeto parametro:
        Cliente c = new Cliente();
        c.setNome("Nome do cliente");
        c.setTel("2673-9000");
        //passamos o objeto criado para o nosso frame:
        ClienteFrame frame = new ClienteFrame(c);
        frame.setVisible(true);
    }
}

O resultado será:


No momento acredito que isto seja o básico, se tiver qualquer dúvida sobre o assunto deixe nos comentários