Muitos livros de Java descrevem a switch
instrução como sendo mais rápida do que a if else
instrução. Mas eu não descobri em lugar nenhum porque o switch é mais rápido do que se .
Exemplo
Eu tenho uma situação em que tenho que escolher qualquer um dos dois itens. Eu posso usar qualquer um
switch (item) {
case BREAD:
//eat Bread
break;
default:
//leave the restaurant
}
ou
if (item == BREAD) {
//eat Bread
} else {
//leave the restaurant
}
considerando item e BREAD é um valor int constante.
No exemplo acima, qual ação é mais rápida e por quê?
java
switch-statement
Jacob van Lingen
fonte
fonte
Respostas:
Porque existem bytecodes especiais que permitem uma avaliação eficiente da instrução switch quando há muitos casos.
Se implementado com instruções IF, você teria uma verificação, um salto para a próxima cláusula, uma verificação, um salto para a próxima cláusula e assim por diante. Com switch, a JVM carrega o valor a ser comparado e itera por meio da tabela de valores para encontrar uma correspondência, o que é mais rápido na maioria dos casos.
fonte
switch
não pode ser traduzido em umatableswitch
instrução bytecode - pode se tornar umalookupswitch
instrução que executa de forma semelhante a um if / else (ii) até mesmotableswitch
instruções de bytecode podem ser compiladas em uma série de if / else pelo JIT, dependendo dos fatores como o número decase
s.tableswitch
vsloopuswitch
: stackoverflow.com/questions/10287700/…Uma
switch
declaração nem sempre é mais rápida do que umaif
declaração. Escala melhor do que uma longa lista deif-else
instruções, poisswitch
pode realizar uma pesquisa com base em todos os valores. No entanto, para uma condição curta, não será mais rápido e pode ser mais lento.fonte
switch
seriam mais claras, senão mais rápidas.A JVM atual tem dois tipos de códigos de byte de switch: LookupSwitch e TableSwitch.
Cada caso em uma instrução switch tem um deslocamento inteiro, se esses deslocamentos são contíguos (ou principalmente contíguos sem grandes lacunas) (caso 0: caso 1: caso 2, etc.), então TableSwitch é usado.
Se os deslocamentos estiverem espalhados com grandes lacunas (caso 0: caso 400: caso 93748 :, etc.), então LookupSwitch é usado.
A diferença, em resumo, é que TableSwitch é feito em tempo constante porque cada valor dentro da faixa de valores possíveis recebe um deslocamento de código de byte específico. Portanto, quando você atribui à instrução um deslocamento de 3, ela sabe pular 3 para encontrar o branch correto.
O switch de pesquisa usa uma pesquisa binária para encontrar a ramificação de código correta. Isso é executado em tempo O (log n), que ainda é bom, mas não é o melhor.
Para obter mais informações sobre isso, consulte aqui: Diferença entre LookupSwitch e TableSwitch da JVM?
Portanto, quanto a qual é o mais rápido, use esta abordagem: Se você tiver 3 ou mais casos cujos valores são consecutivos ou quase consecutivos, sempre use um switch.
Se você tiver 2 casos, use uma instrução if.
Para qualquer outra situação, a troca é provavelmente mais rápida, mas não é garantida, uma vez que a pesquisa binária em LookupSwitch pode atingir um cenário ruim.
Além disso, lembre-se de que a JVM executará otimizações JIT nas instruções if que tentarão colocar primeiro o branch mais ativo no código. Isso é chamado de "Previsão de Branch". Para obter mais informações sobre isso, consulte aqui: https://dzone.com/articles/branch-prediction-in-java
Suas experiências podem variar. Não sei se a JVM não executa uma otimização semelhante no LookupSwitch, mas aprendi a confiar nas otimizações JIT e a não tentar ser mais esperto que o compilador.
fonte
switch
um recurso de linguagem ainda mais poderoso. A correspondência de padrões, por exemplo, permitiráinstanceof
pesquisas muito mais suaves e de desempenho . No entanto, acho que é seguro presumir que, para cenários switch / if básicos, a regra que mencionei ainda se aplicará.Portanto, se você planeja ter muitos pacotes, a memória não é realmente um grande custo atualmente e os arrays são muito rápidos. Você também não pode confiar em uma instrução switch para gerar automaticamente uma tabela de salto e, como tal, é mais fácil gerar você mesmo o cenário da tabela de salto. Como você pode ver no exemplo abaixo, assumimos um máximo de 255 pacotes.
Para obter o resultado abaixo, você precisa de abstração ... Não vou explicar como isso funciona, então espero que você tenha uma compreensão disso.
Eu atualizei isso para definir o tamanho do pacote para 255 se você precisar de mais do que você terá que fazer uma verificação de limites para (id <0) || (id> comprimento).
Edite, já que eu uso muito uma tabela de salto em C ++, agora vou mostrar um exemplo de uma tabela de salto de ponteiro de função. Este é um exemplo muito genérico, mas eu o executei e ele funciona corretamente. Lembre-se de que você deve definir o ponteiro como NULL, C ++ não fará isso automaticamente como em Java.
Outro ponto que gostaria de mencionar é o famoso Divide and Conquer. Portanto, minha ideia de array acima de 255 poderia ser reduzida a não mais de 8 declarações if como o pior cenário.
Ou seja, mas tenha em mente que fica confuso e difícil de gerenciar rapidamente e minha outra abordagem é geralmente melhor, mas isso é utilizado em casos em que os arrays simplesmente não funcionam. Você precisa descobrir seu caso de uso e quando cada situação funciona melhor. Assim como você não gostaria de usar nenhuma dessas abordagens se tivesse apenas algumas verificações.
fonte
0 <= id < packets.length
e garantirpackets[id]!=null
e depois fazerpackets[id].execute(data)
?No nível do bytecode, a variável de assunto é carregada apenas uma vez no registro do processador a partir de um endereço de memória no arquivo .class estruturado carregado pelo Runtime, e isso está em uma instrução switch; enquanto em uma instrução if, uma instrução jvm diferente é produzida por seu DE compilador de código, e isso requer que cada variável seja carregada em registradores, embora a mesma variável seja usada como na instrução if anterior seguinte. Se você conhece a codificação em linguagem assembly, isso seria lugar-comum; embora os coxes compilados em java não sejam bytecode, ou código de máquina direto, o conceito condicional deste ainda é consistente. Bem, tentei evitar detalhes técnicos mais profundos ao explicar. Espero ter deixado o conceito claro e desmistificado. Obrigado.
fonte