Используйте массив в качестве оператора case в switch
Я пытаюсь сделать что-то подобное, т. е. использовать массив в операторе switch. Возможно ли это в Java? Если это не так, пожалуйста, объясните возможное решение.
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 ответов:
нет, просто невозможно.
SwitchStatement: switch ( Expression ) SwitchBlock
тип выражения должен быть char, byte, short, int, Character, Byte, Short, Integer, String или enum type (§8.9), или происходит ошибка времени компиляции.
http://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.11
@sᴜʀᴇsʜ ᴀᴛᴛᴀ прав. Но я хотел кое-что добавить. Начиная с Java 7, операторы switch поддерживают строки, поэтому вы можете что-то сделать с этим. Это очень грязно и я не рекомендую, но это работает:
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; }
для тех, кто обеспокоен производительностью: вы правы, это не очень быстро. Это будет скомпилировано в нечто вроде этого:
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 (values[0] + 2 * values[1] + 4 * values[2] + 8 * values[3])
и использовать двоичные литералы в вашем случае высказываний:
case 0b0101
это ваш первый.
попробуйте это решение:
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 { ... }
см. docs здесь.
Да, вы можете передать массив коммутатору. Загвоздка в том, что я говорю не о массивах Java, а о структуре данных.
массив-это систематическое расположение объектов, обычно в строках и столбцах.
то, что вы пытаетесь сделать, это реализовать систему, которая распознает разные флаги и в зависимости от флагов, которые включены или выключены, вы выполняете разные действия.
пример
популярное реализация такого механизма-это права доступа к файлам Linux. Где у тебя
rwx
как "множество флагов".если весь массив истинен, вы увидите
rwx
, это означает, что у вас есть все разрешения. Если вам не разрешено выполнять какие-либо действия с файлом, весь массив имеет значение false, вы увидите---
.реализация
угадайте, что вы можете думать о целых числах как массивы. Целое число представлено " массивом биты."
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
вот почему разрешение
rwx
можно представить как7
фрагмент 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"); } } }
чтобы узнать больше об использовании двоичного формата, проверить этот вопрос: в Java можно ли определить целочисленную константу в двоичном формате?
производительность
- экономия
- вам не нужно делать дополнительную обработку, переключатели или любой другой тип жонглирование.
C программы, которые должны быть максимально эффективными, используют этот тип механизма; они используют флаги, представленные одиночными битами.
нет, вы не можете, однако вы можете заменить выше с помощью следующего (грязный я признаю) код:
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); }
Если вы пытаетесь определить, является ли условия верно, я бы использовал побитовые поля вместо этого.
например,
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 ; } } }
Я бы вычислял значение на основе последовательности элементов в логическом массиве, т. е.
[true, false, true, true]
будет вычисляться до 1011, а затем на основе этого целочисленного значения вы можете использовать оператор switch.
ответ-нет. Лучше всего объяснить, как использовать оператор switch.
начиная с JRE 1.7, вам нужно будет использовать Хак, я рекомендую:
предположим
values.length <= 64
преобразование значений в
long
представляя bitflags
Switch
против шестнадцатеричном магия чиселJava Code Hack:
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); }
ответ не Java, но Haxe, потому что это возможно в нем, благодаря сопоставлению шаблонов и имеет интересный вывод, который может быть полезен для вас, чтобы найти переключатель, который делает то, что вы просите. Массивы могут быть сопоставлены по фиксированной длине.
Я создал демо, которое компилируется на Javascript и Flash. Вы можете увидеть JS-выход в правой колонке.
демо: 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" } }
это выходной коммутатор, он использует вложенные коммутаторы. Если вы играете с корпусами, вы видите, как JS-ouput изменяется, чтобы иметь эффективный переключатель.
(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(); })();
еще один интересный шаблон, который вы можете использовать подчеркивание. в _ образец все матчи, поэтому дело _: равна по умолчанию, которая заставляет вас в состоянии сделать это:
var myArray = [1, 6]; var match = switch(myArray) { case [2, _]: "0"; case [_, 6]: "1"; case []: "2"; case [_, _, _]: "3"; case _: "4"; } trace(match); // 1
вы также можете взглянуть на то, как Groovy реализует методы isCase() в Java, используйте более простую версию, которая соответствует вашим потребностям. Можно поместить это в интерфейс и создать DSL для сравнения любых двух объектов в вашем приложении.
return isCase(DefaultTypeTransformation.asCollection(caseValue), switchValue);
соответствующий код описан в строки 877 через строки 982
@Todor Да, это возможно в 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; }
примечание: Я не разработчик java, поэтому мой синтаксис кода может быть неправильным, но логика совершенна. Вы можете отредактировать мой ответ. Здесь я просто попытался преобразовать массив в строковый формат, а затем сопоставить в случае коммутатора.
Я бы использовал постоянные значения int, которые представляют логическое состояние.
если вы используете Java 1.7 или выше вы можете использовать двоичные литералы, которые являются более читабельным.
public static final int TRUE_FALSE_TRUE_FALSE = 0b1010; public static final int FALSE_FALSE_TRUE_FALSE = 0b0010;
на Java 1.6 и ниже используйте любые другие литералы int, например hex
public static final int TRUE_FALSE_TRUE_FALSE = 0xA; public static final int FALSE_FALSE_TRUE_FALSE = 0x2;
затем создайте метод, который преобразует логический массив в целочисленный битовый набор. Е. Г.
public static int toIntBitSet(boolean...values){ int bitset = 0; for (boolean value : values) { bitset = (bitset << 1) | (value ? 1 : 0); } return bitset; }
наконец используйте константы в вашем коммутаторе заявление
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; }
другой подход может быть использовать Java
BitSet
иMap
, что соответствует логике, которая должна выполняться в зависимости от значения bitset это.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; }
и реализовать свою логику
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"; } }