BC0505 – Processamento da Informação Assunto: Modularização de código e passagem de parâmetros Versão: 0.2 Aula Prática: 4 Introdução – Modularização No Java, como em outras linguagens de Programação Orientadas a Objeto, o código pode ser simplificado empregando-se métodos de classe, de princípio análogo às funções nas linguagens funcionais. Em algoritmos seqüenciais, como os estudados nesta disciplina, sem empregar Programação Orientada a Objeto, não há diferenças notáveis entre métodos e funções. Toda a classe executável em Java já deve incluir ao menos um método, o método main, que é aquele chamado automaticamente pela JVM quando a classe principal é executada. Como já visto a declaração do método main é feita na forma: public static void main(String[] args) { código do usuário } De forma similar, outros métodos podem ser definidos pelo usuário para executar blocos de código repetidos várias vezes. Por exemplo, uma função fatorial (recursiva) pode ser implementada em um método como segue: [1] [2] [3] [4] [5] [6] public static long fatorial(long n) { return n>1?n*fatorial(n - 1):1; } [1] Métodos públicos podem ser acessados por outras classes. Em POO, métodos também podem ser privados e protegidos, por enquanto utilizaremos apenas métodos públicos. [2] Lembre-se também que métodos declarados como estáticos apenas podem acessar métodos e variáveis de classe estáticas (não instanciadas em objetos, ou únicas da classe). [3] O tipo da variável retornada pelo método deve ser declarado ou identificado por void (vazio) no caso do método não retornar nada. [4] A nomenclatura segue as mesmas regras de variáveis, como estudado (http://drop.io/Processamento/asset/00-introd-prog-java-com-netbeans-pdf ). [5] Definimos os parâmetros de entrada do método declarando as variáveis locais que receberão os valores, separadas por vírgula, (existirão somente no escopo do método). [6] Caso o método não tenha sido declarado como void (vazio), o método deverá incluir um comando return, que finaliza a execução do método e retorna ao ponto de chamada o valor indicado. Métodos podem ser copiados e reutilizados em novos projetos. Métodos declarados públicos podem ser acessados externamente por qualquer classe, simplificando o código principal, o que é particularmente útil em projetos com códigos extensos. Para utilizar uma classe externa, basta importá-la no início da classe, caso não esteja no mesmo projeto. Quando utilizamos o método Math.pow(2,6) para efetuar a operação 26, estamos chamando o método pow (exponenciação) da classe padrão Math, que oferece funções (ex. sin(), cos(), random(), etc.) e constantes (Math.PI e Math.E ) matemáticas. Classes padrão do Java como System (chamadas do sistema), Math , String, Integer, Double, etc. são automaticamente incluídas. As demais devem ser manualmente especificadas, como java.util.Scanner e javax.swing.JOptionPane. 1 Atividade 1 – Modularizando o código O código da página seguinte deve ser simplificado escrevendo-se métodos modulares com o objetivo de reduzir a repetição de código ao longo do programa. Por exemplo, o código: double valorInicial = Double.parseDouble( JOptionPane.showInputDialog("Valor inicial: ", "300")); int meses = Integer.parseInt( JOptionPane.showInputDialog("Quantos meses? ", "1")); retorna uma mensagem de erro no caso de uma entrada de dados inválida (faça o teste), ex. String vazia, caracteres não numéricos ou com erros de formatação, como “,” ao invés de “.”). O comando pode ser substituído por um método que desempenhe a leitura incorporando tratamento de erros. double valorInicial = ler("Valor inicial: ", 300); int meses = ler("Quantos meses?", 1); implementando-se na classe um método ler de forma que: public static double ler(String m, double d) { try { return Double.parseDouble( JOptionPane.showInputDialog(m, d)); } catch (Exception e) { e.printStackTrace(); return d; } } O método ler pode ser sobrecarregado* para aceitar outros tipos de variável, como números inteiros: public static int ler(String m, int i) { try { return Integer.parseInt(JOptionPane.showInputDialog(m, i)); } catch (Exception e) { e.printStackTrace(); return i; } Na estrutura try { comandos } catch(Exception) { código em caso de erro }, o comando e.printStackTrace exibe a mensagem de erro produzida no console (pode ser omitida) apenas para fins didáticos, mas o programa continua sua execução normalmente, retornando o valor padrão especificado na chamada. Repare que o método chamado depende do valor passado e da variável que recebe o retorno. a) O programa a seguir não deve ser copiado, em lugar, tente reduzir ao máximo a repetição do código dentro do método main, tentando deixá-lo o mais breve possível. Dica: passe a um método os valores através de parâmetros, de forma que a chamada fique parecida com mensagem = tempo("investimento", juros, inicial, complemento, objetivo); * Sobrecarregar métodos significa criar vários métodos com mesmo nome, porem que operam com tipos de variáveis diferentes, aceitem parâmetros adicionais ou de tipos diferentes. public class Main { /** Variáveis de classe ou "variáveis Globais" o modificador final indica uma constante */ final static double Poupanca = 1.0055; // + 0,55% ao mes na media final static double CDB = 1.0075; // + 0,75% ao mes final static double LTN = 1.01; // + 1% ao mes final static double Multimercado = 1.014; // + 1,4% ao mes final static double taxaAnual = 0.01; // - 1% ao ano public static void main(String[] args) { double inicial = ler("Qual o valor investido? ", 1000f); double complemento = ler("Qual o complemento mensal? ", 0f); double objetivo = ler("Qual o seu objetivo? ", 1000000f); String frase = String.format( "O tempo para um investimento de R$ %,.2f com aplicações "+ "mensais de R$ %,.2f\n atingir R$ %,.2f é:\n\n", inicial, complemento, objetivo); int meses = 0; double saldo = inicial; double juros = Poupanca; while (saldo < objetivo) { meses++; saldo = saldo * juros + complemento; } frase += String.format("%d meses (%d anos) na poupanca\n", meses, meses / 12); meses = 0; saldo = inicial; juros = CDB; while (saldo < objetivo) { meses++; saldo = saldo * juros + complemento; } frase += String.format( "%d meses (%d anos) no CDB\n", meses, meses / 12); meses = 0; saldo = inicial; juros = LTN; while (saldo < objetivo) { meses++; saldo = saldo * juros + complemento; } frase += String.format( "%d meses (%d anos) em Letras do Tesouro Nacional\n", meses, meses / 12); meses = 0; saldo = inicial; juros = Multimercado; while (saldo < objetivo) { meses++; saldo = saldo * juros + complemento; if (meses % 12 == 0) saldo -= saldo * taxaAnual; } frase += String.format( "%d meses (%d anos) em Fundos Multimercado\n", meses, meses / 12); JOptionPane.showMessageDialog(null, frase); } b) Modularize o código de forma que o novo método main contenha apenas um comando, como segue: public static void main(String[] args) { JOptionPane.showMessageDialog(null, frase(), "Planejamento financeiro", JOptionPane.CLOSED_OPTION); } public static String frase() { double i = ler("Qual o valor investido? ", 1000f); double c = ler("Qual o complemento mensal? ", 0f); double o = ler("Qual o objetivo? ", 1000000f); return String.format("O tempo para um investimento de R$ %,.2f\n" + "com aplicacoes mensais de R$ %,.2f atingir R$ %,.2f " + "seria:\n\n" + tempo("na Poupanca", .55, 0, i,c,o) + tempo("no CDB", .75, 0, i,c,o) + tempo("em Letras do Tesouro Nacional", 1.1, 0,i,c,o) + tempo("em Fundos Multimercado", 1.5, 1, i,c,o),i,c,o); } public static String tempo(String s, double juros, double taxa, double saldo, double complemento, double objetivo) {... Atividade 2 – Sobrecarga de métodos Como demonstrado na atividade anterior, os métodos podem ser sobrecarregados para lidar com tipos diferentes de entrada e saída. Podemos implementar classes com o propósito de oferecer ferramentas reutilizáveis para tratamento da informação de um dado tipo, ou que aceitem parâmetros distintos. O código a seguir introduz uma subclasse embutida que propõe operar um determinado tipo de objeto. Lembre-se que a classe principal (cujo nome é o mesmo do arquivo) sempre contém o método main. a) Note que houve um erro ao utilizar valores de ponto flutuante. Isso ocorre porque o Java considera valores de dupla precisão como padrão. Uma solução é acrescentar um f no final do número, indicando que este é do tipo float. b) Modifique a classe Cubo para que opere com double. c) Crie um método para testar a isometria do cubo, retornando true se as laterais do cubo forem iguais. d) Crie um método que retorne a área de superfície do cubo. 3. Exercícios para Casa 3.1. Construa uma subclasse que receba um valor “raio”, que pode ser passado por byte, int, long, float ou double. Crie métodos distintos para retornar (em double): a) o perímetro da circunferência; b) a área do circulo; c) o volume da esfera; 3.3. Crie uma classe Temperatura que receba uma temperatura em graus Celsius, Fahrenheit e Kelvin através dos métodos celsius(t), kelvin(t) e fahrenheit(t) (sobrecarregados) em qualquer formato (byte, int, long, float ou double) realizando as conversões necessárias. Um método toString() deve retornar uma String no seguinte formato: "%f ºC = %f ºF = % K". Dados: (Fahrenheit) = 1.8*(Celsius) + 32; (Kelvin) = (Celsius) + 273.15;