Return e métodos. [Resolvido]

8 respostas
G

Olá

Estou com uma dúvida quanto ao tipo de retorno de métodos. Já vi na documentacao da SUN que métodos que retornam void não precisam de return, e quando precisarem é só usar return;. Fora isso o método deve retornar algo do tipo especificado, blz.

seguinte:

public class MorseCode {
	public static String toMorse(char c) {
		
		if ( !(((c >= 48) && (c <= 57)) || ((c >= 65) && (c <= 90)) || ((c >= 97) && (c <= 122))) ) { // se nao ascii 0-9, A-Z, a-z
			return null;
		}
		
		if (Character.isDigit(c)) {
			switch(c) {
			case '1': return ".----";
			case '2': return "..---";
			case '3': return "...--";
			case '4': return "....-";
			case '5': return ".....";
			case '6': return "-....";
			case '7': return "--...";
			case '8': return "---..";
			case '9': return "----.";
			case '0': return "-----";
			}
		}
		
		c = Character.toUpperCase(c);
		switch(c) {
		case 'A': return ".-";
		case 'B': return "-...";
		case 'C': return "-.-.";
		case 'D': return "-..";
		case 'E': return ".";
		case 'F': return "..-.";
		case 'G': return "--.";
		case 'H': return "....";
		case 'I': return "..";
		case 'J': return ".---";
		case 'K': return "-.-";
		case 'L': return ".-..";
		case 'M': return "--";
		case 'N': return "-.";
		case 'O': return "---";
		case 'P': return ".--.";
		case 'Q': return "--.-";
		case 'R': return ".-.";
		case 'S': return "...";
		case 'T': return "-";
		case 'U': return "..-";
		case 'V': return "...-";
		case 'W': return ".--";
		case 'X': return "-..-";
		case 'Y': return "-.--";
		case 'Z': return "--..";
		}
	return null;
	}
}

1 dúvida: Aquele primeiro return null é a forma mais apropriada para trabalhar com a validação de dados quando os mesmos não são válido para serem manipulados? Se não, qual é o JAVA way de se fazer isso?
2 dúvida: O segundo return null está ali pois a ide ficou de frescuras dizendo que meu método tinha que retornar algo do tipo String, ok faz parte da regra da linguagem, mas dos possíveis “fins” do meu método todos retornam uma String então resolvi colocar esse return null para obedecer as regra da linguagem. Minha dúvida é se essa forma está de “acordo com o padrão JAVA” ou eu deveria trocar esse monte de return “”; por char ch = “”; break; e no final tocrar return null; por return ch; ?

Esse código foi postado aqui e funciona bem.

8 Respostas

ONHATE

Bom dia,
Uma solução que eu usaria sendo Java Way, é jogar uma exceção...
Exemplo:

public class MorseCode {
	public static String toMorse(char c) {
		
		if ( !(((c >= 48) && (c <= 57)) || ((c >= 65) && (c <= 90)) || ((c >= 97) && (c <= 122))) ) { // se nao ascii 0-9, A-Z, a-z
			throw new IllegalArgumentException("O caracter enviado não um um ascii válido 0-9 e A-z");
		}
		
		if (Character.isDigit(c)) {
			switch(c) {
			case '1': return ".----";
			case '2': return "..---";
			case '3': return "...--";
			case '4': return "....-";
			case '5': return ".....";
			case '6': return "-....";
			case '7': return "--...";
			case '8': return "---..";
			case '9': return "----.";
			case '0': return "-----";
			}
		}
		
		c = Character.toUpperCase(c);
		switch(c) {
		case 'A': return ".-";
		case 'B': return "-...";
		case 'C': return "-.-.";
		case 'D': return "-..";
		case 'E': return ".";
		case 'F': return "..-.";
		case 'G': return "--.";
		case 'H': return "....";
		case 'I': return "..";
		case 'J': return ".---";
		case 'K': return "-.-";
		case 'L': return ".-..";
		case 'M': return "--";
		case 'N': return "-.";
		case 'O': return "---";
		case 'P': return ".--.";
		case 'Q': return "--.-";
		case 'R': return ".-.";
		case 'S': return "...";
		case 'T': return "-";
		case 'U': return "..-";
		case 'V': return "...-";
		case 'W': return ".--";
		case 'X': return "-..-";
		case 'Y': return "-.--";
		case 'Z': return "--..";
		}
        //Neste aqui é difícil cair(impossível)... pois já validou lá no início... somente os caracteres válidos e ele só vai cair aqui se não for válido...
        //Mas sei que só está aqui por que o compilador daria um erro dizendo que a função não tem retorno... tudo bem...
        //Daria para trocar sua validação lá de cima e jogar a exceção direto daqui de baixo pq se chegou até aqui, é pq não é válido...
        //então joga a exceção direto...
	return null;
	}
}
Basilio

Vc pode no comeco do seu metodo declarar uma String, tipo String retorno =null; e fazer dessa String o retorno. Nos cases vc ao inves de usar case ‘1’: return “.----”; vc faria case ‘1’: retorno = “.----”;

Espero ter ajudado.

ViniGodoy

Acho que esse código fica melhor estruturado com um map:

public class MorseCode {  
   private static final Map<Character, String> morse;

   static { 
       morse = new HashMap<Character, String>();
       //Numeros
       morse.put('1', ".----");
       morse.put('2', "..---");  
       morse.put('3', "...--");  
       morse.put('4', "....-");  
       morse.put('5', ".....");  
       morse.put('6', "-....");  
       morse.put('7', "--...");  
       morse.put('8', "---..");  
       morse.put('9', "----.");  
       morse.put('0', "-----");  

       //Letras
       morse.put('A', ".-");  
       morse.put('B', "-...");  
       morse.put('C', "-.-.");  
       morse.put('D', "-..");  
       morse.put('E', ".");  
       morse.put('F', "..-.");  
       morse.put('G', "--.");  
       morse.put('H', "....");  
       morse.put('I', "..");  
       morse.put('J', ".---");  
       morse.put('K', "-.-");  
       morse.put('L', ".-..");  
       morse.put('M', "--");  
       morse.put('N', "-.");  
       morse.put('O', "---");  
       morse.put('P', ".--.");  
       morse.put('Q', "--.-");  
       morse.put('R', ".-.");  
       morse.put('S', "...");  
       morse.put('T', "-");  
       morse.put('U', "..-");  
       morse.put('V', "...-");  
       morse.put('W', ".--");  
       morse.put('X', "-..-");  
       morse.put('Y', "-.--");  
       morse.put('Z', "--..");  
       morse = Collections.unmodifiableMap(morse);
   }

   public static String toMorse(char c) {  
      c = Character.toUpperCase(c);
      if (!morse.contains(c)) {
         throw new IllegalArgumentException("Caractere inválido: " + c);
      }
      return morse.get(c);
   }

}

Assim fica fácil inserir novos códigos, se necessário. E evita aquele switch horrendo.

ONHATE

Bom também… :slight_smile:

ViniGodoy
GradeBook:
1 dúvida: Aquele primeiro return null é a forma mais apropriada para trabalhar com a validação de dados quando os mesmos não são válido para serem manipulados? Se não, qual é o JAVA way de se fazer isso?

Depende. Muitas vezes é a forma correta, tudo vai depender do que você estiver modelando. Só fique atento que, uma vez retornando null, quem usa seu método terá que testar contra null, e isso terá que estar bem documentado. Muitas vezes, é melhor usar o padrão null object e retornar um objeto com um valor que represente o nulo, mas que não seja nulo em si. Por exemplo, ao invés de
return null;

Você poderia usar:
return "";

Como no exemplo do código do outro link que você postou.

GradeBook:
2 dúvida: O segundo return null está ali pois a ide ficou de frescuras dizendo que meu método tinha que retornar algo do tipo String, ok faz parte da regra da linguagem, mas dos possíveis "fins" do meu método todos retornam uma String então resolvi colocar esse return null para obedecer as regra da linguagem. Minha dúvida é se essa forma está de "acordo com o padrão JAVA" ou eu deveria trocar esse monte de return ""; por char ch = ""; break; e no final tocrar return null; por return ch; ?

Eu geralmente prefiro dar o return o quanto antes possível. Veja bem, sem o return, o programador é obrigado a ler o resto do seu método inteiro, só para descobrir que no final, ele simplesmente vai retornar o char. Se você retornar direto, isso fica bastante claro.

A prática de testar condicionais logo no início do método, e retornar com return ou um exception logo de cara, é chamada de code-guard. Eu considero uma boa prática, pois já deixa claro para quem está lendo o seu código, qual é a condição de execução do seu método:

public void fatorial(int valor) {
    if (valor < 0) {
        throw new IllegalArgumentException("Informe um valor maior do que 0!");
    }

    if (valor <= 2) {
       return valor;
    }

    return valor * fatorial(valor-1);
}

Outro detalhe: Note que se você dá return ou lança exception dentro de um if, o else não é necessário. Isso evita também identação desnecessária. No exemplo acima, o código só chegou na linha 6 se o valor era maior que zero. Caso contrário, ele já teria caído fora na exception. Da mesma forma, ele só chegou na linha 10, pq o valor era > 2, caso contrário, o código já teria saído no return.

Isso torna o código ali em cima consideravelmente mais claro do que esse aqui:
public void fatorial(int valor) {
   int retorno = -1;

    if (valor < 0) {
        throw new IllegalArgumentException("Informe um valor maior do que 0!");
    } else {
       if (valor <= 2) {
           retorno = valor; //Será que ele vai fazer algo mais com retorno? Só lendo o resto.
       } else { //Terceiro nível de identação, ufa!
          retorno = valor * fatorial(valor-1);
       }
    }

    return retorno;
}
G

Olá a todos

ONHATE: Imaginei que fosse por aí mesmo, tenho visto coisas do tipo:

public char charAt(int index) {
        if ((index < 0) || (index >= count)) {                               <----
            throw new StringIndexOutOfBoundsException(index);    <----
        }
        return value[index + offset];
    }

no código do String.class para fazer a validação de entrada de dados, mas ainda não cheguei na parte de exceptions no livro do Deitel. Valeu pela dica. :smiley:

Basilio: ajudou sim, essa é uma outra forma de fazer.

ViniGodoy: Ainda não cheguei no Map. Estou tentando fazer do jeitão feijão com arroz ainda.
Me diga uma coisa, esse map que você fez é mais ou menos isso aqui em C?

struct cmdtab {
	int command;
	char *name;
	int min;
	char *args;
} cmdtab[] = {
{ CMD_BLANK,	"blank",	1, "" },
{ CMD_CDDB,	"cddbinfo",     2, "[n]" },
{ CMD_CDID,	"cdid",		3, "" },
{ CMD_CDPLAY,	"cdplay",	3, "[track1-trackN ...]" },
{ CMD_CDRIP,	"cdrip",	3, "[track1-trackN ...]" },
{ CMD_CLOSE,    "close",        1, "" },
{ CMD_DEBUG,    "debug",        3, "on | off" },
{ CMD_DEVICE,   "device",       1, "devname" },
{ CMD_EJECT,    "eject",        1, "" },
{ CMD_QUIT,	"exit",		2, "" },
{ CMD_HELP,     "?",            1, 0 },
{ CMD_HELP,     "help",         1, "" },
{ CMD_INFO,     "info",         1, "" },
{ CMD_NEXT,	"next",		1, "" },
{ CMD_PAUSE,    "pause",        2, "" },
{ CMD_PLAY,     "play",         1, "[track1[.index1] [track2[.index2]]]" },
{ CMD_PLAY,     "play",         1, "[[tr1] m1:s1[.f1] [tr2] [m2:s2[.f2]]]" },
{ CMD_PLAY,     "play",         1, "[#block [len]]" },
{ CMD_PREV,	"previous",	2, "" },
{ CMD_QUIT,     "quit",         1, "" },
{ CMD_REPLAY,	"replay",	3, "" },
{ CMD_RESET,    "reset",        4, "" },
{ CMD_RESUME,   "resume",       1, "" },
{ CMD_SET,      "set",          2, "lba | msf" },
{ CMD_STATUS,   "status",       1, "" },
{ CMD_STOP,     "stop",         3, "" },
{ CMD_VOLUME,   "volume",       1, "left_channel right_channel" },
{ CMD_VOLUME,   "volume",       1, "left | right | mono | stereo | mute" },
{ 0, 0, 0, 0}
};

Retirado de: http://www.openbsd.org/cgi-bin/cvsweb/~checkout~/src/usr.bin/cdio/cdio.c?rev=1.71;content-type=text%2Fplain

resposta 1: Saquei, retornar um objeto mesmo que vazio.
resposta 2: Eu já tenho uma idéia sobre esse tipo de coisa, só não sabia que se chamava code-guard. :smiley:

ViniGodoy

Não isso que vc fez no C é o mesmo que:

Class CmdTab {
   public int command;
   public String name;
   public int min;
   public String args;

   public CmdTab(int command, String name, int min, String args) {
      this.command = command;
      this.name = name;
      this.min = min;
      this.args = args;
   }
}

CmdTab cmdtab[] = {
   new CmdTab(CMD_BLANK,    "blank",    1, ""), 
   new CmdTab(CMD_CDDB, "cddbinfo",     2, "[n]"),
   //etc etc etc
};

Isto é, um array de uma classe qualquer.

No C++, um map é feito assim:
using std::map;
using std::string;

class Morse 
{
   private:
      map<char, string> morse;
   public:
      Morse() 
      {
         morse['A'] = ".-";
         morse['B'] = "-...";
         morse['C'] = "-.-.";
         morse['D'] = "-..";    
         morse['E'] = ".";
         //etc...etc...etc...
      }

      const string& toMorse(const char c) const 
      {
         if (morse.find(c) == map::end)
            return "";
         return morse[c];
      }   
};

Note que um Map, tanto em Java quanto em C++, equivalem a um array, onde a chave pode ser qualquer coisa, ao invés de apenas um número. No C++ isso fica mais evidente pois há sobrecarga de operadores. No Java, você deve usar os métodos put e get para fazer o papel dos colchetes.

No fundo o mapa é usado para associar uma chave a um valor (no caso, o caracter ascii - chave - ao código morse em si - valor). Por isso, o mapa também é chamado de array associativo.

G

Muito obrigado a todos pelas respostas. :lol: :lol:
Quanto mais explicado melhor!

Criado 14 de dezembro de 2009
Ultima resposta 15 de dez. de 2009
Respostas 8
Participantes 4