Goto xxx

38 respostas
M

Ola amigos

Gostaria de saber como implementar o comando GOTO do C++ no Java .
Exemplo: Dado uma certa condição de um if , eu qeuro q a execução vá para outro ponto do código marcado com um rótulo …
no C++ seria

if (a>b) goto ponto;

ponto: return;

Obrigado

38 Respostas

peczenyj

pesquise sobre break label – é a unica forma de fazer isso :wink:

K

goto não foi implemetada na linguagem Java. É considerada perigosa.
A palavra goto é reservada em java, mas não é utilizada.

Se vc tentar usar goto em java, o compilador lhe adivertirá:

‘goto’ not supported.

C

CRUZES!!

Ainda bem. Não devia ter sido implementada em linguagem alguma.

Uma vez eu ouvi que ela é utilizada internamente pelo compilador. É verdade?

andre_a_s

Alguem me explica pq é tão ruim(ou perigoso) usar goto?
Realmente acho que o código fica sujo, mas nao vejo nada de perigoso nisso.

cassio

goto?!?!?!?! Sai foooraaaaa!!1

Isso ai é o maior absurdo! Mesmo em C/C++ definitivamente não é aconselhável utilizar goto!
O problema com isso é: Seu código vira uma zona, parecendo um espaguete. O normal é que o código siga uma sequência "linear"de execução, não fique indo e voltando. O problema maior que isso gera é na hora de debugar o código, fica impraticável, você nunca sabe onde está, se perde, enfim, é terrível.
O uso de goto está entre as piores práticas de programação! Eu nunca vi um caso em que um goto fosse 100% necessário, sempre dá pra evitar usar isso, é só rever a lógica :slight_smile:

Falou!

C

E como fica a pilha de execução do programa? Ele não tem como saber que você saiu do método/função para limpar tudo que foi alocado…

Acho que seu trocar todos os “returns” por “gotos” uma hora vou estourar a pilha…

kuchma

andre_a_s:
Alguem me explica pq é tão ruim(ou perigoso) usar goto?
Realmente acho que o código fica sujo, mas nao vejo nada de perigoso nisso.

IMHO isso eh paranoia de professor que ensina Pascal na faculdade. Os caras bitolam tanto a cabeca dos alunos, que o cara sai de la achando que “goto” eh coisa do outro mundo.

Realmente, nao eh recomendavel utilizar, mas tem la suas “classicas” aplicacoes (o velho exemplo do tratamento de erros, sair de diversos loops aninhados, etc). E sim, realmente, nao tem nada que nao de pra fazer sem o goto.

Marcio Kuchma

T

Se você fizer uma máquina de estados com “while” e “switch” é muito parecido com o goto. Por exemplo:

int estado = 1;
while (estado != 0) {
    switch (estado) {
    case 1:
         if (algumacoisa) estado = 2;
         else if (outracoisa) estado = 3;
         break;
    case 2:
         if (algumacoisa) estado = 3;
         else if (outracoisa) estado = 0;
         break;
     case 3:
         ... etc....
     default:
         break;
     }
}
Sami_Koivu

cesarse:

Uma vez eu ouvi que ela é utilizada internamente pelo compilador. É verdade?

Acho que não faz sentido. Porém, em java bytecode existe sim a instrução goto que é utilizado para implementar if, while, for, finally, etc nas classes compiladas.

[]s,
Sami

K

Ha, no livro da Kathy Sierra para certificação, quando citam sobre palavras reservadas não utilizadas, diz que o primeiro esboço que o projetista criou para o aviso de advertencia do uso do goto foi assim:

Esses projetistas tem um humor… :slight_smile:

J

Isso me lembrou de um tio que programava em Turbo Basic num PC-XT, ele estava desenvolvendo um editor de textos. A listagem dele era gigantesca e os “gotos” estavam lá “ajudando” a trocar as páginas de 34 para 56 depois para 25 e volta pra 56 vai pra 144.

Hauahuahauahua…

M

Primeiro,
se goto fosse tão terrível assim, nunca seria implementado em nenhuma linguagem.
Em java não foi implementado, isso pelo fato de java ter sido projetado para “usuários”
de um alto nível que chega a cegar!
Já usei goto e foi muito necessário. Eu poderia ter usado outros recursos,
mas com o goto ficou bem mais simples.
O cara só tem que ter cuidade e não viciar!!!

peczenyj

De uma olhada no texto:

Go To Statement Considered Harmful
Edsger W. Dijkstra

http://david.tribble.com/text/goto.html

ViniGodoy

Eu discordo, mangad2.

Inicialmente ele foi implementado pois era uma escolha lógica, era um comando que remetia diretamente a instrução jump, do assembly. E era com o jump que os engenheiros da época estavam acostumados. Isso não significa que a escolha tenha sido acertada, quer dizer, só po rque alguém já fez um dia, devemos continuar fazendo hoje.

Aliás, se você ler um livro de C++ (ou de qualquer linguagem de legado), vai ver uma série de recomendações do que não se deve fazer. E usar goto é uma delas. Pegue por exemplo o livro “A linguagem de programação C++”, do Bjarne Stroustroup, criador do C++, na página 132 da 3a edição traduzida. Lá ele explica o comando goto com a seguinte ressalva: “Um dos poucos usos do goto que fazem sentido em código comum é sair de um laço aninhado ou de um comando switch (um break sai fora somente do laço ou comando switch mais interno que o inclua)”. Note que é exatamente a situação que o break condicional do java implementa.

O goto não é a única coisa que as linguagens modernas tem evitado. A definição de constantes no lugar de macros, a redução de escopo de variáveis, uso de herança múltipla, e o uso cada vez mais incomum de linguagens com suporte de aritmética de ponteiros é um sinal de que a coisa tem evoluído.

É lógico que se você for um bom programador, disciplinado, você vai fazer um bom uso do goto ou de qualquer uma das coisas que falei acima. Entretanto, um dos pontos fortes do java é o fato de você não precisar ser um programador assim para programar bem. Já leu um manual de C++ ou um livro como Effective C++?

Programar C++ é como andar num campo minado. No menor descuido, você pode fazer uma besteira, inserir um erro maquiavélico ou deixar o seu código muito difícil de se manter. Tanto que bibliotecas inteiras, como a Boost, foram inventadas para driblar os erros comuns dos programadores, livros foram escritos para ensinar o que é bom e o que não é bom se fazer no código.

Acho que o Java foi uma evolução natural desse processo. Quando os programadores criaram o Java, retiraram tudo de potencialmente perigoso que tinha no C++. Viram que não adiantava manter um comando como goto para uma ou duas situações específicas. Pesaram o que causava mais mal do que bem e retiraram fora. E fizeram uma linguagem que é realmente um prazer de se programar.

M

Exato…
goto não é pra todo mundo.
Na verdade eu só usei uma única vez, e fiz várias alterações no código, mas ele continua lá.
Não se pode comparar C++ com JAVA, são para propósitos diferentes.
Java não faz tudo que C++ faz, mas C++ faz tudo que JAVA faz, isso é nítido porque java foi feito inicialmente em c++.
Agora, meu código não ficou horrível utilizando um goto, talvez até ficaria se eu utilizasse uns 10, mas não é o caso.
Realmente o goto foi feito para simular o jump. E como o java tá tão longe da máquina física, não tem cabimento mesmo utilizar goto.

M

Outra coisa também, temos que formar opniões por experiências e não por que está escrito numa certa página de um certo capítulo de um livro.

ViniGodoy

Eu programo em C++ há pelo menos 10 anos. Também já programei em Basic e tive diversos problemas com Goto.

E achei que citar o criador da linguagem é uma BOA referência para provar que, mesmo que o comando esteja numa linguagem, ele não necessariamente deve ser usado. Esse argumento era uma das suas justificativas do porque o comando goto era bom. Afinal, era o comentário de nada menos que o criador da linguagem, que manteve o comando por lá.

Por fim, seu último argumento foi um tanto infantil. A experiência não vem necessariamente de você tentar, se ferrar e descobrir que é ruim. Ler livros e aprender com outras pessoas que já tiveram seus problemas é uma ótima maneira de aprender. Até por isso livros como Design Patterns existem e se tornaram muito famosos.

M

Talvez 10 anos seja pouco…

ViniGodoy

O que dizer de um comentário como esse? Já tá virando Trolling.

Enfim, para não dizer que o Goto é completamente inútil, algumas situações onde ele é usado:

  1. Otimizações: Estamos falando aqui de código extremamente otimizado, onde abre-se mão da legibilidade e paga-se um preço alto de manutenção em prol de performance. Um exemplo clássico (que inclusive gerou uma dicussão similar a essa envolvendo o goto) é o caso do Kernel do Unix;

  2. Código gerado automaticamente: Código gerado por ferramentas como ANTLR podem usar goto. Acredita-se que um programador não deva meter a mão num código desses, gerado automaticamente. Notem que o código da ferramenta em si não deve usar goto, só o que ela gera. Esse código não passa da uma reescrita de instruções nativas em uma linguagem mais estruturada;

  3. Para sair de switchs e for aninhados: É o caso do break condicional do java, que nada mais é que um goto comportado. Realmente, aqui não tem escapatória. Mas há boas maneiras de escapar elegantemente dessas situações.

louds

Goto em C é utilizado com dois propósitos, o primeiro é para centralizar a limpeza de recurso em uma função, o segundo é para opter performance em interpretadores baseados em opcodes, que permite utilizar direct-threading (não tem relação com threads do Java). No primeiro caso a alternativa é mais feia que não usar goto, então é um sacrificio medido.

M

trolling???
O que eu disse de mais?

rogeriop80

Louds,

Exato e o seguinte, hoje criticamos GOTO pois implementar Orientado a Objetos é muito comum agora quero ver criar sistemas grandes com linguagens estruturadas a 10, 12 anos atrás sem utilizar GOTO. Desenvolvi durante muito tempo em C e a gente evitava ao máximo utilizar GOTO, mas as vezes a própria limitação da linguagem estruturada nos obrigava a utilizar.

Abraços.

pcalcado

rogeriop80:

Exato e o seguinte, hoje criticamos GOTO pois implementar Orientado a Objetos é muito comum agora quero ver criar sistemas grandes com linguagens estruturadas a 10, 12 anos atrás sem utilizar GOTO. Desenvolvi durante muito tempo em C e a gente evitava ao máximo utilizar GOTO, mas as vezes a própria limitação da linguagem estruturada nos obrigava a utilizar.

Abraços.

Interessante. Se importa de comentar um exemplo onde uma linguagem procedural não resolveria um problema sem GOTO?

louds

Até onde eu sei, nenhuma linguagem estruturada tem suporte a exceptions. Dado o seguinte código:

int check_abc (char * file) {
   FILE *f = NULL;
   f = fopen (file, "r");

   if (!f) return -1;

   if (fgetc (f) != 'a') {
      fclose (f);
      return -2;
   }

   if (fgetc (f) != 'b') {
      fclose (f);
      return -2;
   }

   //... mais 1 monte de testes feito o if anterior

   fclose (f);
   return 0;
}

Fica muito mais facil de manter se for escrito assim:

int check_abc (char * file) {
#define FAILED goto __failed;
   FILE *f = NULL;
   f = fopen (file, "r");

   if (!f) return -1;

   if (fgetc (f) != 'a')
      FAILED;

   if (fgetc (f) != 'b')
      FAILED;

   //... mais 1 monte de testes feito o if anterior

   fclose (f);
   return 0;

__failed:
   fclose (f);
   return -2;
#undef FAILED
}

Não é uma questão de não ser possivel escrever sem GOTO, mas de ficar mais facil, o código de limpeza, nesse caso “fclose(f)”, fica restrito a um lugar apenas. Se estivesse usando Java, seria um try/finally.

pcalcado

Nesse caso o problema não é do paradigma, é da linguagem. Ser OO não implica ter exceções também.

M

O exemplo do Louds foi perfeito!!!

L

Até onde eu sei, nenhuma linguagem estruturada tem suporte a exceptions. Dado o seguinte código:

int check_abc (char * file) {
   FILE *f = NULL;
   f = fopen (file, "r");

   if (!f) return -1;

   if (fgetc (f) != 'a') {
      fclose (f);
      return -2;
   }

   if (fgetc (f) != 'b') {
      fclose (f);
      return -2;
   }

   //... mais 1 monte de testes feito o if anterior

   fclose (f);
   return 0;
}

Fica muito mais facil de manter se for escrito assim:

int check_abc (char * file) {
#define FAILED goto __failed;
   FILE *f = NULL;
   f = fopen (file, "r");

   if (!f) return -1;

   if (fgetc (f) != 'a')
      FAILED;

   if (fgetc (f) != 'b')
      FAILED;

   //... mais 1 monte de testes feito o if anterior

   fclose (f);
   return 0;

__failed:
   fclose (f);
   return -2;
#undef FAILED
}

Não é uma questão de não ser possivel escrever sem GOTO, mas de ficar mais facil, o código de limpeza, nesse caso “fclose(f)”, fica restrito a um lugar apenas. Se estivesse usando Java, seria um try/finally.

Goto já não é considerado boa prática há uns quarenta anos. E nem vem dizer que é inevitável usar GOTO em C. Olha seu código, não está seguindo a programação estruturada! Tudo bem, a questão do exception é complicada, mas seria possível escrever esse código sem utilização de goto, fazendo assim:

int check_abc (char * file) {
#define FAILED { fclose(f); return -2; }
   FILE *f = NULL;
   f = fopen (file, "r");

   if (!f) return -1;

   if (fgetc (f) != 'a')
      FAILED

   if (fgetc (f) != 'b')
      FAILED

   //... mais 1 monte de testes feito o if anterior

   fclose (f);
   return 0;

#undef FAILED
}

E um melhor, sem define e seguindo mais ainda a programação estruturada.

int check_abc (char * file) {
   int retValue = 0;
   FILE *f = NULL;
   f = fopen (file, "r");

   if (f) {
      if (fgetc (f) == 'a') {
         if (fgetc (f) == 'b') {
         //... mais 1 monte de testes feito o if anterior
            // faça o que quiser com o arquivo
         } else
            retValue = -2;
      } else
         retValue = -2;
      // tenho que fechar o arquivo de qualquer jeito
      fclose(f);
   } else
      retValue = -1;
   
   return retValue;
}

É claro que isso pode entrar em gosto pessoal, mas se fosse fazer em C, eu fazia (e realmente eu fazia, antes de entrar no Java) como esse último código mostrado.

M

Leonardo3001,

Você fez duas versões do código original sem utilização de goto. Mas vc se esqueceu que sua versão faz exatamente a mesma coisa que o goto, ou seja, fica igual.
O problema todo não é a sintaxe “goto label;” Mas sim a semântica “vá em algum lugar do código e faça alguma coisa”. A questão nativa é a legibilidade, e no seu caso, ficou EXATAMENTE igual a versão utilizando goto!!!
Isso acontece porque geralmente ensinam programação e dizem que é terrível a utilização do goto. O cara aprende a não usar e odiar o goto mas faz uma “gambiarra” que causa a mesta desestruturação que o goto…
Isso ai, é trocar 1GB por 1024MB…

ViniGodoy

Ele substituiu goto por uma macro mais complexa. E isso também é um tanto questionável. As macros desaparecem antes mesmo da compilação, e são difíceis de se depurar. Além de ter a chance de gerar um comportamento inesperado. É fato que ele restringiu a macro apenas a função dele, o que melhora muito as coisas. Acho que aqui é uma questão de gosto pessoal, eu ainda prefiro a solução do Louds, mesmo com os gotos. Que aliás, é parcialmente adotada pelo Visual Basic, como mecanismo oficial da linguagem.

Mas... veja bem. A pergunta a oficial do tópico é: Porque o Java não suporta goto? Se remontarmos a origem histórica do goto, claro, acharemos os locais onde, para época, ele era uma boa solução. É capaz até de, se pegarmos livros daquela época, acharmos recomendações envolvendo goto.

O fato é que isso causou uma boa dose de dor de cabeça para os programadores da época. E programadores aprendem com os erros e melhoram os seus programas. Criam paradigmas melhores e técnicas melhores. E graças a isso, o comando se tornou obsoleto hoje em dia.

Se você usar Java, ou mesmo C++, você realmente deve odiar o goto (exceto talvez nas situações que descrevi ali em cima). Nessas linguagens já há maneiras muito superiores de se resolver o problema. Assim como deve odiar retornar "códigos de erro" no lugar de exceptions, ou ainda desconfiar muito quando estiver escrevendo switchs.

PS:
int x = 2;
int y = 1;
//Como exemplo de macro que gera comportamento inesperado, conside a clássica:
#define MAX((a),(b)) (a) > (b) ? (a) : (b)

//Veja o que acontece se fizermos:
int z = MAX(x++, y);  //Notem que parece uma função, mas é macro.

//Esse código é substituido por:
int z = x++ > y ? x++ : y;

//Quantas pessoas notariam que x é somado 2 vezes?
peczenyj

É possivel fazer um tipo de ‘tratamento de excessões’ em C sem goto, via setjump/longjump :wink:

janiogabriel

Olá! GOTO foi banido pq com o advento da orientação a objetos fica confuso utilizá-lo, já para um para linguagens de programação estruturada como o puro asm NÃO há como fazer uma aplicação sem o uso do JUMP (JSR, LJMP, etc.). Agora citar que o GOTO é coisa de usuário dummy acho que é um pouco “sem noção”… qm duvida, que vá implementar um protocolo de comunicação qlqr em asm, por exemplo.

ViniGodoy

E quase um ano depois… alguém desenterra o tópico! :o

Só um comentário. No caso específico de protocolos de comunicação de tempo real (telefonia, por exemplo), muitos são implementados em hardware. E, portanto, em assembly e C.

E, nesses casos, usa-se goto.

mathiasgrimm

import com.sun.org.apache.bcel.internal.generic.GOTO;

int i=0;

a:

System.out.println(1123123);

i++;
if(i==0)
    {
    	GOTO a;
    }

funciona que uma beleza!!

Zord

Então como eu faria no meu problema abaixo sem apelar pro "temível" GOTO?

// ESCOLHA
opcao = Integer.parseInt(JOptionPane.showInputDialog(null,"Digite um número entre 1 e 4:"));

switch(opcao) {
   case 1:
      ...
      break;
   case 2:
      ...
      break;
   case 3:
      ...
      break;
   case 4:
      ...
      break;
   default:
      JOptionPane.showInputDialog(null,"Opção inválida! É entre 1 e 4 seu animal. =P");
      // volte para a ESCOLHA
}
No caso eu não quero colocar um IF ELSE por fora pq não quero o encerramento do programa, quero que o usuário corrija sua escolha na mesma execução.

Flws!

T

E a propósito, você não vai subir na vida se tratar o usuário como “animal”. É ele que paga seu salário :stuck_out_tongue:

// ESCOLHA
do {
    opcao = Integer.parseInt(JOptionPane.showInputDialog(null,"Digite um número entre 1 e 4:"));
    switch(opcao) {
       case 1:
          ...
          break;
       case 2:
          ...
          break;
       case 3:
          ...
          break;
       case 4:
          ...
          break;
       default:
          JOptionPane.showInputDialog(null,"Opção inválida! É entre 1 e 4 seu animal. =P");
          // volte para a ESCOLHA
    }
} while (opcao < 1 || opcao > 4);
celso.martins

Se convencer esse pessoal que goto é uma péssima prática, imagina dizer que null references foi um erro de um bilhão de dólares.

No próprio Basic, o goto já podia ser substituido por gosub, criando o nível 1 de encapsulamento, as sub-rotinas. E no Basic que programei (TK2000 II-Color) o goto era feito para uma linha de código e não para um “label” o que degradava mais ainda a legibilidade do código.

Não lembro de goto no Clipper e nem no Object Pascal.

Zord

Vlws ae!

E de boa, akele “esporro” seria só pra deixar esse exemplo cômico! ^^

Engraçado q eu tinha pensado no DO WHILE, mas estava colocando-o no lugar errado. :-\

E no caso eu nunca iria conseguir usar o BREAK do Java, pois ele teria q ser assim:

loop: ... ... ... break loop;
Teria que ir para cima do código e não pular pra uma parte abaixo dele…

Flws!

M

Olha, eu realmente não gosto de usar o goto, mas algumas vezes por questão de performance, temos que acabar usando…

É que nem mixturar com assembly, torna teu codigo dependente de plataforma, mas em algum casos é a melhor opção se não a unica.

Pra pucrs, eu tavah fazendo um exercicio de optimização de algoritimos…

era pra gerar um milhão de numeros primos, eu consegui em 3 segundos, e para isso eu usei varios laços de repetição, um deles dentro do verificador do numero, para ver se é composto ou primo. Este laço tinha que executar uma vez testando no maximo ate onze, matando a maior parte dos numeros, e se terminase sua execução teria que testar ate a raiz para ter certeza que o numero era primo…

Por questões obvias de performance, clareza (não repetir a mesma coisa), e uso de memoria, optei pelo goto para retornar ao mesmo laço, mas com outros parametros…

O problema é que tenho que entregar em Java, e o mesmo algoritimo em java, leva por volta de 45 segundos para executar sem este tweak…

O codigo segue abaixo:

/*
 *  Primos.c
 *  
 *
 *  Created by Marcos Sartori on 28/10/2009.
 *  Copyright 2009 Marcos Sartori Computer Systems. All rights reserved.
 *
 */

#include <stdio.h>
#include <math.h>

#define TRUE -1
#define FALSE 0

int main (int argc, char* argv)
{
	unsigned register int i, z;
	i = 0; z = 0;
	
	while (z<=1000000){
		if (isPrime(i)){
			printf("%d\n", i);
			z++;
		}
		i++;
	}
	//printf("0x%08X\n", i);
	
	return 0;
}

int isPrime(unsigned int aNumber)
{
	unsigned register int i, z, j;
	
	if (aNumber<=1) return FALSE;
	if ((!(aNumber&1))&&(aNumber!=2)) return FALSE;
	
	z=aNumber<=11?aNumber-1:11; goto loop;
	
sqrt:
	z=sqrt(aNumber); j = TRUE;
loop:
	for (i=3; i<=z; i+=2)
		if (!(aNumber%i)) return FALSE;
	if(!j) goto sqrt;
	
	return TRUE;
}

Se tiver algum Japhilopho que saiba como conseguir um suquinho de performance do java, me retornem por favor…

Criado 13 de julho de 2006
Ultima resposta 29 de out. de 2009
Respostas 38
Participantes 21