Um método é um conjunto de comandos que permite realizar uma operação específica em um programa. Em outras palavras, um método é uma função; algo que sua classe é capaz de fazer.
Em outras linguagens de programação, os métodos costumam ser chamados de “funções”, mas em Java a palavra “método” é mais comum. 🙂
Se você se lembra, na última lição criamos métodos simples para uma Cat
classe, de modo que nossos gatos pudessem dizer miau e pular:
public class Cat {
String name;
int age;
public void sayMeow() {
System.out.println("Meow!");
}
public void jump() {
System.out.println("Pounce!");
}
public static void main(String[] args) {
Cat smudge = new Cat();
smudge.age = 3;
smudge.name = "Smudge";
smudge.sayMeow();
smudge.jump();
}
}
sayMeow()
e jump()
são métodos de nossa classe.
E a execução desses métodos resulta na seguinte saída do console:
Meow!
Pounce!
Nossos métodos são bastante simples: eles simplesmente emitem texto para o console.
Mas em Java, os métodos têm uma tarefa importante: eles executam ações nos dados de um objeto. Eles alteram os dados do objeto, transformam-no, exibem-no e fazem outras coisas com ele.
Nossos métodos atuais não fazem nada com os Cat
dados do objeto. Vejamos um exemplo mais ilustrativo:
public class Truck {
int length;
int width;
int height;
int weight;
public int getVolume() {
int volume = length width height;
return volume;
}
}
Por exemplo, aqui temos uma classe que representa a Truck
.
O semi-caminhão tem comprimento, largura, altura e peso (dos quais precisaremos mais tarde). No método, fazemos cálculos, convertendo os dados de nosso objeto em um número que representa seu volume (multiplicamos o comprimento, a largura e a altura).getVolume()
Este número será o resultado do método.
Observe que a declaração do método é escrita como . Isso significa que esse método deve retornar um .public int getVolume
int
Calculamos o valor de retorno do método e agora devemos retorná-lo ao programa que chamou nosso método.
Para retornar o resultado de um método em Java, usamos a palavra-chave return.
return volume;
Parâmetros do método
Podemos passar valores chamados “argumentos” para um método ao chamá-lo. A declaração de um método inclui uma lista de variáveis que nos dizem o tipo e a ordem das variáveis que o método pode aceitar. Essa lista é chamada de “parâmetros do método”.
Truck
O método de nossa classe atualmente não define nenhum parâmetro, então vamos tentar estender nosso exemplo de caminhão.getVolume()
Crie uma nova classe chamada BridgeOfficer
. Este é um policial de plantão em uma ponte, que verifica todos os caminhões que passam para ver se a carga excede o peso permitido.
public class BridgeOfficer {
int maxWeight;
public BridgeOfficer(int normalVolume) {
this.maxWeight = normalVolume;
}
public boolean checkTruck(Truck truck) {
if (truck.weight > maxWeight) {
return false;
} else {
return true;
}
}
}
O checkTruck
método aceita um argumento, um Truck
objeto, e determina se o policial permitirá ou não o caminhão na ponte. Dentro do método, a lógica é bastante simples: se o peso do caminhão ultrapassar o máximo permitido, o método retorna falso. Terá que encontrar outra estrada 🙁
Se o peso for menor ou igual ao máximo, ele pode passar e o método retorna verdadeiro.
Se você ainda não entende totalmente as frases “retornar” ou “o método retorna um valor”, vamos fazer uma pausa na programação e considerá-las usando um exemplo simples da vida real. 🙂
Digamos que você fique doente e fique em casa sem trabalhar por alguns dias. Você vai ao departamento de contabilidade com o seu atestado médico, porque a licença médica deve ser paga.
Se compararmos essa situação com métodos, o contador terá um método. Você passa um atestado médico como argumento para esse método (sem ele, o método não funcionará e você não será pago!). Em seguida, são feitos os cálculos necessários dentro do método usando sua nota (o contador a utiliza para calcular quanto a empresa deve pagar a você), e o resultado do seu trabalho (uma quantia em dinheiro) é devolvido a você.paySickLeave()
Nosso programa funciona de maneira semelhante. Ele chama um método, passa dados para ele e, por fim, recebe um resultado. Este é BridgeOfficer
o método do nosso programa :main()
public static void main(String[] args) {
Truck first = new Truck();
first.weight = 10000;
Truck second = new Truck();
second.weight = 20000;
BridgeOfficer officer = new BridgeOfficer(15000);
System.out.println("Truck 1! Can I go, officer?");
boolean canFirstTruckGo = officer.checkTruck(first);
System.out.println(canFirstTruckGo);
System.out.println();
System.out.println("Truck 2! And can I?");
boolean canSecondTruckGo = officer.checkTruck(second);
System.out.println(canSecondTruckGo);
}
Criamos dois caminhões com cargas de 10.000 e 20.000. E a ponte onde o oficial trabalha tem peso máximo de 15.000.
O programa chama o método. O método calcula tudo e então retorna true, que o programa então salva como variável . Agora você pode fazer o que quiser com ele (assim como você pode fazer com o dinheiro que o contador lhe deu).officer.checkTruck(first)
boolean
canFirstTruckGo
No final do dia, o código
boolean canFirstTruckGo = officer.checkTruck(first);
se resume a
boolean canFirstTruckGo = true;
Aqui está um ponto muito importante: a return
instrução não retorna apenas o valor de retorno do método, ela também interrompe a execução do método! Qualquer código que vier após a return
instrução não será executado!
public boolean checkTruck(Truck truck) {
if (truck.weight > maxWeight) {
return false;
System.out.println("Turn around, you're overweight!");
} else {
return true;
System.out.println("Everything looks good, go ahead!");
}
}
Os comentários do oficial não serão exibidos, porque o método já retornou um resultado e foi encerrado! O programa retorna ao local onde o método foi chamado.
Você não precisa ficar atento a isso: o compilador Java é inteligente o suficiente para gerar um erro quando você tenta escrever um código após uma return
instrução.
Vingadores: Guerra de parâmetros
Existem situações em que queremos várias maneiras de chamar um método.
Por que não criar nossa própria inteligência artificial? A Amazon tem Alexa, a Apple tem Siri, então por que não teríamos um? 🙂
No filme Homem de Ferro, Tony Stark cria sua própria inteligência artificial incrível, Jarvis.
Vamos prestar homenagem a esse personagem incrível e nomear nossa IA em sua homenagem. 🙂
A primeira coisa que precisamos fazer é ensinar Jarvis a dizer olá para as pessoas que entram na sala (seria estranho se um intelecto tão incrível fosse indelicado).
public class Jarvis {
public void sayHi(String name) {
System.out.println("Good evening, " + name + ". How are you?");
}
public static void main(String[] args) {
Jarvis jarvis = new Jarvis();
jarvis.sayHi("Tony Stark");
}
}
Saída do console:
Good evening, Tony Stark. How are you?
Muito bom! Jarvis agora pode receber convidados. Claro, com mais freqüência do que seu mestre, Tony Stark.
Mas e se ele não vier sozinho! Mas nosso método aceita apenas um argumento. E assim ele pode saudar apenas uma pessoa que entra na sala, e irá ignorar a outra. Não muito educado, concorda? : /sayHi()
Nesse caso, podemos resolver o problema simplesmente escrevendo 2 métodos com o mesmo nome, mas com parâmetros diferentes:
public class Jarvis {
public void sayHi(String firstGuest) {
System.out.println("Good evening, " + firstGuest + ". How are you?");
}
public void sayHi(String firstGuest, String secondGuest) {
System.out.println("Good evening, " + firstGuest + " and " + secondGuest + ". How are you?");
}
}
Isso é chamado de sobrecarga de método. A sobrecarga de métodos permite que nosso programa seja mais flexível e acomode várias formas de trabalho. Vamos revisar como funciona:
public class Jarvis {
public void sayHi(String firstGuest) {
System.out.println("Good evening, " + firstGuest + ". How are you?");
}
public void sayHi(String firstGuest, String secondGuest) {
System.out.println("Good evening, " + firstGuest + " and " + secondGuest + ". How are you?");
}
public static void main(String[] args) {
Jarvis jarvis = new Jarvis();
jarvis.sayHi("Tony Stark");
jarvis.sayHi("Tony Stark", "Captain America");
}
}
Saída do console:
Good evening, Tony Stark. How are you?
Good evening, Tony Stark and Captain America. How are you?
Excelente, ambas as versões funcionaram. 🙂
Mas não resolvemos o problema! E se houver três convidados? Podemos, é claro, sobrecarregar o método novamente, para que ele aceite três nomes de hóspedes. Mas pode haver 4 ou 5. Até o infinito.sayHi()
Não existe uma maneira melhor de ensinar Jarvis a lidar com qualquer número de nomes, sem sobrecarregar o método um milhão de vezes? : /sayHi()
Claro que existe! Se não existisse, você acha que Java seria a linguagem de programação mais popular do mundo? 😉
public void sayHi(String...names) {
for (String name: names) {
System.out.println("Good evening, " + name + ". How are you?");
}
}
Quando ( ) é usado como parâmetro, indica que uma coleção de Strings será passada para o método. Não precisamos especificar com antecedência quantos serão, então agora nosso método é muito mais flexível:String... names
public class Jarvis {
public void sayHi(String...names) {
for (String name: names) {
System.out.println("Good evening, " + name + ". How are you?");
}
}
public static void main(String[] args) {
Jarvis jarvis = new Jarvis();
jarvis.sayHi("Tony Stark", "Captain America", "Black Widow", "Hulk");
}
}
Saída do console:
Good evening, Tony Stark. How are you?
Good evening, Captain America. How are you?
Good evening, Black Widow. How are you?
Good evening, Hulk. How are you?
Algum código aqui não será familiar para você, mas não se preocupe com isso.
É simples em seu núcleo: o método pega cada nome por vez e cumprimenta cada convidado! Além disso, ele funcionará com qualquer número de strings passadas! Dois, dez, até mil – o método funcionará corretamente com qualquer número de convidados. Muito mais conveniente do que sobrecarregar o método com todas as possibilidades, não acha? 🙂
Aqui está outro ponto importante: a ordem dos argumentos é importante!
Digamos que nosso método receba uma String e um número:
public class Person {
public static void sayYourAge(String greeting, int age) {
System.out.println(greeting + " " + age);
}
public static void main(String[] args) {
sayYourAge("My age is ", 33);
sayYourAge(33, "My age is "); // Error!
}
}
Se o método Person
da classe sayYourAge
recebe uma string e um número como entradas, o programa deve passá-los nessa ordem específica! Se passarmos por uma ordem diferente, o compilador gerará um erro e a pessoa não poderá dizer sua idade.
A propósito, construtores, que vimos na última lição, também são métodos! Você também pode sobrecarregá-los (ou seja, criar vários construtores com diferentes conjuntos de parâmetros) e a ordem dos argumentos passados também é fundamentalmente importante para eles. Eles são métodos reais! 🙂
Mais uma vez em relação aos parâmetros
Sim, desculpe, não terminamos com eles ainda. 🙂
O tema que estudaremos agora é muito importante.
Há 90% de chance de que você seja questionado sobre isso em todas as entrevistas futuras!
Vamos falar sobre como passar argumentos para métodos.
Considere um exemplo simples:
public class TimeMachine {
public void goToFuture(int currentYear) {
currentYear = currentYear+10;
}
public void goToPast(int currentYear) {
currentYear = currentYear-10;
}
public static void main(String[] args) {
TimeMachine timeMachine = new TimeMachine();
int currentYear = 2018;
System.out.println("What year is it?");
System.out.println(currentYear);
timeMachine.goToPast(currentYear);
System.out.println("How about now?");
System.out.println(currentYear);
}
}
A máquina do tempo possui dois métodos. Ambos pegam o número que representa o ano atual como uma entrada e aumentam ou diminuem seu valor (dependendo se queremos ir para o passado ou para o futuro).
Mas, como você pode ver na saída do console, o método não funciona!
Saída do console:
What year is it?
2018
How about now?
2018
Passamos a currentYear
variável para o método, mas seu valor não mudou.goToPast()
Estávamos em 2018 e aqui ficamos. Mas por que? : /
Porque os primitivos em Java são passados para métodos por valor.
O que isso significa?
Quando chamamos o método e passamos a variável para ele, o método não obtém a variável em si, mas sim uma cópia dela.goToPast()
int
currentYear (=2018)
currentYear
Claro, o valor desta cópia também é 2018, mas quaisquer alterações na cópia não afetam nossa currentYear
variável original de forma alguma!
Vamos tornar nosso código mais explícito e observar o que acontece com currentYear
:
public class TimeMachine {
public void goToFuture(int currentYear) {
currentYear = currentYear+10;
}
public void goToPast(int currentYear) {
System.out.println("The goToPast method has started running!");
System.out.println("currentYear inside the goToPast method (at the beginning) = " + currentYear);
currentYear