Assinatura, resultado e contrato
Um método associa um nome e parâmetros a um comportamento. Na versão simples sem generics, a assinatura distingue o nome e os tipos dos parâmetros, incluindo a ordem. Mudar apenas o nome de um parâmetro ou o tipo devolvido não cria um overload diferente. Se já existe int load(String key), declarar também long load(String key) na mesma classe é um conflito. Um nome como loadLong pode tornar a escolha explícita, acompanhado da regra de conversão e dos limites.
O tipo devolvido obriga a fornecer um resultado quando o método termina normalmente por return. Um método int que só faz if (enabled) return 8; e pode chegar ao fim com enabled false não compila. Acrescentar return 0 resolve o caminho sintático, mas só é uma solução correta se zero for o resultado definido pelo contrato. Uma falha ou uma ausência pode precisar de outra representação, que não deve ser inventada apenas para satisfazer o compilador.
Overload: escolher pela expressão de chamada
Se label(Object) e label(String) coexistem, a chamada com Object value = "ready" seleciona label(Object). O compilador usa o tipo da expressão value; não escolhe novamente o overload quando descobre o conteúdo do objeto. A situação é diferente se o próprio argumento tiver tipo String.
A resolução tem fases. Primeiro procura uma chamada aplicável sem boxing, unboxing ou invocação de aridade variável. Se route(long) já é aplicável a um literal int, essa escolha é feita antes da fase que admitiria route(Integer) por boxing. Não se trata de adivinhar qual tipo parece mais próximo do valor.
null pode ser compatível com vários tipos de referência. Entre send(String) e send(Integer), send(null) é ambígua: nenhum dos dois tipos é mais específico que o outro. send((String) null) seleciona String e continua a passar null. O cast escolhe o contrato; não prova que o método aceite ausência. Nos exercícios que usam essa chamada, a aceitação de null é explícita.
Override: executar a implementação do objeto
Um método de instância pode ser redefinido numa subclasse através de override. Considera Base.label(Object), redefinido em Child, que também acrescenta label(String). Com Base b = new Child(); Object x = "ready";, b.label(x) seleciona a assinatura label(Object) na compilação. A implementação executada é Child.label(Object), porque o objeto é Child. O overload String não é reconsiderado.
Esta distinção é útil quando uma chamada passa por uma interface ou tipo base: o contrato visível ao chamador escolhe a operação; o objeto fornece a implementação aplicável dessa operação. Uma revisão deve perguntar quais entradas, resultados e efeitos o contrato promete. A existência de um override não verifica automaticamente essas promessas de negócio. Herança e interfaces serão desenvolvidas no módulo seguinte; aqui basta manter separados a escolha da assinatura e o despacho do método de instância.
Ciclos: valores, progresso e saída
Em for (int amount : amounts), amount recebe o valor de um elemento em cada iteração. Atribuir amount *= 2 não escreve no array de int. Para modificar elementos primitivos, escreve nas posições do array. Se os elementos forem referências para objetos mutáveis, alterar o objeto referido é uma operação diferente de reatribuir a variável de iteração.
continue termina a iteração atual e procura a seguinte. Num for básico, a atualização do cabeçalho é feita antes da próxima condição. Num while cujo i++ está depois de uma guarda com continue, esse incremento pode ser ignorado. Se a[0] é negativo e a guarda faz continue antes de avançar i, o mesmo elemento é analisado indefinidamente. Uma substituição por for (int i = 0; i < a.length; i++) deve substituir também a declaração local anterior de i.
break sem etiqueta sai apenas do ciclo ou switch envolvente mais próximo. return sai do método. Nenhum destes comandos desfaz alterações anteriores. Ao seguir um excerto, regista o índice, o estado acumulado e a próxima instrução; não confundas "saltar esta entrada" com "terminar todo o processamento".
switch para escolher um resultado
Uma expressão switch fornece um valor que pode ser atribuído. Por exemplo, int n = switch (mode) { case 1 -> 10; default -> 20; }; produz 10 para mode igual a 1 e 20 para os restantes int. Uma regra com seta executa apenas a alternativa escolhida; não continua automaticamente na regra seguinte.
Se uma regra precisa de um bloco, yield fornece o resultado desse bloco à expressão switch: case 1 -> { yield 10; }. Um literal isolado dentro do bloco não constitui uma instrução válida, e break 10 não é a sintaxe de resultado em Java SE 25. Não confundas yield com return do método.
No switch tradicional com etiquetas terminadas por dois pontos, a execução pode continuar nas instruções após etiquetas seguintes se não houver uma saída. Ao converter uma tabela de decisões, confirma quais casos partilham resultado e quais tinham fall-through intencional. Para esta aula, os seletores são int; regras adicionais de padrões e referências não são pressupostas.
Aplicação guiada: validar antes dos efeitos
Um método recebe quantidades 4, 7 e -1. Todas têm de estar entre 1 e 100; se alguma for inválida, nenhuma chamada apply pode ocorrer. Validar e aplicar no mesmo ciclo permite aplicar 4 e 7 antes de descobrir -1. Devolver false nesse momento informa o erro, mas não desfaz o que aconteceu.
Neste cenário, o array não muda durante a chamada, a validação não tem efeitos e apply termina sem falhas. Faz uma primeira passagem que apenas valida; se todos os elementos forem válidos, faz uma segunda passagem para aplicar. O excerto abaixo soma as quantidades em vez de as aplicar, para permitir comparar o resultado por leitura. A coleção é limitada a 1 000 elementos, pelo que a soma máxima de 100 000 cabe em int.
Se houver concorrência ou falhas de escrita, a primeira passagem não fornece atomicidade. Seria necessário definir um snapshot ou uma fronteira transacional apropriada. A conclusão deste caso limita-se à rejeição de entradas inválidas antes de iniciar efeitos sob as premissas declaradas.
Decisão: primeira correspondência e resumo obrigatório
Um método pesquisa grupos e, dentro de cada grupo, itens. O objetivo é registar apenas a primeira correspondência global e publicar um resumo depois da pesquisa, mesmo quando não encontra nenhuma. Um break no ciclo interior permite avançar para o grupo seguinte e encontrar outra correspondência. Um return após o registo sai do método e omite o resumo que está a seguir aos ciclos.
Uma etiqueta search no ciclo exterior permite break search após o primeiro registo. O controlo continua na instrução após os ciclos, onde está publishSummary. Uma alternativa de desenho é extrair a pesquisa para um método que devolva o resultado e manter o resumo no chamador. Em ambos os desenhos, segue os caminhos com e sem correspondência. O exercício assume ciclos finitos, ausência de finally e chamadas sem exceções; tratamento de falhas e recursos será estudado separadamente.
static int acceptedTotal(int[] quantities) {
java.util.Objects.requireNonNull(quantities);
if (quantities.length > 1_000) {
throw new IllegalArgumentException("batch too large");
}
for (int quantity : quantities) {
if (quantity < 1 || quantity > 100) {
throw new IllegalArgumentException("quantity outside range");
}
}
int total = 0;
for (int quantity : quantities) total += quantity;
return total;
}Método a ler dentro de uma classe, assumindo que o array não muda durante a chamada. {4, 7} devolve 11; {4, 7, -1} lança antes do ciclo de soma. Um array vazio devolve 0. O limite de tamanho e a regra por elemento justificam a capacidade de int.
Armadilhas comuns
Escolher overload pelo objeto real; usar o tipo devolvido para distinguir assinaturas; esquecer o avanço num continue; tratar break como saída de todos os ciclos; omitir trabalho obrigatório através de return.
Tópicos relacionados: Tipos, conversões e validação · Objetos, interfaces e records · Exceções, recursos e ficheiros · Streams, lambdas e ausência
Escolhe a assinatura pelos tipos da chamada, acompanha o despacho e segue cada caminho até ao resultado e aos efeitos. A saída do fluxo não é um rollback.
Referência: JLS 25: Method invocation · Java SE 25; no preview features