Por que mudar é mais rápido do que se

Eu encontrei muitos livros em java dizendo que a instrução switch é mais rápida do que se afirmação else. Mas eu não encontrei o antwhere dizendo porque o switch é mais rápido que se .

Exemplo

Eu tenho uma situação que eu tenho que escolher qualquer um dos dois itens que eu posso usar qualquer um dos seguintes maneira

switch(item){ case BREAD: //eat Bread break; default: //leave the restaurant } 

ou usando se declaração como o seguinte

 if(item== BREAD){ //eat Bread }else{ //leave the restaurant } 

considerando o item e o pão é constante valor int

No exemplo acima, que é mais rápido em ação e por quê?

Porque existem códigos de bytes 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 o switch, a JVM carrega o valor para comparar e percorre a tabela de valores para encontrar uma correspondência, que é mais rápida na maioria dos casos.

Uma instrução switch nem sempre é mais rápida que uma instrução if . Ele é dimensionado melhor que uma longa lista de instruções if-else , pois o switch pode realizar uma pesquisa com base em todos os valores. No entanto, por um curto período, não será mais rápido e poderá ser mais lento.

A JVM atual possui dois tipos de códigos de byte de comutador: LookupSwitch e TableSwitch.

Cada caso em uma instrução switch possui um deslocamento inteiro, se esses deslocamentos forem contíguos (ou na maior parte contíguos sem grandes lacunas) (case 0: case 1: case 2, etc.), então TableSwitch é usado.

Se os deslocamentos estão espalhados com grandes lacunas (caso 0: case 400: case 93748 :, etc.), então LookupSwitch é usado.

A diferença, em suma, é que TableSwitch é feito em tempo constante, porque cada valor dentro do intervalo de valores possíveis é dado um deslocamento de código de byte específico. Assim, quando você dá à instrução um deslocamento de 3, ela sabe avançar 3 para encontrar a ramificação correta.

Interruptor de pesquisa usa uma pesquisa binária para localizar o ramo de código correto. Isso é executado no tempo O (log n), que ainda é bom, mas não é o melhor.

Para obter mais informações sobre isso, consulte: Diferença entre o LookupSwitch da JVM e o TableSwitch?

Portanto, na medida em que é mais rápido, use esta abordagem: Se você tem 3 ou mais casos cujos valores são consecutivos ou quase consecutivos, sempre use um switch.

Se você tiver dois casos, use uma instrução if.

Para qualquer outra situação, é mais provável que o switch seja mais rápido, mas não é garantido, já que a pesquisa binária no LookupSwitch pode atingir um cenário ruim.

Além disso, lembre-se de que a JVM executará as otimizações JIT em instruções if que tentarão colocar a ramificação mais ativa primeiro no código. Isso é chamado de “Predição de Ramificação”. Para mais informações sobre isso, veja 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 do JIT e não tentar enganar o compilador.

No nível do bytecode, a variável subject é carregada apenas uma vez no registrador do processador a partir de um endereço de memory no arquivo .class estruturado carregado pelo Runtime, e isso está em uma instrução switch; enquanto que 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 para registradores, embora a mesma variável seja usada como na instrução if precedente seguinte. Se você souber codificar em linguagem assembly, isso seria comum; embora coxes compilados em java não sejam bytecode, ou código de máquina direto, o conceito condicional deste documento ainda é consistente. Bem, tentei evitar detalhes técnicos ao explicar. Espero ter tornado o conceito claro e desmistificado. Obrigado.

Se você estiver executando uma quantidade insana de verificações como 100+, convém considerar alguma abstração.

Você tem pacotes de input que variam de ids 0 a 255. Você usa talvez 150 deles. Você pode querer considerar algo como o abaixo, em vez de um switch de 150 ids.

 Packets[] packets = new Packets[150]; static { packets[0] = new Login(); packets[2] = new Logout(); packets[3] = new GetMessage(); packets[7] = new AddFriend(); packets[9] = new JoinGroupChat(); // etc... not going to finish. } static final byte[] INDEX_LIST = { 0, 2, 3, 7, 9, // etc... Not going to do it, but this will convert packet id to index. }; public void handlePacket(IncomingData data) { int id = data.readByte(); packets[INDEX_LIST[id]].execute(data); } 

Também devo salientar que a lista de índices não é realmente necessária e, provavelmente, diminuiria o código de qualquer maneira. Foi apenas uma sugestão para que você não tenha lugares vazios. Também para não mencionar é esta situação que você está perdendo apenas de 106 índices. Eu não tenho 100% de certeza, mas acredito que cada um deles está apontando para null de qualquer maneira, portanto, nenhum problema de memory real estaria presente.