Métodos Java e decomposição de programas
return. Descubra onde cada variável pode ser usada, por que um método trabalha com cópias dos valores de seus argumentos e como a pilha de chamadas acompanha os métodos em execução. Faça sobrecarga de métodos e preveja qual versão Java chama. Por fim, divida um problema em pequenos métodos que fazem uma tarefa cada, elimine código repetido e construa e teste um programa um método de cada vez.BásicoAula 3 de 11 do curso Curso de Programação orientada a objetos com Java
O que você vai aprender
- Defina métodos estáticos, chame-os a partir de
maine de outros métodos e forneça as informações necessárias por meio de parâmetros.- Defina um método e chame-oEscreva o cabeçalho e o corpo de um método no lugar correto, chame o método pelo nome e acompanhe como a execução passa para o método e retorna.
- Passe informações para um método por meio de parâmetrosDeclare parâmetros com tipo e nome, chame o método com argumentos compatíveis e use vários parâmetros na ordem correta.
- Defina um método e chame-o
- Escreva métodos que calculam um valor e o devolvem com
returne use os valores retornados em variáveis, expressões e condições.- Retorne um valor e use-oDeclare um tipo de retorno, devolva um resultado com uma instrução return e decida no código que chama o método o que acontece com o valor retornado.
- Retorne de dentro de estruturas condicionais e laçosUse instruções return dentro de instruções if e laços, garanta que todos os caminhos retornem um valor e escreva métodos que respondam a uma pergunta de sim ou não.
- Retorne um valor e use-o
- Saiba onde cada variável pode ser usada, o que um método pode ou não alterar no código que o chama e como a pilha de chamadas acompanha os métodos em execução.
- Identifique onde cada variável pode ser usadaAplique as regras de escopo para variáveis locais, parâmetros e variáveis declaradas em blocos e corrija os erros de compilação causados por problemas de escopo.
- Compreenda que os valores dos argumentos são passados como cópiasPreveja o que um método pode alterar no código que o chama: o método trabalha com cópias dos valores dos argumentos, portanto reatribuir um parâmetro não altera a variável de quem chamou.
- Acompanhe as chamadas de métodos na pilha de chamadasAcompanhe como Java registra métodos em execução em registros de ativação, rastreie programas em que métodos chamam outros métodos e interprete um rastreamento da pilha.
- Identifique onde cada variável pode ser usada
- Dê o mesmo nome a vários métodos com listas de parâmetros diferentes e preveja qual versão Java chama para um conjunto de argumentos.
- Escreva métodos sobrecarregadosDeclare métodos que compartilham um nome, saiba quais diferenças tornam uma sobrecarga válida e use sobrecarga quando os métodos realizam a mesma tarefa.
- Preveja qual método sobrecarregado será executadoDetermine qual versão Java escolhe a partir dos tipos dos argumentos, incluindo a conversão automática de ampliação, e reconheça chamadas que não compilam.
- Escreva métodos sobrecarregados
- Divida um problema em pequenos métodos que fazem uma tarefa cada, substitua código repetido por métodos parametrizados e construa e teste um programa um método de cada vez.
- Atribua uma tarefa clara a cada métodoReconheça um programa bem dividido, separe código que faz tarefas demais e mantenha o cálculo separado da entrada e da saída.
- Substitua código repetido por um método parametrizadoEncontre código repetido com pequenas diferenças, transforme-o em um método cujos parâmetros representem essas diferenças e verifique se o programa continua se comportando da mesma forma.
- Projete um programa de forma descendente e teste cada métodoPlaneje um programa como uma sequência de chamadas de métodos, escreva-o passo a passo com métodos provisórios e teste cada método com entradas cujos resultados você conhece.
- Atribua uma tarefa clara a cada método
Guia de estudo de Métodos em Java
1Escreva e chame seus próprios métodos
Um programa fica mais fácil de acompanhar quando suas etapas significativas têm nomes. Um método dá um nome a um grupo de instruções, e uma chamada executa essas instruções no ponto em que são necessárias. Comece com um método que sempre exibe a mesma linha e depois adicione parâmetros para que uma definição possa lidar com entradas diferentes. Ler um cabeçalho e relacioná-lo a uma chamada permite ver quais informações cada etapa precisa antes de examinar seu corpo.
1.1 Defina um método e chame-o
Um método é um bloco nomeado de instruções que executa uma tarefa. Definir um método disponibiliza essa tarefa; chamá-lo faz a tarefa ser executada.
Leia o cabeçalho e o corpo
public static void printLine() {
System.out.println("----------");
}
A primeira linha é o cabeçalho. Leia suas partes da esquerda para a direita:
publicpermite que código de outras classes chame o método.staticfaz o método pertencer à classe. Não é necessário um objeto para chamá-lo.voidindica que o método não retorna valor.printLinenomeia a tarefa.()é a lista de parâmetros vazia: este método não precisa de entrada.
As chaves delimitam o corpo, as instruções executadas em uma chamada. Não há ponto e vírgula entre esse cabeçalho e sua chave de abertura.
Coloque a definição na classe
public class Main {
public static void main(String[] args) {
System.out.println("Start");
printLine();
System.out.println("Middle");
printLine();
}
public static void printLine() {
System.out.println("----------");
}
}
main e printLine são métodos separados dentro de Main. A chave de fechamento de main vem antes da definição de printLine. Um método não pode ser definido dentro de outro; uma chave fora do lugar pode produzir “illegal start of expression”.
As definições podem aparecer em qualquer ordem. Mover printLine para cima de main não altera o momento em que ele é executado. Um método que nunca é chamado não é executado apenas porque sua definição aparece no arquivo.
Acompanhe uma chamada e o retorno a quem chamou
A chamada printLine(); consiste no nome, nos parênteses e em um ponto e vírgula, pois a chamada é uma instrução isolada. A execução começa em main:
- Exibe “Start”.
- Entra em
printLine, exibe dez hífens e continua após a chamada. - Exibe “Middle”.
- Entra novamente em
printLinee exibe dez hífens outra vez.
A saída é:
Start
----------
Middle
----------
As duas chamadas usam a mesma definição. Alterar a linha que ela exibe muda os dois lugares que a usam.
Nomeie e chame métodos com precisão
Use um verbo ou expressão verbal em camelCase, começando com letra minúscula: printReceipt, calculateAverage ou isValidCode. Java trata maiúsculas e minúsculas como diferentes: PrintLine() não encontra um método chamado printLine. Escrever printLine; também falha; os parênteses fazem parte da chamada.
Para um método estático de outra classe, escreva primeiro o nome da classe. Math.max(3, 8) resulta em 8, Math.abs(-4) resulta em 4 e Math.sqrt(16.0) resulta em 4.0. Seus próprios métodos na mesma classe podem ser chamados apenas pelo nome.
Estes exemplos usam a forma clássica baseada em classe com public static void main(String[] args). O Java 25 também aceita arquivos-fonte compactos com void main() e sem uma classe envolvendo o código. Mantenha a forma clássica ao executar estes exemplos; seus métodos auxiliares são declarados static. Métodos da biblioteca de Java que você chama, como System.out.println, não precisam ser estáticos.
Principais conclusões
- Coloque as definições de métodos dentro da classe e fora de outros métodos.
- Uma definição disponibiliza uma tarefa; uma chamada a executa e depois continua em quem chamou.
- Escreva parênteses em uma chamada e ponto e vírgula quando a chamada for uma instrução.
- Use um nome descritivo em camelCase e respeite exatamente as letras maiúsculas e minúsculas.
- Chame um método estático de outra classe com o nome da classe, como em
Math.max(3, 8).
1.2 Passe informações para um método por meio de parâmetros
Um parâmetro permite que um método lide com valores que mudam de uma chamada para outra. Um argumento é o valor fornecido para esse parâmetro quando o método é chamado.
Dê um tipo e um nome a cada entrada
public static void printStars(int count) {
for (int i = 0; i < count; i++) {
System.out.print("*");
}
System.out.println();
}
int count declara um parâmetro. Em printStars(3);, o argumento 3 se torna o valor inicial de count. O laço é executado três vezes, portanto exibe *** e println() encerra a linha. printStars(8); usa o mesmo corpo com count igual a 8.
O tipo é escrito na definição, não na chamada. Escreva printStars(5);, não printStars(int 5);.
Avalie os argumentos antes de entrar no corpo
Um argumento pode ser um literal, uma variável ou uma expressão:
int n = 4;
printStars(n * 2);
Java avalia n * 2 primeiro. Ele passa o valor resultante 8, portanto o corpo começa com count igual a 8. O nome da variável de quem chama não precisa ser igual ao nome do parâmetro.
Associe vários parâmetros por posição
Cada parâmetro precisa de seu próprio tipo. Um método para desenhar retângulos pode começar com este cabeçalho:
public static void printRectangle(int width, int height)
A chamada printRectangle(5, 2); atribui a width o valor 5 e a height o valor 2. Inverter os argumentos produz um retângulo com 2 de largura e 5 de altura. Ambas as chamadas compilam porque os dois argumentos são int; apenas a forma desejada indica qual ordem está correta. Escrever (int width, height) no cabeçalho falha porque height não tem tipo declarado.
Tipos diferentes tornam alguns erros de ordem mais fáceis de identificar:
public static void printRepeated(String text, int times) {
for (int i = 0; i < times; i++) {
System.out.print(text);
}
System.out.println();
}
printRepeated("ab", 3); exibe “ababab”. printRepeated(3, "ab"); não corresponde a uma String seguida de um int. A quantidade de argumentos também deve corresponder: printRectangle(5); deixa um parâmetro sem valor.
Verifique tipos numéricos compatíveis
Java converte automaticamente um int em double por ampliação. Um método com parâmetros (double km, double hours) aceita os argumentos (150, 2), recebendo 150.0 e 2.0. Todo valor int pode ser representado exatamente como double.
Java não converte implicitamente um argumento double para um parâmetro int por estreitamento. printStars(2.9); falha porque a conversão perderia a parte fracionária. A conversão explícita em printStars((int) 2.9); produz 2, portanto dois asteriscos são exibidos. Use uma conversão explícita apenas quando descartar essa parte for o comportamento desejado.
Escolha um parâmetro para cada informação necessária à tarefa. Receber um texto e uma contagem permite usar printRepeated com entrada do teclado, uma chamada de teste fixa ou outro método. Seu corpo não precisa decidir de onde vieram esses valores.
Principais conclusões
- Um parâmetro é declarado em um cabeçalho; um argumento fornece seu valor em uma chamada.
- Java avalia as expressões dos argumentos antes de executar o método chamado.
- Os argumentos correspondem aos parâmetros por posição, quantidade e tipo compatível.
- Escreva um tipo para cada parâmetro, mas nenhum tipo na chamada.
- Um int pode ser ampliado para double; um double precisa de conversão explícita para se tornar int.
- Trocar argumentos do mesmo tipo pode compilar e ainda assim alterar o resultado.
2Retorne resultados de métodos
Um método pode fazer mais do que exibir: ele pode devolver um valor ao código que o chamou. Isso permite usar um cálculo em outro cálculo, em uma condição ou em um relatório posterior. Acompanhe como tipos de retorno, expressões e atribuições se relacionam e depois use retornos em decisões e buscas. A posição de um return importa: ela determina tanto a resposta que chega a quem chamou quanto a parte do método que tem chance de ser executada.
2.1 Retorne um valor e use-o
Um valor de retorno é um resultado enviado por um método a quem o chamou. Depois que uma chamada termina, ela pode ser usada como uma expressão com o tipo desse resultado.
Declare o que é devolvido
public static int sum(int a, int b) {
return a + b;
}
int substitui void no cabeçalho porque esse método devolve um inteiro. A instrução return avalia a + b e envia o valor ao ponto da chamada. Para sum(4, 7), esse valor é 11.
Quem chama decide o que acontece em seguida:
int total = sum(4, 7);
System.out.println(sum(4, 7));
int doubled = sum(2, 3) * 2;
A primeira linha armazena 11; a segunda exibe 11; a terceira armazena 10. Um valor retornado também pode ser usado em uma condição, como if (sum(a, b) > 10).
Um resultado int compatível pode ser ampliado ao ser retornado por um método double. Um resultado double não pode ser retornado por um método int sem uma conversão explícita adequada.
Calcule a expressão antes de converter o resultado
public static double average(int a, int b) {
return (a + b) / 2.0;
}
Para average(3, 4), o numerador é 7. Dividir pelo literal double 2.0 resulta em 3.5. Se a expressão fosse (a + b) / 2, Java primeiro dividiria dois valores int e obteria 3. Só então ampliaria esse valor para o 3.0 retornado. Um tipo de retorno double não corrige uma divisão inteira já realizada dentro do corpo.
Distinga retornar de exibir
| Comportamento do método | O que quem chama recebe | O que aparece na tela |
|---|---|---|
return a + b; em um método int | A soma | Nada dessa instrução |
System.out.println(a + b); em um método void | Nenhum valor | A soma |
Uma chamada void não pode fornecer um valor em uma atribuição ou outra chamada. Se printSum for void, int total = printSum(1, 2); falha mesmo que printSum exiba um número. Use um método que retorna valor para cálculos e deixe que quem chama escolha se vai exibi-lo.
Retorne texto e respostas de sim ou não
Os tipos de retorno também incluem String e boolean. Um método de saudação pode retornar "Hello, " + name + "!", resultando em “Hello, Ana!” para o argumento "Ana". Um método isEven(int n) pode retornar n % 2 == 0.
Um método de formatação transforma um número em texto reutilizável:
public static String formatDuration(int minutes) {
return minutes / 60 + " h " + minutes % 60 + " min";
}
Para 135, a divisão inteira resulta em 2 horas inteiras e o resto resulta em 15 minutos. O resultado é “2 h 15 min”; para 60, é “1 h 0 min”.
Guarde ou combine o resultado
Uma chamada como sum(4, 7); compila, mas descarta seu resultado. Se square(x) retornar um novo valor, use x = square(x); para armazená-lo em x.
Um resultado também pode se tornar um argumento imediatamente. Em Math.max(sum(1, 2), 4), sum(1, 2) primeiro resulta em 3 e depois Math.max(3, 4) resulta em 4. Avalie a chamada interna antes de usar seu resultado na chamada externa.
Principais conclusões
- O tipo de retorno declarado informa a quem chama que tipo de resultado a chamada fornece.
- Retornar fornece um valor; exibir mostra um valor.
- A expressão é calculada antes de seu resultado ser convertido para o tipo de retorno.
- Armazene um valor retornado quando o código posterior precisar dele; uma chamada isolada o descarta.
- Um valor retornado pode ser argumento de outro método.
2.2 Retorne de dentro de estruturas condicionais e laços
Uma instrução return encerra imediatamente a chamada do método atual. Dentro de uma condição ou de um laço, ela ainda encerra o método inteiro, não apenas aquele bloco.
Dê uma resposta a cada caminho
public static int larger(int a, int b) {
if (a > b) {
return a;
}
return b;
}
larger(9, 4) retorna 9 de dentro do if. Para larger(2, 6), o corpo do if é ignorado e o return final fornece 6. Entradas iguais como (5, 5) também chegam ao return final, que fornece 5. Não é necessário else após o primeiro return porque esse caminho já saiu do método.
Em um método comum que retorna valor, nenhum caminho possível pode chegar à chave de fechamento sem fornecer um valor. Um método de sinal que retorna apenas para entradas positivas e negativas deixa o zero sem resposta:
public static String sign(int n) {
if (n > 0) {
return "positive";
} else if (n < 0) {
return "negative";
}
return "zero";
}
O return final completa o método. Duas instruções if separadas, uma testando n > 0 e outra testando n <= 0, ainda precisam de um return final ou de uma estrutura if/else clara. A verificação de retorno de Java não deduz que essas duas comparações abrangem todos os inteiros. Uma instrução diretamente após um return incondicional no mesmo bloco é inalcançável e rejeitada.
Termine uma busca no momento certo
public static int firstMultipleOf7(int start, int end) {
for (int i = start; i <= end; i++) {
if (i % 7 == 0) {
return i;
}
}
return -1;
}
Para (10, 20), o laço rejeita 10, 11, 12 e 13 e retorna 14. A chamada termina sem verificar de 15 a 20. Para (15, 20), o laço termina sem encontrar correspondência, portanto o return depois dele fornece -1, o sinal combinado de “não encontrado”.
Colocar else { return -1; } dentro do laço encerraria a busca após o primeiro candidato rejeitado. A busca a partir de 10 informaria falha antes de chegar a 14. O retorno de falha deve vir após a verificação de todos os candidatos.
Retorne a própria condição
Uma comparação já produz um booleano. Escreva return n % 2 == 0; em vez de um if/else que retorna true e false separadamente. O nome de um método com retorno booleano geralmente começa com is ou has, de modo que uma chamada possa ser lida naturalmente dentro de um if.
public static boolean isLeapYear(int year) {
return (year % 4 == 0 && year % 100 != 0)
|| year % 400 == 0;
}
Isso retorna true para 2024 e 2000, mas false para 1900 e 2023. Use if (isLeapYear(y)) diretamente.
Saia antecipadamente de um método void
Um método void usa return; sem valor. Por exemplo, printSquareRoot(double x) pode exibir “No real square root” e retornar imediatamente para uma entrada negativa. Para outras entradas, pode exibir Math.sqrt(x), que resulta em 1.5 para 2.25. Escrever return 5; em um método void falha porque seu cabeçalho promete não retornar valor.
Principais conclusões
returnencerra imediatamente a chamada atual, inclusive quando está dentro de um laço.- Um método que retorna valor não deve chegar à chave de fechamento sem uma resposta.
- Coloque o retorno de falha de uma busca após o laço, para que os candidatos posteriores possam ser verificados.
- Uma comparação pode ser retornada diretamente como um booleano.
- Use
return;sem valor para sair antecipadamente de um método void. - Código diretamente após um return incondicional no mesmo bloco é inalcançável.
3Acompanhe variáveis e chamadas ao longo de um programa
Uma chamada de método não dá a um método auxiliar acesso a todas as variáveis do programa. Cada chamada tem seus próprios parâmetros e variáveis locais, e Java mantém esses valores em um registro de ativação separado. Use o escopo para determinar onde um nome é permitido, a passagem por valor para prever o que as atribuições podem alterar e a pilha de chamadas para acompanhar o trabalho ainda não concluído. Essas três ideias explicam por que duas variáveis podem ter o mesmo nome e armazenar valores diferentes.
3.1 Identifique onde cada variável pode ser usada
O escopo de uma variável é a região do código em que seu nome pode ser usado. Comece pelas chaves em torno de sua declaração: um nome local pertence a um método ou bloco específico.
As variáveis locais de quem chama permanecem em seu método
public static void main(String[] args) {
int price = 20;
printDouble(price);
}
public static void printDouble(int price) {
System.out.println(price * 2);
}
O price de main e o parâmetro price de printDouble são variáveis distintas. O argumento fornece o valor necessário ao método auxiliar, portanto ele exibe 40.
Remover o parâmetro e chamar printDouble() não permite que o método auxiliar leia o price local de main. Seu corpo falharia com “cannot find symbol”. Chamar um método a partir de outro não une seus escopos. Métodos diferentes podem usar o nome count sem conectar suas variáveis.
Um bloco aninhado cria um escopo menor
Uma variável local pode ser usada de sua declaração até a chave de fechamento de seu bloco. Um parâmetro fica disponível em todo o corpo do método. Um contador declarado em for (int i = 0; i < 3; i++) pertence a esse laço; i não pode ser lido depois dele.
Para manter um resultado após um laço, declare-o antes do laço:
int sum = 0;
for (int i = 1; i <= 5; i++) {
sum += i;
}
System.out.println(sum);
As somas fazem sum passar por 1, 3, 6, 10 e 15. A exibição final pode ler sum porque o bloco que o contém ainda não terminou. i é necessário apenas para o laço e permanece dentro de seu escopo.
Mover int sum = 0; para o corpo do laço cria um novo sum a cada passagem. Cada um começa em zero e desaparece no fim dessa passagem. Ele não pode manter uma soma acumulada nem ser exibido após o laço.
Verifique nomes e valores iniciais separadamente
Duas variáveis locais com o mesmo nome não podem ter escopos sobrepostos dentro de um método. Um método com um parâmetro x não pode declarar outra variável local x; um laço que declara i não pode declarar outro i em seu corpo. Renomeie a segunda variável ou use a existente.
Dois laços consecutivos podem declarar int i. O escopo do primeiro laço terminou antes da segunda declaração. As chaves, e não o arquivo inteiro, determinam essa reutilização.
Um nome permitido também precisa de um valor antes de ser lido. int total; total++; falha porque ++ precisa ler o valor anterior, e uma variável local não recebe valor inicial automático. Use int total = 0; para uma soma acumulada.
Mantenha uma variável local no menor bloco que precisa dela. Se um método precisa de informações de quem o chama, transforme essas informações em parâmetros. Se quem chama precisa de um resultado, retorne-o. Assim, o cabeçalho e o corpo do método mostram de onde vêm seus dados.
Principais conclusões
- Um nome local fica disponível de sua declaração até o fim de seu bloco.
- Um método chamado não pode ler pelo nome as variáveis locais de quem o chamou.
- Declare um acumulador antes de um laço quando ele precisar manter um total ou ser lido depois.
- Nomes locais não podem ter escopos sobrepostos dentro de um método, e variáveis locais precisam de valores antes do uso.
3.2 Compreenda que os valores dos argumentos são passados como cópias
Java passa argumentos por valor. No início de uma chamada, cada parâmetro recebe uma cópia do valor de seu argumento. Atribuir um valor ao parâmetro altera essa variável local.
Rastreie a cópia separadamente
public static void main(String[] args) {
int score = 10;
addBonus(score);
System.out.println(score);
}
public static void addBonus(int score) {
score = score + 5;
System.out.println(score);
}
Há duas variáveis chamadas score. Acompanhe seus valores em cada ponto:
| Momento | score de main | score de addBonus |
|---|---|---|
| Antes da chamada | 10 | Ainda não há chamada |
Na entrada de addBonus | 10 | 10 |
| Após a atribuição do método auxiliar | 10 | 15 |
| Após o retorno do método auxiliar | 10 | A chamada terminou |
O método auxiliar exibe 15, depois main exibe 10. Compartilhar um nome não faz as duas variáveis compartilharem o armazenamento. Renomear o parâmetro não alteraria esse comportamento.
Retorne o novo valor e armazene-o
public static int addBonus(int score) {
return score + 5;
}
Com esta versão, escreva score = addBonus(score);. Java copia o valor antigo para o parâmetro, calcula 15, retorna esse valor e o atribui à variável de quem chamou. A atribuição em quem chama é a etapa que altera essa variável.
Um resultado também pode ser armazenado em outro lugar. Se triple(int n) multiplicar seu n local por 3 e retorná-lo, então int a = 4; int b = triple(a); deixa a igual a 4 e atribui a b o valor 12. Exibir a + " " + b mostra “4 12”.
Aplique a mesma regra a referências String
Uma variável String armazena uma referência a um objeto String. Java copia essa referência para um parâmetro String:
public static void exclaim(String text) {
text = text + "!";
}
Se word de quem chama se referir a “hi”, exclaim(word); deixa word se referindo a “hi”. A concatenação cria uma nova String, e a atribuição altera apenas aquilo a que o parâmetro se refere. O conteúdo existente de uma String não pode ser alterado.
Para manter o novo texto, retorne text + "!" de um método String como exclaimed e depois escreva word = exclaimed(word);.
Para objetos mutáveis, como listas, uma referência copiada ainda pode apontar para o mesmo objeto. Um método pode alterar o conteúdo desse objeto por meio da referência copiada. Reatribuir o parâmetro ainda não pode fazer a variável de quem chamou se referir a outro objeto. A regra da referência copiada e a regra do número copiado são ambas passagem por valor.
Você pode reatribuir um parâmetro, mas uma variável local separada como result pode facilitar a leitura de um cálculo mais longo: ela mantém a entrada original disponível e mostra qual valor será retornado.
Principais conclusões
- Cada parâmetro recebe uma cópia do valor de seu argumento.
- Reatribuir um parâmetro deixa inalterada a variável de quem chamou.
- Para manter um novo valor calculado, retorne-o e atribua-o em quem chamou.
- Uma referência copiada pode acessar o mesmo objeto mutável, mas a reatribuição do parâmetro permanece local.
3.3 Acompanhe as chamadas de métodos na pilha de chamadas
A pilha de chamadas registra chamadas que começaram, mas ainda não terminaram. Cada chamada recebe um registro de ativação com seus parâmetros, suas variáveis locais e o ponto em que quem chamou continuará.
Empilhe um registro, conclua-o e remova-o
A pilha funciona pelo princípio último a entrar, primeiro a sair. A chamada mais recente fica no topo e é executada enquanto quem a chamou aguarda abaixo. Quando ela retorna, Java remove seu registro e retoma quem chamou.
public static void main(String[] args) {
int total = totalSeconds(2, 30);
System.out.println(total);
}
public static int totalSeconds(int minutes, int seconds) {
int fromMinutes = toSeconds(minutes);
return fromMinutes + seconds;
}
public static int toSeconds(int minutes) {
return minutes * 60;
}
Acompanhe o trabalho ainda não concluído:
maincomeça e chamatotalSeconds(2, 30). Sua atribuição atotaldeve esperar.- O novo registro tem
minutes = 2eseconds = 30. Ele chamatoSeconds(minutes)e aguardafromMinutes. toSecondsrecebe seu própriominutes = 2. Ele retorna120e seu registro é removido.totalSecondsarmazenafromMinutes = 120, adiciona30e retorna150. Seu registro é removido.mainarmazenatotal = 150e exibe150.
No ponto mais profundo, os registros de baixo para cima são main, totalSeconds e toSeconds. Ambos os métodos auxiliares têm um parâmetro chamado minutes, mas esses parâmetros ocupam registros diferentes. As variáveis locais de quem chama e está aguardando não ficam visíveis para o método acima dele.
Uma chamada posterior recebe um novo registro. Um contador local não se lembra de seu valor anterior após o término da chamada; o valor de retorno é o que pode levar um resultado de volta.
Leia um rastreamento da pilha a partir do erro
Uma exceção não tratada exibe um rastreamento da pilha que mostra onde o erro ocorreu e quais chamadas levaram até ele. Veja um arquivo completo:
public class Main {
public static void main(String[] args) {
report(300, 0);
}
public static void report(int meters, int minutes) {
int speed = perMinute(meters, minutes);
System.out.println(speed + " m per minute");
}
public static int perMinute(int meters, int minutes) {
return meters / minutes;
}
}
A primeira linha da saída é Exception in thread "main" java.lang.ArithmeticException: / by zero. Os registros abaixo dela são:
at Main.perMinute(Main.java:12)
at Main.report(Main.java:7)
at Main.main(Main.java:3)
O registro superior identifica a divisão inteira por zero. Os dois seguintes localizam as chamadas que levaram até ela. Os números de linha pertencem exatamente a esta disposição do arquivo; adicionar uma linha os altera.
A pilha tem espaço finito. Uma cadeia que continua adicionando chamadas sem permitir que terminem pode causar StackOverflowError. A visualização da pilha de um depurador permite examinar a mesma cadeia enquanto o programa está pausado em um ponto de interrupção, incluindo as variáveis separadas de cada chamada em espera.
Principais conclusões
- Cada chamada empilha um novo registro; um retorno remove esse registro e retoma quem chamou.
- A chamada inacabada mais recente é executada primeiro: na pilha, o último a entrar é o primeiro a sair.
- Variáveis locais com o mesmo nome em registros diferentes são variáveis distintas.
- Acompanhe um valor retornado de volta à expressão ou atribuição que o aguarda.
- Leia um rastreamento da pilha a partir do registro do erro no topo em direção às chamadas abaixo.
- Uma cadeia que continua adicionando registros pode esgotar a pilha.
4Faça sobrecarga de métodos
Uma operação útil pode aceitar vários tipos de entrada. A sobrecarga permite que essas formas compartilhem um nome, mantendo uma lista de parâmetros distinta para cada uma. Primeiro, verifique se duas declarações realmente têm assinaturas diferentes. Depois, acompanhe a escolha do compilador em uma chamada: conte os argumentos, identifique seus tipos e compare as versões compatíveis. O tipo da variável que recebe o resultado não pode salvar uma chamada cujos argumentos não identificam uma sobrecarga adequada.
4.1 Escreva métodos sobrecarregados
A sobrecarga dá o mesmo nome a métodos com listas de parâmetros diferentes. Ela é útil quando os métodos realizam a mesma tarefa para quantidades ou tipos diferentes de entrada.
Compare assinaturas
Para esses métodos, uma assinatura consiste no nome e nos tipos dos parâmetros em ordem. A quantidade de parâmetros decorre dessa lista.
public static int max(int a, int b) {
if (a > b) {
return a;
}
return b;
}
public static int max(int a, int b, int c) {
return max(max(a, b), c);
}
public static double max(double a, double b) {
if (a > b) {
return a;
}
return b;
}
As assinaturas são max(int, int), max(int, int, int) e max(double, double). max(3, 9) retorna 9 usando a primeira. max(3, 9, 5) chama a segunda: a chamada interna com dois valores int retorna 9, depois a chamada externa com dois valores int compara 9 e 5, também retornando 9. max(2.5, 1.0) usa a versão double e retorna 2.5.
Saiba quais alterações não contam
Alterar apenas o tipo de retorno não cria uma sobrecarga. Estes cabeçalhos entram em conflito:
public static int area(int w, int h)
public static double area(int w, int h)
Ambos têm a assinatura area(int, int). Java rejeita a declaração duplicada. Renomear os parâmetros para width e height também mantém a mesma assinatura: quem chama fornece valores por posição, não pelo nome do parâmetro.
A ordem de tipos diferentes conta. describe(String s, int n) e describe(int n, String s) são assinaturas distintas. Elas compilam juntas, mas quem chama precisa lembrar uma ordem fácil de confundir, portanto use esse par apenas quando ele ajudar no projeto.
Deixe uma sobrecarga mais curta fornecer um valor padrão
Java não fornece valores padrão para parâmetros em declarações de métodos. Uma sobrecarga mais curta pode chamar uma mais longa com um argumento fixo:
public static void printLine(int length, char symbol) {
for (int i = 0; i < length; i++) {
System.out.print(symbol);
}
System.out.println();
}
public static void printLine(int length) {
printLine(length, '-');
}
printLine(5, '*'); exibe *****. printLine(4); entra no método mais curto, que chama o mais longo com 4 e '-', exibindo ----. O laço fica em um só lugar, portanto alterações na tarefa de exibição se aplicam às duas formas.
A biblioteca de Java também usa sobrecargas. System.out.println aceita um int, um double, um char, um boolean ou uma String por meio de versões diferentes. Math.abs e Math.max oferecem versões para int, long, float e double.
Mantenha um único significado para o nome compartilhado. Exibir um recibo e exibir uma etiqueta são tarefas diferentes; nomes claros como printReceipt e printLabel informam a quem chama qual tarefa será executada.
Principais conclusões
- Sobrecargas compartilham um nome e diferem na quantidade, nos tipos ou na ordem dos tipos dos parâmetros.
- Tipos de retorno e nomes de parâmetros não distinguem assinaturas.
- Uma sobrecarga mais curta pode chamar uma mais longa com um argumento padrão fixo.
- Use um nome sobrecarregado para uma tarefa com diferentes formas de entrada.
4.2 Preveja qual método sobrecarregado será executado
O compilador escolhe uma sobrecarga a partir da quantidade e dos tipos dos argumentos. Determine essa escolha antes de considerar como o valor retornado será usado.
Comece pelas correspondências exatas
Suponha que uma classe defina show(int x) e show(double x). show(5) usa a versão int porque o literal 5 é int. show(5.0) usa a versão double. Um valor inteiro escrito como 5.0 ainda é uma expressão double.
Para uma chamada com vários argumentos, compare o tipo em cada posição. Um candidato com a quantidade errada de argumentos não pode ser compatível.
Permita a conversão de ampliação quando necessário
Se existir apenas show(double x), show(5) é válido: o int é ampliado para 5.0. Os caminhos de ampliação de tipos primitivos incluem:
byte → short → int → long → float → double
char → int → long → float → double
Com show(long x) e show(double x), um argumento int escolhe long. Esse é o tipo de parâmetro compatível mais específico: um long pode ser ampliado para double, enquanto um double não pode ser ampliado de volta para long.
A ampliação é uma conversão numérica permitida; ela não garante que toda conversão desse tipo preserve todos os algarismos. Em particular, converter um long suficientemente grande em double pode arredondar seu valor. A conversão de int para double usada nos exemplos anteriores preserva exatamente todos os valores int.
Um char também tem valor numérico. Com letter(int code) e letter(String text), letter('A') chama a versão int com 65. Um caractere não se torna uma String para corresponder a um parâmetro. As aspas duplas em "A" criariam um argumento String.
Rejeite o estreitamento implícito
Se houver apenas show(int x), show(5.0) falha. Java não faz o estreitamento de um argumento double apenas porque seu valor é um número inteiro. show((int) 5.0) passa um int após uma conversão explícita.
Da mesma forma, versões de max para dois e três valores int não podem aceitar max(1). Nenhum candidato tem a quantidade necessária de parâmetros, portanto o compilador informa “no suitable method found”. Compare a lista de candidatos com os argumentos fornecidos.
Separe a escolha da sobrecarga da conversão do resultado
Considere int twice(int n) e double twice(double x). Em double d = twice(3);, o argumento seleciona a sobrecarga int. Essa chamada retorna 6, e a atribuição o amplia para 6.0. O destino d não seleciona a sobrecarga double.
Reconheça uma chamada ambígua
public static void combine(int a, double b) { }
public static void combine(double a, int b) { }
combine(1, 2) é compatível com a primeira após ampliar seu segundo argumento e com a segunda após ampliar seu primeiro. Nenhuma assinatura é mais específica nas duas posições. Java informa “reference to combine is ambiguous”; ele não escolhe a definição escrita primeiro.
combine(1, 2.0) é compatível apenas com (int, double), pois a outra assinatura precisaria de uma conversão de estreitamento de 2.0. Um tipo de argumento claro ou um conjunto melhor de sobrecargas elimina a ambiguidade.
Principais conclusões
- Escolha uma sobrecarga pela quantidade e pelos tipos dos argumentos em tempo de compilação.
- Uma correspondência exata prevalece; a ampliação pode tornar outra versão compatível.
- Java não faz estreitamento implícito de argumentos numéricos de métodos.
- A variável que recebe o resultado não escolhe a sobrecarga.
- Ambiguidade significa que várias versões são compatíveis e nenhuma é mais específica para a chamada inteira.
5Divida um programa em métodos
Os métodos de um programa devem revelar seu plano. Dê a cada método uma tarefa significativa, passe a ele os valores necessários e deixe que seu resultado alimente a etapa seguinte. Código repetido muitas vezes revela a falta de um método; um método longo muitas vezes revela várias tarefas misturadas. Planeje os cabeçalhos primeiro, construa pequenas partes com resultados conhecidos e conecte-as aos poucos. Isso facilita identificar tanto o fluxo de dados quanto o local de um novo defeito.
5.1 Atribua uma tarefa clara a cada método
Decomposição significa dividir um problema em tarefas menores e resolver cada tarefa em seu próprio método. Escolha tarefas cujos nomes ajudem alguém a entender o plano do programa.
Separe o cálculo da entrada e da saída
Um programa sobre um passeio de bicicleta precisa calcular a velocidade e apresentar um relatório. As duas tarefas usam os mesmos dados, mas têm funções diferentes:
public static double kilometersPerHour(double km, double hours) {
return km / hours;
}
public static void printRideReport(double speed) {
System.out.println("Speed: " + speed + " km/h");
}
Para um passeio de 150 km em 2 horas, o cálculo retorna 75.0. O método de relatório recebe esse valor e o exibe. Quem chama conecta as etapas:
double speed = kilometersPerHour(150, 2);
printRideReport(speed);
O método de cálculo não lê entrada do teclado nem exibe um relatório. Outro programa pode usá-lo para comparar passeios ou armazenar velocidades sem alterar seu corpo. Para testá-lo, chame-o com entradas conhecidas e compare o número retornado com o esperado.
Reconheça um método com tarefas demais
Um nome como readAndCheckAndPrint sugere várias ações. Outros indícios incluem seções marcadas por comentários, um corpo maior que uma tela e grupos de variáveis que atendem a finalidades sem relação entre si. Esses são motivos para examinar o método, não limites rígidos para a quantidade de linhas que ele pode ter.
Divida o método em um ponto que faça sentido. O código de entrada pode obter um valor, um método auxiliar com retorno booleano pode verificá-lo, um método de cálculo pode retornar um resultado e um método de relatório pode exibi-lo. Assim, main pode ser lido como uma breve descrição de como essas tarefas se conectam.
Métodos focados são mais fáceis de ler separadamente, reutilizar e testar. Se o formato de um relatório mudar, edite o método de relatório. Se um cálculo estiver errado, teste esse cálculo sem precisar digitar uma sessão inteira de entrada.
Deixe o cabeçalho explicar o fluxo de dados
Em kilometersPerHour(double km, double hours), o nome indica o resultado, os nomes dos parâmetros indicam as grandezas e o tipo de retorno double indica o tipo de resposta. Um breve comentário Javadoc pode acrescentar o significado das entradas e do resultado:
/**
* Calculates a ride's average speed.
* @param km distance in kilometers
* @param hours elapsed time in hours, greater than zero
* @return speed in kilometers per hour
*/
Coloque esse comentário diretamente acima do cabeçalho do método. Um comentário útil acrescenta informações como unidades ou um requisito para a entrada; ele não precisa narrar cada linha do corpo.
Um método auxiliar necessário apenas à sua própria classe pode ser private static. private impede que outras classes o chamem, enquanto o código da mesma classe ainda pode usá-lo. public static disponibiliza o método auxiliar para outras classes.
Separar cada instrução óbvia em seu próprio método também pode obscurecer o plano. Mantenha um método quando seu nome representar uma etapa significativa ou um cálculo reutilizável. Uma cadeia de métodos auxiliares que apenas repassam a mesma chamada acrescenta mais lugares a examinar sem explicar melhor a tarefa.
Principais conclusões
- Decomponha um programa em tarefas significativas com nomes claros.
- Métodos de cálculo recebem parâmetros e retornam resultados; métodos de relatório os exibem.
- Métodos auxiliares focados podem ser reutilizados e testados separadamente.
- Um cabeçalho e um breve comentário Javadoc podem informar entradas, unidades e resultado.
- Use
private staticpara métodos auxiliares que apenas sua própria classe deve chamar. - Divida onde um nome esclarece a tarefa, não em cada instrução individual.
5.2 Substitua código repetido por um método parametrizado
Código duplicado repete a mesma tarefa em mais de um lugar. Quando apenas os valores de entrada diferem, um método parametrizado pode manter o trabalho comum em um só lugar.
Encontre o cálculo comum
Suponha que um programa some de 1 a 10 e depois de 1 a 50:
int total1 = 0;
for (int i = 1; i <= 10; i++) {
total1 += i;
}
System.out.println("Sum 1 to 10: " + total1);
int total2 = 0;
for (int i = 1; i <= 50; i++) {
total2 += i;
}
System.out.println("Sum 1 to 50: " + total2);
Os dois laços começam em 1, adicionam valores a um total e param em um limite superior. Apenas esse limite muda. Um parâmetro n pode levá-lo a um cálculo compartilhado.
Extraia o método
public static int sumUpTo(int n) {
int total = 0;
for (int i = 1; i <= n; i++) {
total += i;
}
return total;
}
n é a entrada variável. total e i são variáveis de trabalho que pertencem ao método auxiliar. Quem chama precisa da soma final, portanto o método auxiliar retorna um int.
Substitua as duas seções repetidas:
System.out.println("Sum 1 to 10: " + sumUpTo(10));
System.out.println("Sum 1 to 50: " + sumUpTo(50));
sumUpTo(10) retorna 55, e sumUpTo(50) retorna 1275. As linhas exibidas são “Sum 1 to 10: 55” e “Sum 1 to 50: 1275”, como antes. As descrições permanecem em quem chama; o laço realiza apenas o cálculo.
Verifique a extração em uma ordem definida
- Marque as instruções que realizam a tarefa repetida.
- Identifique cada valor que difere entre as cópias.
- Transforme esses valores em parâmetros com tipos adequados e retorne qualquer resultado necessário fora do método.
- Substitua cada cópia por uma chamada usando suas entradas originais.
- Execute as mesmas entradas antes e depois e compare o comportamento.
Alterar a estrutura do código preservando seu comportamento é refatoração. Deixar uma cópia original significa que uma correção posterior ainda terá dois lugares para atualizar. Mover uma exibição para dentro de um laço ou alterar o limite final de um laço muda o comportamento, mesmo que o código fique mais curto.
Quando duas diferenças têm tipos diferentes, use parâmetros correspondentes. Repetir textos diferentes quantidades diferentes de vezes sugere printRepeated(String text, int times); a palavra é uma String e a contagem é um int.
Código com aparência semelhante nem sempre realiza a mesma tarefa. Um parâmetro booleano que alterna um método entre cálculos sem relação entre si pode dificultar a interpretação das chamadas. Dê nomes diferentes a tarefas diferentes. Extraia a operação repetida apenas quando variar suas entradas preservar um significado claro.
Principais conclusões
- Identifique a tarefa comum e transforme suas entradas variáveis em parâmetros.
- Mantenha as variáveis de trabalho locais e retorne qualquer resultado necessário a quem chama.
- Refatore cada cópia e compare o comportamento com as mesmas entradas.
- Una cópias da mesma tarefa, não tarefas diferentes que apenas parecem semelhantes.
5.3 Projete um programa de forma descendente e teste cada método
O projeto descendente começa pela tarefa completa e a refina em chamadas de métodos menores. Decida o que cada chamada precisa e retorna antes de preencher todos os detalhes.
Planeje as etapas e os cabeçalhos
Um programa semanal de exercícios lê 7 durações diárias, soma-as e exibe um relatório. Seus métodos auxiliares podem ser planejados assim:
readMinutes(Scanner scanner, int day)retorna os minutos válidos de um dia.isValidMinutes(int minutes)responde se a entrada está entre 0 e 1440.formatDuration(int minutes)retorna texto com horas inteiras e minutos restantes.averagePerDay(int total, int days)retorna uma média double.printSummary(int totalMinutes, int days)exibe o relatório.
O mesmo Scanner é passado a cada chamada de entrada. Um método auxiliar como isValidMinutes não precisa ler a entrada por conta própria.
Use métodos provisórios durante o desenvolvimento
Um método provisório tem seu cabeçalho definitivo, mas um corpo mínimo temporário, como return 0;. Ele permite que o programa compile antes de o método auxiliar ser implementado. Substitua um método provisório, compile e verifique esse método antes de substituir o próximo. Um método provisório que compila ainda é trabalho inacabado; sua resposta fixa não pode verificar um cálculo real.
Veja o programa concluído:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int total = 0;
for (int day = 1; day <= 7; day++) {
total += readMinutes(scanner, day);
}
printSummary(total, 7);
}
public static int readMinutes(Scanner scanner, int day) {
System.out.println("Minutes for day " + day + ":");
int minutes = scanner.nextInt();
while (!isValidMinutes(minutes)) {
System.out.println("Enter minutes from 0 to 1440:");
minutes = scanner.nextInt();
}
return minutes;
}
public static boolean isValidMinutes(int minutes) {
return minutes >= 0 && minutes <= 1440;
}
public static String formatDuration(int minutes) {
return minutes / 60 + " h " + minutes % 60 + " min";
}
public static double averagePerDay(int total, int days) {
return (double) total / days;
}
public static void printSummary(int totalMinutes, int days) {
System.out.println("Total: " + formatDuration(totalMinutes));
System.out.println("Daily average: "
+ averagePerDay(totalMinutes, days) + " min");
if (totalMinutes >= 150) {
System.out.println("Weekly goal reached");
}
}
}
Para uma entrada inteira, readMinutes repete a verificação do intervalo até que o número seja válido. Com as entradas diárias 30, 45, 0, 60, 90, 45 e 45, o total é 315. A formatação produz “5 h 15 min”, a média é 45.0 minutos e o programa informa que sua meta semanal de 150 minutos foi atingida.
Verifique métodos pequenos e seus valores-limite
Chame cada método de cálculo com resultados conhecidos. formatDuration(0) deve resultar em “0 h 0 min”, 59 resulta em “0 h 59 min”, 60 resulta em “1 h 0 min” e 135 resulta em “2 h 15 min”. As entradas imediatamente abaixo de 60 e no próprio limite verificam a mudança de minutos para uma hora inteira.
Para isValidMinutes, teste -1, 0, 1440 e 1441. Os resultados esperados são false, true, true e false. Exibir os valores esperado e obtido lado a lado torna um erro visível. JUnit automatiza esse tipo de verificação.
O desenvolvimento ascendente começa pela escrita e pelo teste de pequenos métodos auxiliares e depois os une em etapas maiores. Você pode planejar de forma descendente e construir de forma ascendente: defina primeiro o fluxo de dados, comprove que os pequenos cálculos funcionam e depois verifique o programa integrado.
Principais conclusões
- O projeto descendente transforma uma tarefa completa em chamadas e depois refina cada tarefa.
- Decida as entradas e o tipo de retorno de cada método auxiliar antes de seu corpo.
- Um método provisório preserva um cabeçalho planejado enquanto seu corpo ainda é temporário.
- Teste resultados conhecidos e valores nos limites ou próximos deles.
- Construa e verifique um método de cada vez e depois teste o programa integrado.
- O desenvolvimento ascendente constrói pequenos métodos auxiliares antes de combiná-los.
Exercícios resolvidos de Métodos em Java
1Construa um método reutilizável para exibir linhas
11 passos
- 1IntroduçãoTransforme uma ação repetida em uma chamada
Um relatório precisa de um separador curto em vários lugares. Dar um nome de método a essa ação permite que o relatório solicite um separador sem repetir as instruções de exibição. Essa ação nomeada é um método, e uma definição atende a todas as chamadas.
Comece com um separador fixo. Depois permita que quem chama escolha sua largura e seu símbolo com parâmetros. Acompanhe a definição, a chamada e os valores fornecidos como três partes diferentes da tarefa.
- 2ExplicaçãoLeia o cabeçalho de um método
public static void printDivider() { System.out.println("===="); }printDivideré o nome.publicpermite chamadas de outras classes;staticsignifica que não é necessário um objeto.voidindica que nenhum valor é devolvido, e()indica que nenhuma entrada é necessária.A instrução dentro das chaves é o corpo. Nada é exibido apenas porque essa definição existe.
- 3DicaColoque o método auxiliar ao lado de main
Em uma classe clássica,
maineprintDividersão métodos separados dentro das mesmas chaves da classe. Feche o corpo demainantes de iniciar o cabeçalho do método auxiliar.Um método auxiliar pode aparecer acima ou abaixo de
main; sua posição não determina quando ele é executado. Uma definição colocada dentro demainé rejeitada. Verifique primeiro as chaves quando um cabeçalho de método produzir “illegal start of expression”. - 4ExemploAcompanhe a primeira chamada
Suponha que
maincontenha:System.out.println("Items"); printDivider(); System.out.println("End");A execução primeiro exibe “Items”. A chamada entra em
printDivider, que exibe “====”. Quando o método auxiliar termina,maincontinua em sua próxima instrução e exibe “End”.O corpo do método auxiliar é executado entre as duas instruções de quem chamou, exatamente onde a chamada aparece.
- 5DesafioColoque um segundo separador
mainchamaprintDivider();, exibe"A"e chamaprintDivider();novamente. Quais três linhas aparecem?---reveal---
As linhas são “====”, “A” e “====”. Cada chamada entra no mesmo corpo do método auxiliar, exibe uma vez e retorna ao seu próprio ponto em
main.Escrever
printDivider;não faria uma chamada. Mesmo sem argumentos, os parênteses são obrigatórios. - 6ExplicaçãoUse a largura como entrada
Substitua o corpo fixo por um laço:
public static void printDivider(int length) { for (int i = 0; i < length; i++) { System.out.print("="); } System.out.println(); }lengthé um parâmetro declarado no cabeçalho. EmprintDivider(6);, o argumento6se torna seu valor inicial. Seis passagens pelo laço exibem seis símbolos antes de a linha terminar. - 7ExemploAvalie uma expressão antes da chamada
int sections = 3; printDivider(sections + 2);Primeiro, avalie
sections + 2para obter5. Depois entre no método auxiliar com seu parâmetrolength = 5. Seu laço exibe “=====” .sectionselengthnão precisam ter o mesmo nome. Um parâmetro recebe o valor avaliado do argumento; quem chama não coloca o tipo na chamada. - 8ExemploAdicione uma segunda entrada variável
Para escolher também o símbolo, use:
public static void printDivider(int length, char symbol) { for (int i = 0; i < length; i++) { System.out.print(symbol); } System.out.println(); }A chamada
printDivider(3, '+');passa3paralengthe'+'parasymbol, exibindo “+++”. Cada parâmetro precisa de seu próprio tipo no cabeçalho. - 9DicaVerifique a quantidade, a ordem e o tipo
Uma chamada deve fornecer um valor compatível para cada parâmetro. Agora falta o símbolo em
printDivider(3);, enquantoprintDivider("3", '+');fornece texto onde é necessário um int.Java pode ampliar um int para double para um parâmetro double. Ele não pode estreitar implicitamente
3.7para adequá-lo a esse parâmetro int. A conversão explícita(int) 3.7fornece3ao descartar a parte fracionária. - 10DesafioPreveja uma chamada com parâmetros
Usando o método auxiliar com dois parâmetros, qual linha isto exibe?
int width = 4; printDivider(width - 1, '#');---reveal---
Ele exibe “###”. A expressão é avaliada como
3, depois o primeiro parâmetro recebe essa contagem e o segundo recebe'#'. O laço é executado três vezes.A chamada é uma instrução, portanto termina com ponto e vírgula. Suas expressões de argumento contêm valores, não declarações de parâmetros.
- 11RecapitulaçãoLeia a ação e suas entradas
Uma definição dá a uma tarefa um cabeçalho e um corpo; uma chamada a executa e depois retoma quem chamou. Mantenha as definições dentro da classe e fora de outros métodos.
Os parâmetros descrevem as entradas necessárias. As chamadas fornecem argumentos avaliados na ordem correspondente, com a quantidade correta e tipos compatíveis.
2Retorne respostas e conclua buscas
13 passos
Salve esta aula para seguir cada Lição Interativa passo a passo.
- 1IntroduçãoDevolva um resultado a quem chamou
- 2ExplicaçãoFaça uma chamada representar um valor
- 3Ideia-chaveUma exibição não pode fornecer valor a uma atribuição
- 4ExemploMantenha a parte fracionária
- 5DesafioUse o resultado em outra expressão
- 6ExemploRetorne texto formatado
- 7ExplicaçãoUm return encerra esta chamada
- 8DicaVerifique o caminho que não entra no if
- 9ExemploEscreva uma busca com um resultado de falha
- 10ExemploRastreie a busca até seu término
- 11DesafioEncontre uma falha prematura
- 12DesafioConecte um resultado de busca a uma condição
- 13RecapitulaçãoAcompanhe a resposta e o ponto de parada
3Mantenha separadas as variáveis de cada chamada
15 passos
Salve esta aula para seguir cada Lição Interativa passo a passo.
- 1IntroduçãoIdentifique cada variável por sua chamada
- 2ExplicaçãoUm método auxiliar vê suas próprias variáveis locais
- 3ExemploMantenha um total fora do laço
- 4DesafioSepare escopo de inicialização
- 5ExemploCopie um número para um parâmetro
- 6ExemploAtribua o novo valor retornado
- 7DesafioPreveja uma segunda chamada
- 8ConexãoReferências copiadas seguem a mesma regra
- 9ExemploInicie um cálculo externo
- 10ExemploPause quem chamou e empilhe outro registro
- 11ExemploLeve os resultados de volta pela pilha
- 12DicaInterprete um erro a partir do registro superior
- 13DesafioEncontre o trabalho em espera
- 14DesafioConecte cópias aos resultados da pilha
- 15RecapitulaçãoMantenha nomes, valores e registros distintos
4Escolha o método sobrecarregado adequado
12 passos
Salve esta aula para seguir cada Lição Interativa passo a passo.
- 1IntroduçãoUma tarefa, várias formas de entrada
- 2ExplicaçãoIdentifique uma assinatura
- 3Ideia-chaveUm tipo de retorno não pode criar uma sobrecarga
- 4ExemploDelegue à versão completa
- 5DesafioVerifique uma terceira declaração proposta
- 6ExplicaçãoEscolha uma correspondência numérica exata
- 7ExemploUse ampliação sem estreitamento
- 8ExemploSepare a chamada de sua atribuição
- 9ExemploCompare cada posição dos argumentos
- 10DicaUse a lista de candidatos para diagnosticar uma chamada
- 11DesafioEscolha uma versão e depois use seu resultado
- 12RecapitulaçãoVerifique as definições antes das chamadas
5Construa um pequeno relatório com métodos auxiliares testados
16 passos
Salve esta aula para seguir cada Lição Interativa passo a passo.
- 1IntroduçãoTransforme um relatório em pequenas tarefas
- 2ExplicaçãoNomeie a tarefa antes de escrever o corpo
- 3ExemploTorne o cálculo reutilizável
- 4ExemploDê à saída seu próprio método
- 5DesafioReutilize um cálculo sem relatório
- 6ExplicaçãoDescubra o que muda no código repetido
- 7ExemploEscolha o cabeçalho extraído
- 8ExemploColoque o laço compartilhado em um só lugar
- 9DesafioPreserve a última repetição
- 10ExplicaçãoPlaneje o programa de cima para baixo
- 11DicaUse um método provisório apenas durante o desenvolvimento
- 12ExemploPasse o mesmo leitor de entrada
- 13ExemploVerifique o cálculo antes de conectá-lo
- 14ExemploVerifique uma sequência de entradas no programa integrado
- 15DesafioLocalize um erro de conexão
- 16RecapitulaçãoConstrua partes significativas e conecte-as
Questões de Métodos em Java
Conjunto 1: Rastreie métodos auxiliares e corrija os limites entre métodos10 Questões de Prática
Questão 1 de 10
Estas sobrecargas estão na mesma classe. Qual valor é armazenado em answer?
public static int adjust(int n) { return n + 1; }
public static double adjust(double n) { return n + 0.5; }
double answer = adjust(6);
Mostrar respostaOcultar resposta
6 é um int, portanto a sobrecarga int retorna 7. A atribuição então amplia esse resultado para 7.0. O destino double não seleciona a sobrecarga double; 6.5 seria o resultado de passar um argumento double como 6.0.Questão 2 de 10
Qual sequência de linhas é exibida?
public static void frame() {
System.out.println("Open");
mark();
System.out.println("Close");
}
public static void mark() {
System.out.println("Mark");
}
main chama frame(); e depois exibe "Done".
Mostrar respostaOcultar resposta
frame exibe “Open”, pausa para executar mark e depois retoma a execução para exibir “Close”. Somente após o término de frame, main exibe “Done”. A chamada de mark é executada onde aparece no corpo; ela não é adiada até o fim de frame.Questão 3 de 10
public static void repeat(int count). Qual valor chega a count em repeat((int) 3.9 + 2);?Mostrar respostaOcultar resposta
3.9, produzindo o int 3. Java então adiciona 2, resultando no valor de argumento 5 antes de entrar em repeat. A conversão trunca a parte fracionária positiva; ela não arredonda 3.9 para 4, o que produziria 6.Questão 4 de 10
Qual valor é atribuído a result?
public static int addTwo(int n) {
return n + 2;
}
public static int product(int a, int b) {
return a * b;
}
int result = product(addTwo(4), addTwo(addTwo(1)));
Mostrar respostaOcultar resposta
6. Para o segundo, addTwo(1) retorna 3, depois a chamada externa addTwo(3) retorna 5; portanto, product(6, 5) retorna 30. Multiplicar 6 por 3 ignoraria a chamada externa em torno do segundo argumento.Questão 5 de 10
O método deve retornar o primeiro valor par em um intervalo inclusivo, ou -1 se nenhum existir. Ele retorna -1 incorretamente para (9, 12). Qual alteração corrige a busca?
public static int firstEven(int start, int end) {
for (int n = start; n <= end; n++) {
if (n % 2 == 0) {
return n;
} else {
return -1;
}
}
return -1;
}
Mostrar respostaOcultar resposta
9, é ímpar, mas isso não é motivo para encerrar a busca: 10 é uma correspondência posterior. Remover o ramo else permite que o laço continue. Retornar n + 1 pareceria corrigir essa entrada, mas poderia retornar um valor fora de um intervalo que contém apenas um número ímpar.Questão 6 de 10
pages de main. Como os dados devem chegar ao método auxiliar?Mostrar respostaOcultar resposta
main. Dê a ele um parâmetro e passe o valor ao chamá-lo. Fazer a chamada enquanto pages está no escopo disponibiliza o argumento em main, mas não faz o corpo do método auxiliar compartilhar esse escopo.Questão 7 de 10
Qual valor retorna a main a partir de outer(4)?
public static int outer(int n) {
int saved = n;
int changed = inner(n + 1);
return saved + changed;
}
public static int inner(int n) {
n *= 2;
return n - 1;
}
Mostrar respostaOcultar resposta
outer mantém saved = 4 e chama inner(5). O registro interno dobra seu próprio n para 10 e retorna 9, portanto o registro externo que aguardava calcula 4 + 9 = 13. Usar o n interno como se ele substituísse saved misturaria variáveis de registros separados.Questão 8 de 10
printBorder(int length, char symbol), com dois argumentos, já contém o laço de exibição. Como printBorder(int length) deve fornecer '#' como padrão sem duplicar o laço?Mostrar respostaOcultar resposta
Questão 9 de 10
8 * 3 e outro usando 11 * 4. Ambos os resultados são necessários para comparações posteriores. Qual cabeçalho de método auxiliar é adequado para extrair esse cálculo compartilhado?Mostrar respostaOcultar resposta
Questão 10 de 10
public static int countItems(int limit) { return 0; } um método provisório útil?Mostrar respostaOcultar resposta
Conjunto 2: Chamadas, valores e pequenas etapas de um programa10 Questões de Prática
Salve esta aula para ver todas as respostas e praticar cada conjunto.
Questão 1 de 10
main e precisa de um novo método printMenu. Onde a nova definição deve ficar?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 2 de 10
Qual linha esta chamada exibe?
public static void showPair(int rows, int columns) {
System.out.println(rows + ":" + columns);
}
int width = 7;
showPair(3, width - 2);
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 3 de 10
Qual valor halfTotal(8, 5) retorna?
public static double halfTotal(int a, int b) {
return (a + b) / 2;
}
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 4 de 10
Por que este método não compila?
public static String label(int n) {
if (n >= 0) {
return "ready";
}
}
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 5 de 10
Um laço deve somar os inteiros de 2 a 4 e depois exibir o total. Qual declaração deve substituir o comentário?
// declaration here
for (int i = 2; i <= 4; i++) {
total += i;
}
System.out.println(total);
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 6 de 10
Quais dois números são exibidos, em ordem?
public static void lower(int level) {
level -= 3;
System.out.println(level);
}
int level = 14;
lower(level);
System.out.println(level);
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 7 de 10
public static int scale(int value). Qual cabeçalho adicional entraria em conflito com sua assinatura?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 8 de 10
show(int n) e show(double n). Qual método é executado para show(12.0)?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 9 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 10 de 10
Um programa deve aceitar durações de tarefas de 0 a 90 minutos e informar sua média. Atualmente, ele usa estes métodos auxiliares. Quais duas chamadas com entradas podem revelar os dois defeitos independentes?
public static boolean valid(int m) {
return m > 0 && m <= 90;
}
public static double mean(int total, int count) {
return total / count;
}
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Conjunto 3: Conecte argumentos, caminhos de retorno e projeto10 Questões de Prática
Salve esta aula para ver todas as respostas e praticar cada conjunto.
Questão 1 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 2 de 10
Uma pessoa programadora escreve isto dentro de uma classe. Por que a definição do método auxiliar é rejeitada?
public static void main(String[] args) {
public static void printTitle() {
System.out.println("Schedule");
}
}
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 3 de 10
O método retorna a quantidade de grupos inteiros. O que groups(5, 18) retorna?
public static int groups(int groupSize, int items) {
return items / groupSize;
}
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 4 de 10
Um método auxiliar de calendário é escrito como abaixo. Qual par de resultados é retornado por leap(2100) e depois por leap(2400)?
public static boolean leap(int year) {
return (year % 4 == 0 && year % 100 != 0)
|| year % 400 == 0;
}
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 5 de 10
Qual texto é exibido por quem chama?
public static void tag(String name) {
name = name + "-checked";
}
String label = "parcel";
tag(label);
System.out.println(label);
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 6 de 10
Um relatório de erro começa com ArithmeticException: / by zero e estes registros. Onde ocorreu a divisão que falhou?
at Main.unitCount(Main.java:23)
at Main.printLoad(Main.java:15)
at Main.main(Main.java:5)
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 7 de 10
public static void describe(String name, int count). Qual cabeçalho adiciona uma sobrecarga válida alterando a ordem dos tipos dos parâmetros?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 8 de 10
Qual linha é exibida por esta chamada? O caractere 'B' tem valor numérico 66.
public static int code(int n) { return n + 1; }
public static String code(String s) { return s + "!"; }
double result = code('B');
System.out.println(result);
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 9 de 10
O programa original exibe os totais 20 e 30, nessa ordem. Após a extração, ele usa este método auxiliar. Como as duas chamadas devem ser escritas para preservar esses totais?
public static int sumMultiples(int factor, int count) {
int total = 0;
for (int i = 1; i <= count; i++) {
total += factor * i;
}
return total;
}
O primeiro laço original somava 2, 4, 6 e 8. O segundo somava 5, 10 e 15.
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 10 de 10
Um programa lê cinco contagens diárias, soma-as e exibe uma média. Os cabeçalhos planejados dos métodos auxiliares estão abaixo. Qual conexão em main permite que a etapa de relatório receba todos os dados necessários?
public static int readCount(Scanner scanner, int day)
public static double average(int total, int days)
public static void printReport(int total, int days)
O Scanner já foi criado.
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Conjunto 4: Diagnostique interações completas entre métodos10 Questões de Prática
Salve esta aula para ver todas as respostas e praticar cada conjunto.
Questão 1 de 10
Qual linha é exibida?
public static int next(int n) { return n + 1; }
public static double half(int n) { return n / 2.0; }
int n = 5;
next(n);
double result = half(next(n)) + n;
System.out.println(result);
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 2 de 10
Qual valor locate(5) retorna?
public static int locate(int limit) {
int total = 0;
for (int n = 1; n <= limit; n++) {
total += n;
if (total > 8) {
return n;
}
}
return -1;
}
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 3 de 10
O código deve totalizar os pesos e exibir sua soma após o laço. Atualmente, ele não compila. Qual alteração corrige o problema de escopo e preserva uma soma acumulada?
for (int box = 1; box <= 3; box++) {
int total = 0;
total += box * 2;
}
System.out.println(total);
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 4 de 10
Qual par de valores é exibido como a:b?
public static int shift(int n) {
n += 4;
return n;
}
int a = 2;
int b = shift(a);
a = shift(b);
System.out.println(a + ":" + b);
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 5 de 10
No ponto marcado, quais são os valores das duas variáveis locais chamadas saved, lendo primeiro o registro externo e depois o interno?
public static int outer(int n) {
int saved = n + 2;
return inner(saved) + saved;
}
public static int inner(int n) {
int saved = n * 3;
// program pauses here
return saved;
}
main chamou outer(5).
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 6 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 7 de 10
Os métodos abaixo estão declarados em uma classe. O que acontece em double result = merge(4, 9);?
public static int merge(int a, double b) { return a; }
public static double merge(double a, int b) { return b; }
public static double merge(double a, double b) { return a + b; }
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 8 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 9 de 10
"Crate" com itens numerados de 1 a 2; o segundo exibe "Bag" com itens numerados de 1 a 4. Qual corpo extraído preserva esse formato para printItems(String label, int count)?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 10 de 10
Um método auxiliar deve retornar uma média diária decimal:
public static double dailyAverage(int total, int days) {
return total / days;
}
Por que verificar apenas (24, 6) não revela seu defeito aritmético?
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Travou em uma questão sua? Ajuda com Tarefas
Termos-Chave
A
Acumulador
sum antes de um laço para que cada iteração adicione ao total mantido da passagem anterior.Argumento
printRepeated("go", 4), os argumentos fornecem o texto e a quantidade de repetições.Assinatura do método
width para w deixa area(int, int) inalterada e não pode criar uma nova sobrecarga.B
Bloco
C
Cabeçalho do método
public static void greet() descreve uma ação que pode ser chamada sem entrada e sem valor de retorno.Caso de valor-limite
-1, 0, 1440 e 1441 como entradas separadas.Chamada ambígua
(int, double) e (double, int) tornam ambígua uma chamada com dois argumentos int.Chamada aninhada
Math.max(sum(2, 6), 5), o resultado 8 se torna o primeiro argumento de Math.max.Chamada de método
printHeader(); executa o método que exibe o cabeçalho naquele ponto de quem chamou.Código duplicado
Conversão de ampliação
12 para um parâmetro double fornece a ele 12.0 sem exigir conversão explícita.Conversão de estreitamento
9.0 para um parâmetro int falha sem uma conversão explícita, mesmo que o valor não tenha parte fracionária.Conversão explícita de tipo
(int) 4.9 fornece 4 a um parâmetro int ao descartar a parte fracionária.Corpo do método
Correspondência exata
show(int) e show(double), show(9) tem uma correspondência exata com a versão int.D
Decomposição
Desenvolvimento ascendente
Desenvolvimento incremental
E
Escopo
Estouro de pilha
StackOverflowError.Extração de método
sumUpTo(int n) deixa quem chama responsável pelo próprio texto do relatório.I
Inicialização
int total = 0; antes de um laço de soma dá à primeira adição um total existente para atualizar.Instrução inalcançável
Instrução return
return minutes * 60; encerra o cálculo e fornece a quantidade de segundos.J
Javadoc
/** ... */ acima de uma declaração, com marcações que descrevem parâmetros e resultados.@param minutes para explicar uma entrada e @return para descrever o texto formatado que ela produz.L
Lista de parâmetros
(int width, int height) exige dois argumentos, associados primeiro a width e depois a height.M
Método
printHeader() pode exibir o mesmo título de relatório em vários lugares de um programa.Método auxiliar
Método com retorno booleano
true ou false, geralmente para responder a uma pergunta que quem chama usa diretamente como condição.isEven(count) pode ser colocada diretamente entre os parênteses de uma instrução if.Método estático
Math.abs(-6) usa o nome da classe Math e retorna o valor positivo 6.Método privado
private static permite que sua própria classe o use sem disponibilizar uma chamada externa.Método provisório
return 0; temporário pode servir de substituto enquanto o cálculo real é implementado e verificado.P
Parâmetro
printRepeated(String text, int times), text e times são os dois parâmetros declarados.Passagem por valor
Pilha de chamadas
main chama um método auxiliar que chama outro método auxiliar, três registros podem estar na pilha ao mesmo tempo.Projeto descendente
main antes de preencher os corpos de seus métodos auxiliares.R
Rastreamento da pilha
Refatoração
Referência
Registro de ativação
minutes porque os parâmetros ocupam registros separados.Resolução de sobrecarga
Retorno antecipado
return candidate; é executado, mesmo que o laço tenha mais candidatos.S
Sobrecarga
max podem aceitar dois valores int e três valores int, mantendo um único significado para o nome.Sobrecarga com delegação
String imutável
"!" e atribuir o resultado a um parâmetro String deixa inalterada a referência de quem chamou.T
Tipo de retorno
void declara que ele não fornece valor.double average(int a, int b) promete um resultado double a quem o chama.Ú
Último a entrar, primeiro a sair
V
Valor de retorno
int total = sum(6, 8);, o 14 retornado é armazenado na variável total de quem chamou.Valor sentinela
-1 após uma busca pode sinalizar “não encontrado” quando -1 não pode ser uma correspondência válida.Variável local
total local em um método auxiliar é separado da variável local de outro método também chamada total.void
printTotal não pode preencher o lado direito de uma atribuição int apenas porque exibe um número.- 1Primeiros programas em Java
- 2Condições e laços em Java
- 3Métodos em Java
- 4Listas e vetores em Java
- 5Classes e objetos em Java
- 6Objetos e referências em Java
- 7HashMaps e coleções em Java
- 8Herança, interfaces e polimorfismo em Java
- 9Exceções em Java
- 10Pacotes e testes unitários em Java
- 11Genéricos e expressões lambda em Java
Sobre esta aula
Crie seus próprios Materiais de Estudo
Transforme suas anotações, slides e documentos em Guias de Estudo, Questões de Prática, Flashcards e mais 6 ferramentas.