Essa funcionalidade será colocada em uma versão Java posterior?
Alguém pode explicar por que não posso fazer isso, como na maneira técnica como a switch
declaração de Java funciona?
java
string
switch-statement
Alex Beardsley
fonte
fonte
"Don't hold your breath."
lol, bugs.sun.com/bugdatabase/view_bug.do?bug_id=1223179Respostas:
As instruções de alternância com
String
casos foram implementadas no Java SE 7 , pelo menos 16 anos após a primeira solicitação. Um motivo claro para o atraso não foi fornecido, mas provavelmente tinha a ver com desempenho.Implementação no JDK 7
O recurso agora foi implementado
javac
com um processo de "remoção de açúcar"; uma sintaxe limpa e de alto nível usandoString
constantes nascase
declarações é expandida no tempo de compilação para um código mais complexo, seguindo um padrão. O código resultante usa instruções da JVM que sempre existiram.A
switch
comString
casos é convertido em dois comutadores durante a compilação. A primeira mapeia cada sequência para um número inteiro único - sua posição no comutador original. Isso é feito ativando primeiro o código de hash do rótulo. O caso correspondente é umaif
instrução que testa a igualdade das cadeias de caracteres; se houver colisões no hash, o teste será em cascataif-else-if
. A segunda opção espelha isso no código-fonte original, mas substitui os rótulos das caixas pelas suas posições correspondentes. Esse processo de duas etapas facilita a preservação do controle de fluxo da chave original.Comutadores na JVM
Para obter mais detalhes técnicos
switch
, consulte a Especificação da JVM, na qual a compilação das instruções do switch é descrita. Em poucas palavras, existem duas instruções diferentes da JVM que podem ser usadas para um comutador, dependendo da escassez das constantes usadas pelos casos. Ambos dependem do uso de constantes inteiras para que cada caso seja executado com eficiência.Se as constantes são densas, elas são usadas como um índice (após subtrair o valor mais baixo) em uma tabela de indicadores de instruções - a
tableswitch
instrução.Se as constantes forem escassas, uma pesquisa binária do caso correto é executada - a
lookupswitch
instrução.Em de-adoçamento um
switch
emString
objetos, ambas as instruções são susceptíveis de ser utilizados. Alookupswitch
é apropriado para o primeiro comutador de códigos de hash para encontrar a posição original do caso. O ordinal resultante é um ajuste natural para atableswitch
.Ambas as instruções exigem que as constantes inteiras atribuídas a cada caso sejam classificadas em tempo de compilação. Em tempo de execução, embora o
O(1)
desempenho detableswitch
geralmente pareça melhor que oO(log(n))
desempenho delookupswitch
, ele requer alguma análise para determinar se a tabela é densa o suficiente para justificar a troca espaço-tempo. Bill Venners escreveu um ótimo artigo que aborda isso com mais detalhes, juntamente com uma análise detalhada de outras instruções de controle de fluxo Java.Antes do JDK 7
Antes do JDK 7,
enum
era possível aproximar umString
comutador baseado em. Isso usa ovalueOf
método estático gerado pelo compilador em todos osenum
tipos. Por exemplo:fonte
Pill
alguma ação com base em,str
eu argumentaria se é preferível, pois permite manipularstr
valores fora do intervalo VERMELHO, AZUL sem a necessidade de capturar uma exceçãovalueOf
ou verificar manualmente uma correspondência com o nome de cada tipo de enumeração que apenas adiciona sobrecarga desnecessária. Na minha experiência, só fazia sentido usarvalueOf
para se transformar em enumeração se uma representação segura do tipo String fosse necessária posteriormente.(hash >> x) & ((1<<y)-1)
produziria valores distintos para cada stringhashCode
diferente e(1<<y)
menor que o dobro do número de strings (ou em pelo menos, não muito maior que isso).Se você tem um lugar no seu código onde pode ativar uma String, pode ser melhor refatorá-la para ser uma enumeração dos valores possíveis, que você pode ativar. Obviamente, você limita os valores potenciais de Strings que você pode ter aos da enumeração, que podem ou não ser desejados.
É claro que sua enumeração pode ter uma entrada para 'other' e um método fromString (String), então você pode ter
fonte
A seguir, é apresentado um exemplo completo, com base na postagem de JeeBee, usando java enum em vez de usar um método personalizado.
Observe que no Java SE 7 e posterior, você pode usar um objeto String na expressão da instrução switch.
fonte
Os comutadores baseados em números inteiros podem ser otimizados para um código muito eficaz. Os comutadores baseados em outro tipo de dados só podem ser compilados em uma série de instruções if ().
Por esse motivo, o C & C ++ permite apenas comutações em tipos inteiros, pois não faz sentido em outros tipos.
Os designers de C # decidiram que o estilo era importante, mesmo que não houvesse vantagem.
Os designers de Java aparentemente pensavam como os designers de C.
fonte
Um exemplo de
String
uso direto desde 1.7 pode ser mostrado também:fonte
James Curran diz sucintamente: "Os comutadores baseados em números inteiros podem ser otimizados para um código muito eficaz. Os comutadores baseados em outro tipo de dados só podem ser compilados em uma série de instruções if (). Por esse motivo, o C & C ++ permite apenas comutadores em tipos inteiros, já que era inútil com outros tipos ".
Minha opinião, e é só isso, é que, assim que você começa a ativar os não-primitivos, você precisa começar a pensar em "iguais" versus "==". Em primeiro lugar, comparar duas seqüências de caracteres pode ser um procedimento bastante demorado, aumentando os problemas de desempenho mencionados acima. Em segundo lugar, se houver a ativação de strings, haverá uma demanda por ativação de strings ignorando maiúsculas e minúsculas, ativação de strings considerando / ignorando localidade, ativação de strings com base em regex .... Eu aprovaria uma decisão que economizasse muito tempo para o desenvolvedores de idiomas ao custo de uma pequena quantidade de tempo para programadores.
fonte
matched
enot matched
. (Não levando em conta coisas como [chamado] grupos / etc, no entanto..)Além dos bons argumentos acima, acrescentarei que muitas pessoas hoje veem
switch
como um restante obsoleto do passado processual do Java (de volta aos tempos C).Não concordo totalmente com essa opinião, acho que
switch
pode ter sua utilidade em alguns casos, pelo menos por causa de sua velocidade, e de qualquer maneira é melhor do que algumas séries de números numéricos em cascataelse if
que vi em algum código ...Mas, de fato, vale a pena examinar o caso em que você precisa de um switch e ver se ele não pode ser substituído por algo mais OO. Por exemplo, enums em Java 1.5+, talvez HashTable ou alguma outra coleção (em algum momento me arrependo de não termos funções (anônimas) como cidadão de primeira classe, como em Lua - que não possui switch - ou JavaScript) ou mesmo polimorfismo.
fonte
Se você não estiver usando o JDK7 ou superior, poderá usá
hashCode()
-lo para simular. ComoString.hashCode()
geralmente retorna valores diferentes para cadeias diferentes e sempre retorna valores iguais para cadeias iguais, é bastante confiável (cadeias diferentes podem produzir o mesmo código de hash que o @Lii mencionado em um comentário, como"FB"
e"Ea"
) Consulte a documentação .Portanto, o código ficaria assim:
Dessa forma, você está tecnicamente ativando um
int
.Como alternativa, você pode usar o seguinte código:
fonte
case
declarações devam, pensei, sempre sejam valores constantes, eString.hashCode()
não sejam tais (mesmo que, na prática, o cálculo nunca tenha mudado entre as JVMs).case
valores das instruções não precisam ser determináveis no tempo de compilação, para que funcione com precisão.Por anos, usamos um pré-processador (de código aberto) para isso.
Os arquivos pré-processados são nomeados Foo.jpp e são processados no Foo.java com um script ant.
A vantagem é que ele é processado em Java que roda na versão 1.0 (embora normalmente só tenhamos suporte na versão 1.4). Além disso, era muito mais fácil fazer isso (muitas opções de cadeias de caracteres) em comparação com enums ou outras soluções alternativas - o código era muito mais fácil de ler, manter e entender. O IIRC (não é possível fornecer estatísticas ou raciocínio técnico neste momento) também foi mais rápido que os equivalentes naturais de Java.
As desvantagens são que você não está editando Java, por isso é um pouco mais de fluxo de trabalho (editar, processar, compilar / testar), mais um IDE será vinculado ao Java que é um pouco complicado (a opção se torna uma série de etapas lógicas if / else) e a ordem das caixas de comutação não é mantida.
Eu não o recomendaria para a versão 1.7+, mas é útil se você deseja programar o Java direcionado a JVMs anteriores (já que o público de Joe raramente tem a última versão instalada).
Você pode obtê-lo no SVN ou procurar o código online . Você precisará do EBuild para construí-lo como está.
fonte
Outras respostas disseram que isso foi adicionado no Java 7 e deu soluções alternativas para versões anteriores. Esta resposta tenta responder o "porquê"
Java foi uma reação às complexidades excessivas do C ++. Foi projetado para ser uma linguagem simples e limpa.
String teve um pouco de tratamento especial de caso na linguagem, mas parece claro para mim que os designers estavam tentando reduzir ao mínimo a quantidade de invólucro especial e açúcar sintático.
ligar as cordas é bastante complexo sob o capô, pois as cordas não são tipos primitivos simples. Não era um recurso comum no momento em que o Java foi projetado e realmente não se encaixa bem no design minimalista. Especialmente porque eles decidiram não usar o caso especial == para strings, seria (e é) um pouco estranho para o caso trabalhar onde == não.
Entre 1.0 e 1.4, a própria linguagem permaneceu praticamente a mesma. A maioria dos aprimoramentos do Java estava no lado da biblioteca.
Tudo isso mudou com o Java 5, a linguagem foi substancialmente estendida. Outras extensões foram seguidas nas versões 7 e 8. Espero que essa mudança de atitude tenha sido impulsionada pelo aumento do C #
fonte
O JEP 354: Expressões do switch (visualização) no JDK-13 e o JEP 361: Expressões do switch (padrão) no JDK-14 estenderão a instrução switch para que ele possa ser usado como expressão .
Agora você pode:
case L ->
):Portanto, a demonstração das respostas ( 1 , 2 ) pode ficar assim:
fonte
Não é muito bonito, mas aqui está outra maneira para o Java 6 e abaixo:
fonte
É uma brisa no Groovy; Incorporei o groovy jar e criei uma
groovy
classe de utilitário para fazer todas essas coisas e muito mais que acho exasperante em Java (já que estou preso usando o Java 6 na empresa).fonte
Ao usar o intellij, observe também:
Arquivo -> Estrutura do projeto -> Projeto
Arquivo -> Estrutura do Projeto -> Módulos
Quando você possui vários módulos, certifique-se de definir o nível de idioma correto na guia módulo.
fonte
fonte