Java run switch case methods with List of items - java

I need to simplify my methods I need to run this method for all weekdays:
if (!getAbsenceSo().equals("-")) {
switch (getAbsenceSo()){
case "uabgelehnt": setAbsenceSo("-"); break;
case "urlaubbeantragt": setAbsenceSo("-"); break;
case "urlaubgenehmigt": setAbsenceSo("Urlaub"); setArbeitMinutenSo((int)(wochenarbeitstunden*60/5)); break;
case "sonderurlaub": setAbsenceSo("Sonderurlaub"); setArbeitMinutenSo((int)(wochenarbeitstunden*60/5)); break;
case "ueabsetzer": setAbsenceSo("Ü-Absetzer"); break;
case "krank": setAbsenceSo("Krank"); setArbeitMinutenSo((int)(wochenarbeitstunden*60/5)); break;
case "kindkrank": setAbsenceSo("Kindkrank"); setArbeitMinutenSo((int)(wochenarbeitstunden*60/5)); break;
case "fbschule": setAbsenceSo("FB/Schule"); setArbeitMinutenSo((int)(wochenarbeitstunden*60/5)); break;
case "kurzarbeit": setAbsenceSo("Kurzarbeit"); setArbeitMinutenSo((int)(wochenarbeitstunden*60/5)); break;
case "unentschuldigt": setAbsenceSo("Unentschuldigt"); break;
}
}
so the next code snippet would look like this:
if (!getAbsenceMo().equals("-")) {
switch (getAbsenceMo()){
case "uabgelehnt": setAbsenceMo("-"); break; and so on...
is there a way that I can use to prevent duplicate code?
I have not really much knowledge about Java - can you give me a hint?
That I can call a method within the object put together from a string.
e.g. how can I call "setAbsense"+item("-"); ??? Or better how should this be done??? Thanks a lot!!!

Do not try to dynamically construct a method call. Instead, rethink your design. You've code that needs to be performed for multiple instances of the same type (same data, same methods). This already indicates: use a class. Every instance (Mo, Tu, ...) will have the same information, but you can manipulate it on that very instance itself.
Quick example to get you going:
public class App {
static class Absence {
private DayOfWeek dayOfWeek;
private String reason;
private int arbeitMinuten;
public Absence(DayOfWeek dayOfWeek, String reason) {
this.dayOfWeek = dayOfWeek;
this.reason = reason;
}
public DayOfWeek getDayOfWeek() {
return dayOfWeek;
}
public void setDayOfWeek(DayOfWeek dayOfWeek) {
this.dayOfWeek = dayOfWeek;
}
public String getReason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
public int getArbeitMinuten() {
return arbeitMinuten;
}
public void setArbeitMinuten(int arbeitMinuten) {
this.arbeitMinuten = arbeitMinuten;
}
}
public static void main(String[] args) throws IOException {
int wochenarbeitstunden = 40;
List<Absence> absenceList;
// Build from your Datasource
absenceList = List.of(new Absence(DayOfWeek.MONDAY, "uabgelehnt"), new Absence(DayOfWeek.TUESDAY, "Krank"), new Absence(DayOfWeek.WEDNESDAY, "Kurzarbeit"));
for (Absence absence : absenceList) {
switch (absence.getReason()) {
case "uabgelehnt" -> absence.setReason("-");
case "urlaubbeantragt" -> absence.setReason("-");
case "urlaubgenehmigt" -> {
absence.setReason("Urlaub");
absence.setArbeitMinuten(wochenarbeitstunden * 60 / 5);
}
case "sonderurlaub" -> {
absence.setReason("Sonderurlaub");
absence.setArbeitMinuten(wochenarbeitstunden * 60 / 5);
}
case "ueabsetzer" -> absence.setReason("Ü-Absetzer");
case "krank" -> {
absence.setReason("Krank");
absence.setArbeitMinuten(wochenarbeitstunden * 60 / 5);
}
case "kindkrank" -> {
absence.setReason("Kindkrank");
absence.setArbeitMinuten(wochenarbeitstunden * 60 / 5);
}
case "fbschule" -> {
absence.setReason("FB/Schule");
absence.setArbeitMinuten(wochenarbeitstunden * 60 / 5);
}
case "kurzarbeit" -> {
absence.setReason("Kurzarbeit");
absence.setArbeitMinuten(wochenarbeitstunden * 60 / 5);
}
case "unentschuldigt" -> absence.setReason("Unentschuldigt");
default -> {}
}
}
}
}

Related

Break in if statement

I have a switch method, and I want that if the type of fetch is ALL, the switch runs in all the statments, (HOUSE AND PLAYER), but it doesn't work because of the break, it only runs in HOUSE, removing the break works, but then if the type is not ALL, it will also runs on the others statments and not only in the given type. Whats is a proper solution for that?
public static void fetch(FetchType fetchType) {
switch (updateType) {
case ALL: // if this is the case, then it should run for HOUSE, PLAYER
case HOUSE:
// code here
break;
case PLAYER:
// code here
break;
default:
throw new IllegalArgumentException();
}
}
Well you can either create private methods for that:
public static void fetch(FetchType fetchType) {
switch (updateType) {
case ALL:
doHouse();
doPlayer();
break;
case HOUSE:
doHouse();
break;
case PLAYER:
doPlayer();
break;
default:
throw new IllegalArgumentException();
}
}
private static void doHouse(){ ... }
private static void doPlayer(){ ... }
Or use Runnable to avoid using polluting the local private namespace:
public static void fetch(FetchType fetchType) {
Runnable house = () -> { ... };
Runnable player = () -> { ... };
switch (updateType) {
case ALL:
house.run();
player.run();
break;
case HOUSE:
house.run();
break;
case PLAYER:
player.run();
break;
default:
throw new IllegalArgumentException();
}
}
If I understand it right you might need to create methods for each case in the Main class and then call all methods if the fetch type is "ALL"
static void methodForHouse() {
System.out.println("I just got executed!");
}
static void methodForPlayer() {
System.out.println("I just got executed!");
}
And then
public static void fetch(FetchType fetchType) {
switch (updateType) {
case ALL:
methodForHouse();
methodForPlayer();
break;
case HOUSE:
methodForHouse();
break;
case PLAYER:
methodForPlayer();
break;
default:
throw new IllegalArgumentException();
}
}

Is there a benefit to using an enum in a FSM over just using a string?

I want to create a finite state machine and most of the example code I can find uses enums and I was just wondering if it gives an advantage over just using a string or int to store the state.
With Enum:
class TrafficLight {
enum State {
RED, YELLOW, GREEN
};
State state = State.GREEN;
public void iterate() throws InterruptedException {
switch (this.state) {
case RED:
System.out.println("RED");
Thread.sleep(1000);
this.state = State.GREEN;
break;
case GREEN:
System.out.println("GREEN");
Thread.sleep(1000);
this.state = State.YELLOW;
break;
case YELLOW:
System.out.println("YELLOW");
Thread.sleep(1000);
this.state = State.RED;
break;
}
}
public class Main {
public static void main(final String[] args) throws InterruptedException {
final TrafficLight a = new TrafficLight();
while (true) {
a.iterate();
}
}
}
With String
public class TrafficLight {
String state = "GREEN";
public void iterate() throws InterruptedException {
switch (state) {
case "RED":
System.out.println("RED");
Thread.sleep(1000);
state = "GREEN";
break;
case "GREEN":
System.out.println("GREEN");
Thread.sleep(1000);
state = "YELLOW";
break;
case "YELLOW":
System.out.println("YELLOW");
Thread.sleep(1000);
state = "RED";
break;
}
}
}
(Both use the same main method)
They both seem to be exactly the same to me I am just wondering if there are any cases in which enums are better or a string wouldn't work.
Thanks.
Main advantage for Enum over String : this is more specifically typed as Enum specifies possible values.
This makes your code both more robust and also better documented.
For a FSM and more generally bounded values, it is what you are looking for.
But for problems/domains where possible values are defined at runtime and not at compile time (retrieving from a database or whatever), Enum is not the best candidate.
Example of Enum interest in your case
With Enum, it will not compile as REDD is not declared in the State enum class:
case REDD:
System.out.println("RED");
Thread.sleep(1000);
this.state = State.GREEN;
break;
But with String, it will compile and just not work as expected :
case "REDD":
System.out.println("RED");
Thread.sleep(1000);
state = "GREEN";
break;
Enumerated values are instances of the enum class with own values for instance fields but also overriding abilities for instance methods
This is another advantage of enum in the FSM or any domain where the enumerated values are associated to specific properties/processings and where according to enumerated value, the fields values or the method behavior could differ.
For example, here we specify the behavior to get the next transition :
enum State {
YELLOW(){
#Override
public State next() {
return RED;
}
},
RED(){
#Override
public State next() {
return GREEN;
}
},
GREEN(){
#Override
public State next() {
return YELLOW;
}
};
public abstract State next();
}
Now, the enum holds enough logic to make the switch statement not needed any longer :
public void iterate() throws InterruptedException {
System.out.println(state);
Thread.sleep(1000);
state = state.next();
}

Ensure every enum value is used

If I´m using an enum to determine the type of a task.
public enum TaskType {
TYPE_ONE("Type1"),TYPE_TWO("Type2"),TYPE_THREE("Type3");
private final String type;
private StageType(String type) {
this.type = type;
}
#Override
public String toString() {
return type;
}
}
how can I assure at one point in my Application
if(taskType == TaskType.TYPE_ONE) {
typeOneProcessing();
} else if(taskType == TaskType.TYPE_TWO) {
typeTwoProcessing();
} else if(taskType == TaskType.TYPE_THREE) {
typeThreeProcessing();
}
that every enum value is used?
I mean if I need to add a new TYPE_FOUR someday, I´d need to find every place in my code where I used the enum, so I ask myself if there is a better way so that I either avoid the enum and use some other concept or that I can ensure that every value of the enum is used in that piece of code.
There are findbugs type tools for doing that but you could consider removing the if-then-else completely and put the processing inside the enum. Here, adding a new TYPE_FOUR will force you to write it's doProcessing() method.
public interface DoesProcessing {
public void doProcessing();
}
public enum TaskType implements DoesProcessing {
TYPE_ONE("Type1") {
#Override
public void doProcessing() {
}
},
TYPE_TWO("Type2") {
#Override
public void doProcessing() {
}
},
TYPE_THREE("Type3") {
#Override
public void doProcessing() {
}
},
TYPE_FOUR("Type4") {
// error: <anonymous com.oldcurmudgeon.test.Test$TaskType$4> is not abstract and does not override abstract method doProcessing() in DoesProcessing
};
private final String type;
private TaskType(String type) {
this.type = type;
}
#Override
public String toString() {
return type;
}
}
public void test() {
DoesProcessing type = TaskType.TYPE_TWO;
type.doProcessing();
}
If you would prefer an abstract method then this works:
public enum TaskType {
TYPE_ONE("Type1") {
#Override
public void doProcessing() {
}
},
TYPE_TWO("Type2") {
#Override
public void doProcessing() {
}
},
TYPE_THREE("Type3") {
#Override
public void doProcessing() {
}
};
private final String type;
private TaskType(String type) {
this.type = type;
}
// Force them all to implement doProcessing.
public abstract void doProcessing();
#Override
public String toString() {
return type;
}
}
You could put the process method as an abstract method in TaskType, and then override it in every task in the enum. What would probably be a better idea is if you create an interface, something like:
public interface Task {
void process();
}
Then you either let your enum implement this interface. Or, probably better, you create concrete classes implementing this interface. One class for each of your task types.
I think you are saying that you are wanting the compiler to tell you that all of the enum's values are considered.
Unfortunately, Java doesn't support that.
You might think that you could write something like this:
public int method(TaskType t) {
switch (t) {
case TYPE_ONE: return 1;
case TYPE_TWO: return 2;
case TYPE_THREE: return 3;
}
// not reachable ... no return required
}
... and rely on the compiler to tell you if you left out one of the enum values in the switch cases.
Unfortunately, it doesn't work!! The above is a compilation error anyway. According to the JLS reachability rules, the switch statement needs a default: arm for that method to be valid. (Or you can add a return at the end ...)
There is a good reason for this oddity. The JLS binary compatibility rules say that adding a new value to an enum is a binary compatible change. That means that any code with switch statement that switches on an enum needs to still remain valid (executable) code after the addition of enum values. If method was valid to start with, it can't become invalid (because there is a return path with no return statement) after the binary compatible change.
In fact, this is how I would write the code above:
public int method(TaskType t) {
switch (t) {
case TYPE_ONE: return 1;
case TYPE_TWO: return 2;
case TYPE_THREE: return 3;
default:
throw new AssertionError("TaskType " + t + " not implemented");
}
// not reachable ... no return required
}
This doesn't pretend to be compile-time safe, but it is fail-fast, and it doesn't involve bad OO design.
AFAIK you can't do it "automatically".
To minimize the risk of forgetting to add an if/case for new value you could have one "service" class for each enum value and a factory which provides a specific service for enum value.
E.g. instead of:
void methodA(TaskType type) {
doSth();
switch(type) {
case TYPE_ONE:
foo1();
break;
case TYPE_TWO:
foo2();
break;
...
}
}
void methodB(TaskType type) {
doSthElse();
switch(type) {
case TYPE_ONE:
bar1();
break;
case TYPE_TWO:
bar2();
break;
...
}
}
do:
interface Service {
foo();
bar();
}
class ServiceFactory {
Service getInstance(TaskType type) {
switch(type) {
case TYPE_ONE:
return new TypeOneService();
case TYPE_TWO:
return new TypeTwoService();
default:
throw new IllegalArgumentException("Unsupported TaskType: " + type);
}
}
}
And then the methods above can be rewritten as follows:
void methodX(TaskType type) {
doSth();
ServiceFactory.getInstance(type).foo();
}
This way you have only one point where you have to add handling of new enum value.
HashMap<String, Integer> hm=new HashMap<String, Integer>();
...
if(taskType == TaskType.TYPE_ONE) {
typeOneProcessing();
hm.put(TaskType.TYPE_ONE, 1)
} else if(taskType == TaskType.TYPE_TWO) {
typeTwoProcessing();
hm.put(TaskType.TYPE_TWO, 1)
} else if(taskType == TaskType.TYPE_THREE) {
typeThreeProcessing();
hm.put(TaskType.TYPE_THREE, 1)
}
...
for (TaskType t : TaskType.values()) {
if(hm.get(t)!=1)
// Trigger the alarm
}
You can even count the times the element was count if you need it
You can do swich case on the enum, and fail if the default is hit:
switch(taskType ){
case TYPE_ONE: ... break;
case TYPE_TWO: ... break;
case TYPE_THREE: ... break;
default:
throw new IllegalStateException("Unsupported task type:"+taskType);
}

Java: using switch statement with enum under subclass

First I'll state that I'm much more familiar with enums in C# and it seems like enums in java is a quite mess.
As you can see, I'm trying to use a switch statement # enums in my next example but I always get an error no matter what I'm doing.
The error I receive is:
The qualified case label SomeClass.AnotherClass.MyEnum.VALUE_A must be replaced with the unqualified enum constant VALUE_A
The thing is I quite understand the error but I can't just write the VALUE_A since the enum is located in another sub-class. Is there a way to solve this problem? And why is it happening in Java?
//Main Class
public class SomeClass {
//Sub-Class
public static class AnotherClass {
public enum MyEnum {
VALUE_A, VALUE_B
}
public MyEnum myEnum;
}
public void someMethod() {
MyEnum enumExample //...
switch (enumExample) {
case AnotherClass.MyEnum.VALUE_A: { <-- error on this line
//..
break;
}
}
}
}
Change it to this:
switch (enumExample) {
case VALUE_A: {
//..
break;
}
}
The clue is in the error. You don't need to qualify case labels with the enum type, just its value.
Wrong:
case AnotherClass.MyEnum.VALUE_A
Right:
case VALUE_A:
Java infers automatically the type of the elements in case, so the labels must be unqualified.
int i;
switch(i) {
case 5: // <- integer is expected
}
MyEnum e;
switch (e) {
case VALUE_A: // <- an element of the enumeration is expected
}
this should do:
//Main Class
public class SomeClass {
//Sub-Class
public static class AnotherClass {
public enum MyEnum {
VALUE_A, VALUE_B
}
public MyEnum myEnum;
}
public void someMethod() {
AnotherClass.MyEnum enumExample = AnotherClass.MyEnum.VALUE_A; //...
switch (enumExample) {
case VALUE_A: { //<-- error on this line
//..
break;
}
}
}
}
From Java 14 onwards, one can use switch expressions.
For this post
public enum MyEnum {
VALUE_A, VALUE_B;
}
public void someMethod() {
MyEnum enumExample //...
switch (enumExample) {
case VALUE_A -> {
// logic
}
case VALUE_B -> {
// logic
}
}
}
Switch expression
Like all expressions, switch expressions evaluate to a single value and can be used in statements. They may contain "case L ->" labels that eliminate the need for break statements to prevent fall through. You can use a yield statement to specify the value of a switch expression.
public enum Month {
JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC;
}
Example 1: Returns value.
public static int getNoOfDaysInAMonth(Month month, boolean isLeapYear) {
return switch(month) {
case APR, JUN, SEP, NOV -> 30;
case FEB -> (isLeapYear)? 29: 28;
case JAN, MAR, MAY, JUL, AUG, OCT, DEC -> 31;
};
}
Example 2: Doesn't returns value.
public static void printNoOfDaysInAMonth(Month month, boolean isLeapYear) {
switch(month) {
case APR, JUN, SEP, NOV -> {
System.out.println("30 days");
}
case FEB -> {
System.out.println(((isLeapYear)? 29: 28) + " days");
}
case JAN, MAR, MAY, JUL, AUG, OCT, DEC -> {
System.out.println("31 days");
}
};
}
Reference
Switch Expressions
This is how I am using it. And it is working fantastically -
public enum Button {
REPORT_ISSUES(0),
CANCEL_ORDER(1),
RETURN_ORDER(2);
private int value;
Button(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
And the switch-case as shown below
#Override
public void onClick(MyOrderDetailDelgate.Button button, int position) {
switch (button) {
case REPORT_ISSUES: {
break;
}
case CANCEL_ORDER: {
break;
}
case RETURN_ORDER: {
break;
}
}
}
Write someMethod() in this way:
public void someMethod() {
SomeClass.AnotherClass.MyEnum enumExample = SomeClass.AnotherClass.MyEnum.VALUE_A;
switch (enumExample) {
case VALUE_A:
break;
}
}
In switch statement you must use the constant name only.
You dont need put instance of enum class, you have to put only enum constant of enum class, like this:
switch (enumExample) {
case VALUE_A: { <-- puting only constant, it will works.
//..
break;
}

Java switch case statement issue

I'm trying to use a switch statement in Android aplication,where I have to check if an integer is equal to some of the Enum's value.The code goes like this :
public enum RPCServerResponseCode{
E_INCORRECT_LOGIN(4001),
E_ACCOUNT_DISABLED(4002),
E_ACCOUNT_NOT_ACTIVE(4003);
private int value;
private RPCServerResponseCode(int i) {
this.value=i;
}
public static RPCServerResponseCode getByValue(int i) {
for(RPCServerResponseCode dt : RPCServerResponseCode.values()) {
if(dt.value == i) {
return dt;
}
}
throw new IllegalArgumentException("No datatype with " + i + " exists");
}
}
}
And my switch statement looks like this :
int errorCode;
switch(errorCode){
case RPCServerResponseCode.E_INCORRECT_LOGIN :
{
if (user.isAuthenticated)
{
// logout before login
}
break;
}
case RPCServerResponseCode.E_ACCOUNT_NOT_ACTIVE:
{
if (user.isAuthenticated)
{
//logout
}
break;
}
}
}
But I get error saying this : "Type mismatch: cannot convert from RPCCommucatorDefines.RPCServerResponseCode to int".
Any suggestions how to solce that issue? Thanks in advance!!!
errorcode is int. Should be of type RPCServerResponseCode, so you could use something like:
switch (RCPServerResponseCode.getByValue(errorcode))
{
...
}
You're trying to compare your INT error code to a RPCServerResponseCode instance - This isn't possible. You need to use the method getByValue in your RPCServerResponseCode class to do the conversion for you. After that, you can use the result (Which will be a RPCServerResponseCode instance) in your switch statement:
int errorCode;
RPCServerResponseCode responseCode = RPCServerResponseCode.getByValue(errorCode);
switch(responseCode){
case RPCServerResponseCode.E_INCORRECT_LOGIN :
{
if (user.isAuthenticated)
{
// logout before login
}
break;
}
case RPCServerResponseCode.E_ACCOUNT_NOT_ACTIVE:
{
if (user.isAuthenticated)
{
//logout
}
break;
}
}
}
Java enums are fully-fledged objects and cannot be implicitly cast to integers.
This should work:
switch(RPCServerResponseCode.getByValue(errorCode)){
you can say
int errorCode=4001;
RPCServerResponseCode code = RPCServerResponseCode.getByValue(errorCode);
switch(code){
...
}

Categories