Usar um array como uma instrução de caso na mudança
eu estou tentando fazer algo assim, isto é, usar um array em uma declaração de switch. É possível em Java? Se não for, por favor explique uma solução possível.
boolean[] values = new boolean[4];
values[0] = true;
values[1] = false;
values[2] = false;
values[3] = true;
switch (values) {
case [true, false, true, false]:
break;
case [false, false, true, false]:
break;
default:
break;
}
15 answers
Não, simplesmente não podes.
SwitchStatement:
switch ( Expression ) SwitchBlock
O tipo da expressão deve ser char, byte, short, int, Character, Byte, Short, Integer, String, or an enum type (§8.9), or a compile-time error occurs.
Http://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.11
@sᴜʀᴇsʜ ᴀᴛᴛᴀ está certo. Mas queria acrescentar uma coisa. Desde o Java 7, switch declarações suporta Strings, então você pode fazer algo com isso. é realmente sujo e eu não recomendo, mas isto funciona:
boolean[] values = new boolean[4];
values[0] = true;
values[1] = false;
values[2] = false;
values[3] = true;
switch (Arrays.toString(values)) {
case "[true, false, true, false]":
break;
case "[false, false, true, false]":
break;
default:
break;
}
Para aqueles preocupados com o desempenho: você está certo, isto não é super rápido. Isto será compilado em algo assim:
String temp = Arrays.toString(values)
int hash = temp.hashCode();
switch (hash)
{
case 0x23fe8da: // Assume this is the hashCode for that
// original string, computed at compile-time
if (temp.equals("[true, false, true, false]"))
{
}
break;
case 0x281ddaa:
if (temp.equals("[false, false, true, false]"))
{
}
break;
default: break;
}
switch
:
switch (values[0] + 2 * values[1] + 4 * values[2] + 8 * values[3])
E usar literais binários nas suas declarações de caso: case 0b0101
é o seu primeiro.
Tenta esta solução:
boolean[] values = new boolean[4];
values[0] = true;
values[1] = false;
values[2] = false;
values[3] = true;
if (ArrayUtils.isEquals(values, new boolean[] {true, false, true, false})) {
...
}
else if (ArrayUtils.isEquals(values, new boolean[] {false, false, true, false})) {
...
}
else {
...
}
Ver docsaqui .
Um array é um arranjo sistemático de objetos, geralmente em linhas e Colunas.
O que você está tentando fazer é implementar um sistema que reconhece diferentes bandeiras e dependendo das bandeiras que estão ligadas ou desligadas você toma diferentes ações.
Exemplo
Uma implementação popular desse mecanismo é o Linux. permissões de ficheiros. Onde você tem rwx
como o "array of flags".
Se toda a matriz for verdadeira, você verá {[[2]}, o que significa que você tem todas as permissões. Se você não estiver autorizado a realizar qualquer ação em um arquivo, todo o array é falso, você verá ---
.
Execução
Adivinha, podes pensar em inteiros como conjuntos. Um inteiro é representado por um"array of bits".001 // 1, if on, set x
010 // 2, if on, set w
100 // 4, if on, set r
// putting it all together in a single "array" (integer)
111 // 2^2 + 2^1 + 2^0 = 4 + 2 + 1 = 7
É por isso que a permissão rwx
pode ser representada como um 7
Excerto de Java:
class Flags {
public static void main(String args[]) {
/**
* Note the notation "0b", for binary; I'm using it for emphasis.
* You could just do:
* byte flags = 6;
*/
byte flags = 0b110; // 6
switch(flags) {
case 0: /* do nothing */ break;
case 3: /* execute and write */ break;
case 6: System.out.println("read and write\n"); break;
case 7: /* grant all permissions */ break;
default:
System.out.println("invalid flag\n");
}
}
}
Para saber mais sobre a utilização de um formato binário, assinale esta pergunta: em Java, posso definir uma constante de inteiro no formato binário?
Desempenho
- Guarda memória
- Você não tem que fazer processamento extra, interruptores ou qualquer outro tipo de malabarismo.
Os programas C que necessitam de ser tão eficientes quanto possível usam este tipo de mecanismo; eles usam bandeiras representadas com bits simples.
Não, você não pode, no entanto você pode substituir o acima com o seguinte código (dirty I admit):
boolean[] values = new boolean[4];
values[0] = true;
values[1] = false;
values[2] = false;
values[3] = true;
switch(makeSuitableForSwitch(values)) {
case 1010:
break;
case 10:
break;
default:
break;
}
private int makeSuitableForSwitch( boolean[] values) {
return (values[0]?1:0)*1000+(values[1]?1:0)*100+(values[2]?1:0)*10+(values[3]?1:0);
}
Se está a tentar determinar se um conjunto de condições é verdadeiro, eu usaria campos bitwise em vez disso.
Por exemplo,
public class HelloWorld
{
// These are the options that can be set.
// They're final so treated as constants.
static final int A=1<<0, B=1<<1, C=1<<2, D=1<<3 ;
public static void main(String []args)
{
// Now I set my options to have A=true, B=true, C=true, D=false, effectively
int options = A | B | C ;
switch( options )
{
case (A):
System.out.println( "just A" ) ;
break ;
case (A|B):
System.out.println( "A|B" ) ;
break ;
case (A|B|C): // Final int is what makes this work
System.out.println( "A|B|C" ) ;
break ;
default:
System.out.println( "unhandled case" ) ;
break ;
}
}
}
Eu calcularia um valor baseado na sequência dos elementos na matriz booleana, ou seja [true, false, true, true]
iria avaliar para 1011 e então com base neste valor inteiro você pode usar a declaração de switch.
A partir de JRE 1.7, você vai precisar de usar um hack, eu recomendo:
Assumir
values.length <= 64
Converter os valores para um
long
representando bitflags
Hack De Código Java:
if(values.length > 64)
throw new IllegalStateException();
long bitflags = 0x0L;
for(int i=0; i< values.length; ++i)
if(values[i])
bitflags |= 0x01L << i;
switch(bitflags) {
case 0xEL: // represents [true, true, true, false]
break;
case 0xAL: // represents [true, false, true, false]
break;
case 0x2L: // represents [false, false, true, false]
break;
default:
break;
}
boolean[] values = new boolean[4];
values[0] = true;
values[1] = false;
values[2] = false;
values[3] = true;
int mask = buildMask(values);
if (areEquals(mask, true, false, true, false)) {
// ...
} else if (areEquals(mask, false, false, true, false)) {
// ...
} else {
// ...
}
private int buildMask(boolean... values) {
int n = 0;
for (boolean b : values) {
n = (n << 1) | (b ? 1 : 0);
}
return n;
}
private boolean areEquals(int mask, boolean... values) {
return mask == buildMask(values);
}
Criei uma demo que compila Javascript e Flash. Você pode ver o js-output na coluna direita.Esta resposta não é Java , mas Haxe porque é possível nela, graças à correspondência de padrões e tem uma saída interessante, o que pode ser útil para você encontrar um interruptor que faça o que você está pedindo. Arrays podem ser combinados em comprimento fixo.
Demo: http://try.haxe.org/#86314
class Test {
static function main(){
var array=[true,false,true];
var result=switch(array){
case [true,true,false]: "no";
case [true,false,true]: "yes";
default:"??";
}
#if js
new js.JQuery("body").html(result);
#elseif flash
trace(result);
#end
// ouputs: "yes"
}
}
Este é o ... Interruptor avançado, usa interruptores aninhados. Se você jogar com os casos, você vê como o js-ouput muda para ter um interruptor eficiente.
(function () { "use strict";
var Test = function() { };
Test.main = function() {
var array = [true,false,true,false];
var result;
switch(array.length) {
case 4:
switch(array[0]) {
case true:
switch(array[1]) {
case false:
switch(array[2]) {
case true:
switch(array[3]) {
case false:
result = "no";
break;
default:
result = "??";
}
break;
default:
result = "??";
}
break;
default:
result = "??";
}
break;
case false:
switch(array[1]) {
case false:
switch(array[2]) {
case true:
switch(array[3]) {
case false:
result = "yes";
break;
default:
result = "??";
}
break;
default:
result = "??";
}
break;
default:
result = "??";
}
break;
}
break;
default:
result = "??";
}
new js.JQuery("body").html(result);
};
var js = {};
var q = window.jQuery;
js.JQuery = q;
Test.main();
})();
Outro padrão interessante que pode usar sobscores. um _ padrão corresponde a qualquer coisa, por isso o caso _: é igual ao padrão, o que o torna capaz de fazer isto:
var myArray = [1, 6];
var match = switch(myArray) {
case [2, _]: "0";
case [_, 6]: "1";
case []: "2";
case [_, _, _]: "3";
case _: "4";
}
trace(match); // 1
Você também pode dar uma olhada em como Groovy implementa os métodos isCase () em Java, usar uma versão mais simples que se encaixa às suas necessidades. É possível colocar isso em uma interface e criar um DSL para comparar qualquer dois objetos em sua aplicação.
return isCase(DefaultTypeTransformation.asCollection(caseValue), switchValue);
O código relevante é coberto pelas linhas das linhas 877 até . 982
@Todor Sim, isto é possível em JAVA.
boolean[] values = new boolean[4];
values[0] = true;
values[1] = false;
values[2] = false;
values[3] = true;
values = Arrays.toString(values)
switch (values) {
case "[true, false, true, false]":
break;
case "[false, false, true, false]":
break;
case "[true, false, false, true]":
System.out.println("YAAAAAAAAAA GOT IT");
break;
default:
break;
}
Nota: não sou um programador java, por isso a minha sintaxe de código pode estar errada, mas a lógica é perfeita. Podes editar a minha resposta. Aqui Eu apenas tentei converter array para o formato string e, em seguida, corresponder no caso switch.
Se usar Java 1, 7 ou acima, poderá usar literais binários que sejam mais legíveis.
public static final int TRUE_FALSE_TRUE_FALSE = 0b1010;
public static final int FALSE_FALSE_TRUE_FALSE = 0b0010;
Para Java 1.6 e abaixo usar qualquer outro int literais, por exemplo hex
public static final int TRUE_FALSE_TRUE_FALSE = 0xA;
public static final int FALSE_FALSE_TRUE_FALSE = 0x2;
Em seguida, criar um método que converte um array booleano para um conjunto de bits inteiro. Por exemplo
public static int toIntBitSet(boolean...values){
int bitset = 0;
for (boolean value : values) {
bitset = (bitset << 1) | (value ? 1 : 0);
}
return bitset;
}
Finalmente use as constantes na sua declaração de mudança
boolean[] values = new boolean[]{true, false, true, false};
int bitset = toIntBitSet(values);
switch (bitset) {
case TRUE_FALSE_TRUE_FALSE:
System.out.println(Integer.toBinaryString(bitset));
break;
case FALSE_FALSE_TRUE_FALSE:
System.out.println(Integer.toBinaryString(bitset));
break;
default:
break;
}
Outro approach May Be to use a java BitSet
and a Map
that maps to the logic that should be executed depending on the bitset value.
public static void main(String[] args) throws Exception {
Map<BitSet, Callable<String>> bitSetMap = new HashMap<>();
bitSetMap.put(bitSetValueOf(true, false, true, false), new TrueFalseTrueFalseCallable());
bitSetMap.put(bitSetValueOf(false, false, true, false), new FalseFalseTrueFalseCallable());
boolean[] values = new boolean[]{true, false, true, false};
BitSet bitset = bitSetValueOf(values);
Callable<String> callable = bitSetMap.get(bitset);
if (callable == null) {
callable = new DefaultCallable();
}
String result = callable.call();
System.out.println(result);
}
public static BitSet bitSetValueOf(boolean... values) {
BitSet bitSet = new BitSet();
for (int i = 0; i < values.length; i++) {
bitSet.set(i, values[i]);
}
return bitSet;
}
E implementar a sua lógica
class FalseFalseTrueFalseCallable implements Callable<String> {
@Override
public String call() throws Exception {
return "0010";
}
}
class TrueFalseTrueFalseCallable implements Callable<String> {
@Override
public String call() throws Exception {
return "1010";
}
}
class DefaultCallable implements Callable<String> {
@Override
public String call() throws Exception {
return "default value";
}
}