using an array for a switch case statement in java - java

I'm making a game, and i want the controls to be editable. well, i've got that part down, but they are being read and changed in a .txt file. that is the way i wanted it to work for now. the values are stored as the key value (ie. KeyEvent.VK_W is equal to 83, so the value for the line is 83). I also have it reading the values and saving them to a String array variable in my core class. In my key event class, the one that handles the pushing of the keys, i have it refering to the array to check if a command key was pushed. i'm continuously getting this error: case expressions must be constant expressions when i try it. here is the WRONG code:
switch(key){
case Integer.parseInt(commands[1]):
...
break;
}
and i get that error. the value of commands[1] is 83. it is the value for "W". here is my declaration of the variable:
for (int i = 0; i < commands.length; i++) {
commands[i] = io.readSpecificLine(FILES.controlsFileFinalDir,
i + 1);
}
and if i have it print out every value, it does work. i've tried making the array final but that didnt work. i've run across the solution before, about 2 years ago, but i cant find it again. does anyone have any ideas on how to fix this? thanks in advance!

As the compiler says, the case expressions must be constant expressions. You can't use an array element as a case expression. You can simply use an if/else if/else clause instead.

You can't use non-constant expressions in case statements. An alternative approach is to build a map from values to the actions. So instead of this (which doesn't actually make any sense to me):
switch (key) {
case Integer.parseInt(commands[1]):
// action 1
break;
// other cases...
default:
// default action
}
You can do something like this:
static Map<Integer, Runnable> keyMap = new HashMap<Integer, Runnable>();
static {
keyMap.put(83, new Runnable() {
#Override
public void run() {
// actions for code 83
}
});
. . .
}
(If it makes more sense, this could also be done on a per-instance basis instead of as a static map.) Then later:
Runnable action = keyMap.get(Integer.parseInt(commands[1]));
if (action != null) {
action.run();
} else {
// default action
}
If you need to pass variables to your actions, you can define your own interface instead of using Runnable for the actions.

Related

How to use a switch case in test cases without passing values to switch() method [duplicate]

I've looked at various Q&As on SO similar to this question but haven't found a solution.
What I have is an enum which represents different ways to view a TV Guide...
In the NDroid Application class
static enum guideView {
GUIDE_VIEW_SEVEN_DAY,
GUIDE_VIEW_NOW_SHOWING,
GUIDE_VIEW_ALL_TIMESLOTS
}
...when the user changes the view an event handler receives an int from 0-2 and I'd like to do something like this...
In an Android Activity onClick(DialogInterface dialog, int which) event handler
// 'which' is an int from 0-2
switch (which) {
case NDroid.guideView.GUIDE_VIEW_SEVEN_DAY:
...
break;
}
I'm used to C# enums and select/case statements which would allow something like the above and I know Java does things differently but I just can't make sense of what I need to do.
Am I going to have to resort to if statements? There will likely only ever be 3 choices so I could do it but I wondered how it could be done with switch-case in Java.
EDIT Sorry I didn't completely expand on the issue as I was looking at it as being a generic Java issue. I've added to the question to explain a bit further.
There isn't anything that's Android specific which is why I didn't tag it as Android but the enum is defined in the Application class and the code where I wan't the switch is in an Activity. The enum is static as I need to access it from multiple Activities.
The part you're missing is converting from the integer to the type-safe enum. Java will not do it automatically. There's a couple of ways you can go about this:
Use a list of static final ints rather than a type-safe enum and switch on the int value you receive (this is the pre-Java 5 approach)
Switch on either a specified id value (as described by heneryville) or the ordinal value of the enum values; i.e. guideView.GUIDE_VIEW_SEVEN_DAY.ordinal()
Determine the enum value represented by the int value and then switch on the enum value.
enum GuideView {
SEVEN_DAY,
NOW_SHOWING,
ALL_TIMESLOTS
}
// Working on the assumption that your int value is
// the ordinal value of the items in your enum
public void onClick(DialogInterface dialog, int which) {
// do your own bounds checking
GuideView whichView = GuideView.values()[which];
switch (whichView) {
case SEVEN_DAY:
...
break;
case NOW_SHOWING:
...
break;
}
}
You may find it more helpful / less error prone to write a custom valueOf implementation that takes your integer values as an argument to resolve the appropriate enum value and lets you centralize your bounds checking.
If whichView is an object of the GuideView Enum, following works well. Please note that there is no qualifier for the constant after case.
switch (whichView) {
case SEVEN_DAY:
...
break;
case NOW_SHOWING:
...
break;
}
The enums should not be qualified within the case label like what you have NDroid.guideView.GUIDE_VIEW_SEVEN_DAY, instead you should remove the qualification and use GUIDE_VIEW_SEVEN_DAY
I like a few usages of Java enum:
.name() allows you to fetch the enum name in String.
.ordinal() allow you to get the integer value, 0-based.
You can attach other value parameters with each enum.
and, of course, switch enabled.
enum with value parameters:
enum StateEnum {
UNDEFINED_POLL ( 1 * 1000L, 4 * 1000L),
SUPPORT_POLL ( 1 * 1000L, 5 * 1000L),
FAST_POLL ( 2 * 1000L, 4 * 60 * 1000L),
NO_POLL ( 1 * 1000L, 6 * 1000L);
...
}
switch example:
private void queuePoll(StateEnum se) {
// debug print se.name() if needed
switch (se) {
case UNDEFINED_POLL:
...
break;
case SUPPORT_POLL:
...
break;
This should work in the way that you describe. What error are you getting? If you could pastebin your code that would help.
http://download.oracle.com/javase/tutorial/java/javaOO/enum.html
EDIT: Are you sure you want to define a static enum? That doesn't sound right to me. An enum is much like any other object. If your code compiles and runs but gives incorrect results, this would probably be why.
Short associative function example:
public String getIcon(TipoNotificacao tipo)
{
switch (tipo){
case Comentou : return "fa fa-comments";
case ConviteEnviou : return "icon-envelope";
case ConviteAceitou : return "fa fa-bolt";
default: return "";
}
}
Like #Dhanushka said, omit the qualifier inside "switch" is the key.
enumerations accessing is very simple in switch case
private TYPE currentView;
//declaration of enum
public enum TYPE {
FIRST, SECOND, THIRD
};
//handling in switch case
switch (getCurrentView())
{
case FIRST:
break;
case SECOND:
break;
case THIRD:
break;
}
//getter and setter of the enum
public void setCurrentView(TYPE currentView) {
this.currentView = currentView;
}
public TYPE getCurrentView() {
return currentView;
}
//usage of setting the enum
setCurrentView(TYPE.FIRST);
avoid the accessing of TYPE.FIRST.ordinal() it is not recommended always
I am doing it like
public enum State
{
// Retrieving, // the MediaRetriever is retrieving music //
Stopped, // media player is stopped and not prepared to play
Preparing, // media player is preparing...
Playing, // playback active (media player ready!). (but the media player
// may actually be
// paused in this state if we don't have audio focus. But we
// stay in this state
// so that we know we have to resume playback once we get
// focus back)
Paused; // playback paused (media player ready!)
//public final static State[] vals = State.values();//copy the values(), calling values() clones the array
};
public State getState()
{
return mState;
}
And use in Switch Statement
switch (mService.getState())
{
case Stopped:
case Paused:
playPause.setBackgroundResource(R.drawable.selplay);
break;
case Preparing:
case Playing:
playPause.setBackgroundResource(R.drawable.selpause);
break;
}

is there way to select everything from a list of model?

asnafList is my list and getIc_number is my getter below is my code
asnafList.get(0).getIc_number();
I am trying to make sort of an authenticating feature for my apps and I use the above code in my if statement for the button. That code only get the 0 position of the list. So my question is, is there a way to get all of the position is the list to compare with the input from the user using the if statement?
int number;
for(int i = 0; i < asnafList.size(); i++) {
number = asnafList.get(i).getIc_number();
if(number == YOUR_COMPARABLE_NUMBER) {
// Compare and do anything here
}
}
As Kushal answered, a for loop is useful for this. But I usually use a for each loop in this scenario. Not sure what type of objects are in the asnafList, but it will look something like this:
for(AsnafObject a : asnafList) {
if(a.getIc_number() == YOUR_COMPARABLE_NUMBER) {
// do stuff
}
}
When you do this for loop, you basically iterate through every object in the asnafList, where AsnafObject is the classtype of your asnafList and a is the object which you can use to call any non-static methods of AsnafObject (or however your class is called)

What keywords should I use in a for-loop when using if-statements?

Let's assume that we have a for-loop that will loop through a collection or array of Strings. In that case, I am searching for a specific keyword (ex. hey) here's how I usually achieve that:
for (String result : strings)
{
if (result == "hey")
{
// Do something with that.
break;
}
}
Now, the question arises from that code snippet is, should I place a keyword (return or break) when the if-statement returns true so the loop will not continue? If not, what will happen and what's the correct way of going about it.
Edit: What happens when you use break and return? What's the difference?
Let's put your code inside a method:
private void foo()
{
for (String result : strings)
{
if (result.equals("hey"))
{
// Do something with that.
break;
}
}
bar();
}
If you use break;, the loop will terminate and bar will be reached. If you use return, the method will terminate and bar won't be executed.
Note that comparing strings should be done using equals, == compares references and not content.
If you know the word can only be found once you can surely place an break; statement so the loop won't continue after finding the match.
If you can have more than one match and you want the if block to be executed for each of those matches you should NOT put the break statement since it will stop the execution of the loop after the first match is found.

Parsing field access flags in java

I have an assignment wherein I have to parse the field access flags of a java .class file.
The specification for a .class file can be found here: Class File Format (page 26 & 27 have the access flags and hex vals).
This is fine, I can do this no worries.
My issue is that there is a large number of combinations.
I know the public, private and protected are mutually exclusive, which reduces the combinations somewhat. Final and transient are also mutually exclusive. The rest however are not.
At the moment, I have a large switch statement to do the comparison. I read in the hex value of the access flag and then increment a counter, depending on if it is public, private or protected. This works fine, but it seems quite messy to just have every combination listed in a switch statement. i.e. public static, public final, public static final, etc.
I thought of doing modulo on the access flag and the appropriate hex value for public, private or protected, but public is 0x0001, so that won't work.
Does anyone else have any ideas as to how I could reduce the amount of cases in my switch statement?
What is the problem? The specification says that it's a bit flag, that means that you should look at a value as a binary number, and that you can test if a specific value is set by doing a bitwise AND.
E.g
/*
ACC_VOLATILE = 0x0040 = 10000000
ACC_PUBLIC = 0x0001 = 00000001
Public and volatile is= 10000001
*/
publicCount += flag & ACC_PUBLIC > 0 ? 1 : 0;
volatileCount += flag & ACC_VOLATILE > 0 ? 1 : 0;
If you are trying to avoid a pattern like this one I just stole:
if (access_flag & ACC_PUBLIC != 0)
{
public++;
}
if (access_flag & ACC_FINAL != 0)
{
final++;
}
...
It's a great instinct. I make it a rule never to write code that looks redundant like that. Not only is it error-prone and more code in your class, but copy & paste code is really boring to write.
So the big trick is to make this access "Generic" and easy to understand from the calling class--pull out all the repeated crap and just leave "meat", push the complexity to the generic routine.
So an easy way to call a method would be something like this that gives an array of bitfields that contain many bit combinations that need counted and a list of fields that you are interested in (so that you don't waste time testing fields you don't care about):
int[] counts = sumUpBits(arrayOfFlagBitfields, ACC_PUBLIC | ACC_FINAL | ACC_...);
That's really clean, but then how do you access the return fields? I was originally thinking something like this:
System.out.println("Number of public classes="+counts[findBitPosition(ACC_PUBLIC]));
System.out.println("Number of final classes="+counts[findBitPosition(ACC_FINAL)]);
Most of the boilerplate here is gone except the need to change the bitfields to their position. I think two changes might make it better--encapsulate it in a class and use a hash to track positions so that you don't have to convert bitPosition all the time (if you prefer not to use the hash, findBitPosition is at the end).
Let's try a full-fledged class. How should this look from the caller's point of view?
BitSummer bitSums=new BitSummer(arrayOfFlagBitfields, ACC_PUBLIC, ACC_FINAL);
System.out.println("Number of public classes="+bitSums.getCount(ACC_PUBLIC));
System.out.println("Number of final classes="+bitSums.getCount(ACC_FINAL));
That's pretty clean and easy--I really love OO! Now you just use the bitSums to store your values until they are needed (It's less boilerplate than storing them in class variables and more clear than using an array or a collection)
So now to code the class. Note that the constructor uses variable arguments now--less surprise/more conventional and makes more sense for the hash implementation.
By the way, I know this seems like it would be slow and inefficient, but it's probably not bad for most uses--if it is, it can be improved, but this should be much shorter and less redundant than the switch statement (which is really the same as this, just unrolled--however this one uses a hash & autoboxing which will incur an additional penalty).
public class BitSummer {
// sums will store the "sum" as <flag, count>
private final HashMap<Integer, Integer> sums=new HashMap<Integer, Integer>();
// Constructor does all the work, the rest is just an easy lookup.
public BitSummer(int[] arrayOfFlagBitfields, int ... positionsToCount) {
// Loop over each bitfield we want to count
for(int bitfield : arrayOfFlagBitfields) {
// and over each flag to check
for(int flag : positionsToCount) {
// Test to see if we actually should count this bitfield as having the flag set
if((bitfield & flag) != 0) {
sums.put(flag, sums.get(flag) +1); // Increment value
}
}
}
}
// Return the count for a given bit position
public int getCount(int bit) {
return sums.get(bit);
}
}
I didn't test this but I think it's fairly close. I wouldn't use it for processing video packets in realtime or anything, but for most purposes it should be fast enough.
As for maintaining code may look "Long" compared to the original example but if you have more than 5 or 6 fields to check, this will actually be a shorter solution than the chained if statements and significantly less error/prone and more maintainable--also more interesting to write.
If you really feel the need to eliminate the hashtable you could easily replace it with a sparse array with the flag position as the index (for instance the count of a flag 00001000/0x08 would be stored in the fourth array position). This would require a function like this to calculate the bit position for array access (both storing in the array and retrieving)
private int findBitPosition(int flag) {
int ret;
while( ( flag << 1 ) != 0 )
ret++;
return ret;
}
That was fun.
I'm not sure that's what you're looking for, but I would use if-cases with binary AND to check if a flag is set:
if (access_flag & ACC_PUBLIC != 0)
{
// class is public
}
if (access_flag & ACC_FINAL != 0)
{
// class is final
}
....

Can I check the iteration variable to know if a foreach loop ran until the end Java?

In Java, I want to go through a list of elements and insert a new one at the right place. I was thinking of doing it in this way:
for( Tab tab : tabList )
if( newTab.getPriority() < tab.getPriority() ) {
newTab.insertBefore(tab);
break;
}
if( tab == null )
newTab.insertBefore(endMarker);
Unfortunately, tab is not accessible outside the for loop. Is there any simple way to do what I want or do I have to use a boolean?
It is better practice to use a tab variable outside the scope of the for loop
Tab selected_tab = null;
for ( Tab tab: tabList ) {
if (tab_I_want(tab)) {
selected_tab = tab;
break;
}
}
// selected_tab is either null or the tab you want
You can't access a foreach iterator variable outside of the loop since it goes out of scope. As you wrote it, the above code doesn't compile.
There's a variety of techniques that you can use, such as using the boolean that you mentioned. You can also use a "sentinel", a dummy tab that you put at the end of tabList that has a maximum priority that is reserved for this purpose (i.e. no "real" tab can have this priority). This guarantees that the if condition inside the loop will be true when you reach the sentinel tab.
Finally, you can also implement your Tab to be Comparable, or define a separate Comparator for it, and make tabList an ordered collection. This way, you don't even need a sentinel, or even a foreach loop; you can just add the newTab to the sorted collection and have it figure out where to insert it. If tabList is a TreeSet, for example, the insertion will be O(log n). The other techniques mentioned so far is O(n).
This wouldn't compile, because of the scope of the tab variable. You can do the following
Tab lastTab = null;
for (Tab tab : tabList) {
if (..) {
..
lastTab = tab;
}
}
The most obvious way to convert that into working code is:
insertBlock: {
int newPriority = newTab.getPriority();
for (Tab tab : tabs) {
if (newPriority < tab.getPriority()) {
newTab.insertBefore(tab);
break insertBlock;
}
}
newTab.insertBefore(endMarker);
}
Although it appears that not many people are familiar with the feature. As it happens, it was this feature that allows goto to be removed from the language.
tab is scoped to the body of the for loop, if I remember my Java correctly (and if it works the way one would "expect", i.e. how for scoping works in C99 and C++), so this probably doesn't compile.
tab is not available outside for loop. You can so many things. Using a boolean is one of them.
Agreed with the above. I don't believe you can modify the tabList while it is being iterated either.
One alternate way of doing this is to find the position in the list you want to add into, and do the add operation then.
int i = 0;
for (; i < tabList.length; i++)
{
if( newTab.getPriority() < tabList[i].getPriority() )
break;
}
// this will shift the current item at that index value into the next one, and insert newtab into the specified index
tabList.add(i, newTab);
Inside a foreach-style loop, I don't think you could know this. However, you could use an Iterator outside of the loop:
Iterator iter = tabList.iterator();
while (iter.hasNext()) {
Tab newTab = iter.next();
if( newTab.getPriority() < tab.getPriority() ) {
newTab.insertBefore(tab);
break;
}
}
if (iter.hasNext()) {
// You've still got elements left!
}
Instead of breaking you could raise an exception and catch it outside the loop. I forget the syntax in Java but Python would be something like this:
broken = False
try:
for i in list:
if i.condition == True:
raise Exception
except Exception:
# you know something has broken the flow
broken = True
Although what if the last item broke? Technically speaking every item was inspected.

Categories