How to simplify multiple if else with simple for loop? - java

I have to check each and every condition with this repetitive if else loop. How to simplify with for loop or any other method?
if(color.equals("1")&&id.equals("pant"))
{
}
else if(color.equals("2")&&id.equals("pant"))
{
}
else if(color.equals("3")&&id.equals("pant"))
{
}
else if(color.equals("4")&&id.equals("pant"))
{
}
else if(color.equals("5")&&id.equals("pant"))
{
}
else if(color.equals("6")&&id.equals("pant"))
{
}
if(color.equals("1")&&id.equals("shirt"))
{
}
else if(color.equals("2")&&id.equals("shirt"))
{
}
else if(color.equals("3")&&id.equals("shirt"))
{
}
else if(color.equals("4")&&id.equals("shirt"))
{
}
else if(color.equals("5")&&id.equals("shirt"))
{
}
else if(color.equals("6")&&id.equals("shirt"))
{
}

You can use two for loops for this purpose,
first get a list which contains two elements that is "shirts" and "pants" something like
string [2] cloths = {"pants","shirts"};
and a variable like i and set that to 1 first
int i = 1;
and then
for (string cloth : cloths)
{
for (i = 1; i < 7 ; i++)
{
if(color.equals(i.toString())&&id.equals(cloth))
{
System.out.println(i.toString()+"&"+cloth);
}
}
}
The whole idea is like this but There maybe some minor syntax errors since I didn't compile the code

switch (Integer.parseInt(color))
{
case 1:
if (id == "pant")
{
// 1:pant
}
else if (id == "shirt")
{
// 1:shirt
}
break;
case 2:
if (id == "pant")
{
// 2:pant
}
else if (id == "shirt")
{
// 2:shirt
}
break;
// etc ...
}

You can use inner if statements to achieve a slightly simpler.
if (id.equals("pant")) {
if (color.equals("1")) {
//code
}
else if (color.equals("2")) {
//code
}
//etc
}
else if (id.equals("shirt")) {
if (color.equals("1")) {
//code
}
else if (color.equals("2")) {
//code
}
//etc
}
There may be ways to further simplify it, but we'd really need to know what is in the if blocks. For example, if you're just outputting the value, it could get really simple.

If you can create a common Command interface and encapsulate color & id into a Key class you can have a Map of <Key, Command> pairs.
public class Key {
private final String color; // "6" as a color? why not "blue"?
private final String name;
public Key(String color, String name) {
this.color = color;
this.name = name;
}
public String getColor() { return this.color; }
public String getName() { return this.name; }
}
public interface Command {
void execute(Object...args);
}
Map<Key, Command> noSwitch;
for (Key key : noSwitch.keyValues()) {
noSwitch.get(key).execute();
}
Or, better yet, embed that behavior into a polymorphic StockItem class that knows what to do.
Yours looks like a brittle, non-object-oriented design. You can do better.

What you can do, is to create an interface:
interface Do {
whatever()
}
Along with a bunch of implementations for whatever you do inside the different if branches.
Then have a Map of Lists to store and find them:
Map<String, List<Do>> dos = new HashMap();
// put lots of Do implementations in Lists and put them in the map.
After the setup your if monster would be reduced to:
dos.get(id).get(color).whatever

If whats inside the braces is different you can't easily replace it with a for loop (we'd need to see whats inside the braces to be definitive). A switch statement would at least make things look nicer (assuming you use color as an int not a string of an int
if (id.equals("pant")){
switch(color){ //note color should be an int, not a string of an int for this to work
case 1:
//whatevers in the braces
break;
case 2:
//whatevers in the braces
break;
etc
default:
break;
}
}

You could build a map that maps the combinations you are interested in to a function to perform.
Something like:
interface Function {
void f();
}
public void test() {
String color = "1";
String id = "pant";
// Map the string to a function.
Map<String,Function> functions = new HashMap<String,Function>();
// As many of these as you have different processes.
// You could name them too.
functions.put("1|pant",new Function() {
#Override
public void f() {
// What to do when we see color=1 id=pant
System.out.println("1|pant");
}
});
// Pull the function out of the map.
Function f = functions.get(color+"|"+id);
// If it was there.
if ( f != null ) {
// Do it.
f.f();
}
}

I would use the color-tag as an Integer-value-switch:
switch (color){
case 1:
if (id.equals("pant"){}
else if (id.equals("shirt"){}
break;
case 2:
if (id.equals("pant"){}
else if (id.equals("shirt"){}
break;
.
.
.}
easiest way imo.

Related

Best way execute code according enum value

The following code is an example of my problem.
I would like to simplify the code without having to repeat the call for the same methods, on different switch statements.
public void simulate(String given, Status status) {
switch (status){
case A:
simulateA(given);
break;
case B:
simulateA(given);
simulateB(given);
break;
case C:
simulateA(given);
simulateB(given);
simulateC(given);
break;
}
PS 1: The order of the calling methods matters!
PS 2: I am not looking for another way of doing the switch, I am looking for another way of modelling the problem, maybe using some kind of class composition with the methods.
I do not know the nature of your enum but if you have many simulation calls you could forgo the switch statement and do it like this. But there is nothing wrong with your current approach. This would also change slightly if your methods were static and not instance. The one advantage of this is that it has the potential to scale.
There are many other ways to to this. You could have a list of method references and the enum arguments could be variable arrays of which methods to call by index.
public class Simulations {
static List<BiConsumer<Simulations, String>> sims =
List.of(Simulations::simulateA, Simulations::simulateB,
Simulations::simulateC);
enum Status {
A(1), B(2), C(3);
private int val;
private Status(int v) {
this.val = v;
}
public int getVal() {
return val;
}
}
public static void main(String[] args) {
Simulations simulation = new Simulations();
simulation.simulate("A", Status.A);
System.out.println();
simulation.simulate("B", Status.B);
System.out.println();
simulation.simulate("C", Status.C);
}
public void simulate(String given, Status status) {
for (int i = 0; i < status.getVal(); i++) {
sims.get(i).accept(this, given);
}
}
public void simulateA(String s) {
System.out.println(s);
}
public void simulateB(String s) {
System.out.println(s);
}
public void simulateC(String s) {
System.out.println(s);
}
}
In this case, the order of simulations always cascades "downwards", e.g. Simulating an B is simulating an A plus some extra's. This matches an inheritance pattern, e.g. a Mammal is an Animal with some extras. Thus, letting simulations inherit from each other fixes the pattern:
interface Simulation
{
void simulate( final String given );
}
class ASimulation implements Simulation
{
#Override
public void simulate( String given )
{
// simulate this given!
}
}
class BSimulation extends ASimulation
{
#Override
public void simulate( String given )
{
super.simulate( given );
// simulate this given some more!
}
}
class CSimulation extends BSimulation
{
#Override
public void simulate( String given )
{
super.simulate( given );
// simulate this given even more!
}
}
Note that this is fragile, as all inheritance trees are. Another solution can be achieved with composition and delegation. This is called a chain:
class LeafSimulation
implements Simulation
{
#Override
public void simulate( String given )
{
// simulate this given!
}
}
class ChainedSimulation
implements Simulation
{
private final Simulation delegate;
ChainedSimulation( final Simulation delegate )
{
this.delegate = delegate;
}
#Override
public void simulate( String given )
{
delegate.simulate( given );
// simulate this given some more!
}
}
To instantiate the chain, use the following order:
final var aSimulation = new LeafSimulation();
final var bSimulation = new ChainedSimulation( aSimulation );
final var cSimulation = new ChainedSimulation( bSimulation );
This code approaches the problem statement more naturally and eliminates the repetition, but it is not concise.
Once you have set up a mapping of status values to method calls, you can use a SortedSet or EnumSet.range to get the enum values after a particular value:
Map<Status, Consumer<String>> simulators = new EnumMap<>(Map.of(
Status.A, this::simulateA,
Status.B, this::simulateB,
Status.C, this::simulateC));
if (!simulators.keySet().equals(EnumSet.allOf(Status.class))) {
throw new RuntimeException(
"Not all Status values have simulators defined.");
}
// ...
SortedSet<Status> all = new TreeSet<>(EnumSet.allOf(Status.class));
Collection<Status> remainingValues = all.tailSet(status);
// Or:
//Status[] allStatuses = Status.values();
//Status lastStatus = allStatuses[allStatuses.length - 1];
//Collection<Status> remainingValues = EnumSet.range(status, lastStatus);
for (Status s : remainingValues) {
simulators.get(s).accept(given);
}
Another option to consider, which avoids switch / if. Declare a map of actions per Status value which can be used with a getOrDefault lookup default for unhandled values:
Consumer<String> simA = this::simulateA;
Map<Status, Consumer<String>> actions = new EnumMap<>(Map.of(
Status.A, simA,
Status.B, simA.andThen(this::simulateB),
Status.C, simA.andThen(this::simulateB).andThen(this::simulateC)
));
actions.getOrDefault(status, s -> {}).accept(given);
If you want to guard against missing / unhandled mappings you should validate the map (as in #VGR answer) or swap the no-operation default with an exception handler:
actions.getOrDefault(status,
s -> { throw new RuntimeException("Missing action for status: "+status); }
).accept(given);
Assuming your first status is A you can do something like this:
public void simulate(String given, Status status) {
if (status != Status.A) {
int indexOfStatus = status.ordinal();
simulate(given, Status.values()[indexOfStatus - 1]);
}
switch (status){
case A:
simulateA(given);
break;
case B:
simulateB(given);
break;
case C:
simulateC(given);
break;
// here you still need to put all your "simulateX" calls but without repetitions
}
}
you don't need to write simulateA(given) to all your cases, just moved it to top
public void simulate(String given, Status status) {
simulateA(given);
switch (status){
case C:
simulateC(given);
case B:
simulateB(given);
break;
case A:
break;
}}
You can try the fallthrough mechanism of switch statement. refer to this
In your example, the code can be(not tested):
Edited:
public void simulate(String given, Status status) {
switch (status){
case C:
simulateC(given);
case B:
simulateB(given);
case A:
simulateA(given);
}
}
Original(Wrong):
public void simulate(String given, Status status) {
switch (status){
case A:
simulateA(given);
case B:
simulateB(given);
case C:
simulateC(given);
}
}
When the reader has the fallthrough concept in mind, the code above is cleaner and easier to read than the code in question. But that is not always the case. My recommendation would be to restructure your code so as to eliminate both the repetitive calls and the fallthroughs.

Efficient Java construct for Arraylist Processing and calling different methods

Please, Is there an elegant and efficient way of doing the following in Post Java 8 i.e.
1. Looping through an arraylist
2. Reading the object
3. Calling different methods of potentially different objects using the values contained in the arraylist items
I did look at streams, switch statement, but it was much messy than my if-else.
Any help will be appreciated. Just looking for continuous improvements
List<JAXBElement<? extends Serializable>> bodyElements = eventRequestBodyTypeSrc.getContent();
for(JAXBElement element: bodyElements){
if(element.getName().getLocalPart().equalsIgnoreCase("A")){
methodA(element.getValue());
}else if(element.getName().getLocalPart().equalsIgnoreCase("B")){
methodB(element.getValue());
}else if(element.getName().getLocalPart().equalsIgnoreCase("C")){
methodC(element.getValue());
}else if(element.getName().getLocalPart().equalsIgnoreCase("D")){
methodD(element.getValue());
}else if(element.getName().getLocalPart().equalsIgnoreCase("E")){
methodE(element.getValue());
}else{
}
}
I think you have a bit of an XY Problem going on. I would refactor this at a higher level to encapsulate the strings and their related actions. Here's a rough concept using an enum:
enum Action {
A("a") {
#Override
void doSomething(Serializable value) {
// ...
}
},
B("b") {
#Override
void doSomething(Serializable value) {
// ...
}
};
private static final Map<String, Action> actionsByName = Arrays.stream(values())
.collect(Collectors.toMap(a -> a.name, a -> a));
private final String name;
Action(String name) {
this.name = name;
}
abstract void doSomething(Serializable value);
public static void processElement(JAXBElement<? extends Serializable> element) {
Action action = actionsByName.get(element.getName().getLocalPart().toLowerCase());
if (action != null) {
action.doSomething(element.getValue());
} else {
// ...
}
}
}
As a lean solution I would gather all mappings first as follows:
Map<String, Consumer<Serializable>> dispatchers = new HashMap<>();
dispatchers.put("A", this::methodA);
// etc.
...and dispatch the elements like that:
Consumer<Serializable> dispatcher = dispatchers.get(element.getName().getLocalPart().toUpperCase(Locale.US));
if (dispatcher != null) {
dispatcher.accept(element.getValue());
}

Is it possible to restrict switch to use particular cases only in kotlin/JAVA?

Is it possible to restrict switch for using particular case.
Here is my scenario :
class XYZ {
public static final String DEFAULT = "DEFAULT";
public static final String BIG_TEXT = "BIG_TEXT";
public static final String BIG_PICTURE = "BIG_PICTURE";
public static final String CAROUSEL = "CAROUSEL";
public static final String GIF = "GIF";
#Retention(RetentionPolicy.SOURCE)
#StringDef({DEFAULT, BIG_TEXT, BIG_PICTURE, CAROUSEL, GIF})
public #interface NotificationStyle {}
#NotificationStyle
public String style() {
if (CollectionUtils.isNotEmpty(carouselItems)) {
return CAROUSEL;
}
if (CollectionUtils.isNotEmpty(gifItems)) {
return GIF;
} else {
return DEFAULT;
}
}
}
So here I have define one StringDef interface and restricting style() just to return #NotificationStyle specified values and here is my switch case
// Some other class
XYZ obj = new XYZ()
switch (obj.style()) {
case XYZ.BIG_PICTURE:
//Something something
break;
case XYZ.BIG_PICTURE:
//Something something
break;
case "Not available to execute":
//Something something
break;
default : //Something something
}
I know obj.style() will only return restricted values but I want to somehow restrict switch case to even provide this case here
case "Not available to execute":
//Something something
break;
As this will be unreachable code always.
*Please do not look for the code and syntax , just looking for concept here.
Thanks.
You're doing a switch over a String, right? That's why you can, of course, add cases, that won't really happen (like "Not available to execute"). Why don't you just change your possible Strings to an enum and make obj.style return a constant from that enum? This is how you can restict those Strings.
fun style(): XYZValues {
if (true) {
return XYZValues.BIG_TEXT
}
return XYZValues.DEFAULT
}
enum class XYZValues(desc: String) {
DEFAULT("DEFAULT"),
BIG_TEXT("BIG_TEXT")
//more }
}
fun main(args: Array<String>) {
when (style()) {
XYZValues.BIG_TEXT -> println("1")
XYZValues.DEFAULT -> println("2")
}
}

Creating array of methods returning boolean and iterating through for-each loop

Okay so I have a batch of methods returning boolean values of true/false.
private void saveChangesOnEditButtonActionPerformed(java.awt.event.ActionEvent evt) {
updateMainTabsAccess();
updateUserPaymentTabPermissions();
updateUserRegistrationTabPermissions();
updateUserStudentsTabPermissions();
updateUserFacultyTabPermissions();
updateUserHomePermissions(); //saves any update made on existing user settings/permissions
updateUserInformation(); // sasve any update made on existing user information such as username
}
I would like to know if it's possible for me to check each of the methods' return value through a for-each loop.
I'm thinking of creating a private boolean isUpdateSuccessful() method.
Say like,
private boolean isUpdateSuccessful(){
Boolean a = updateMainTabsAccess();
Boolean b = updateUserPaymentTabPermissions();
//........so on....
Boolean result = (a && b &&...)
return result;
}
Problem is, I don't know if it's possible to put them in an arraylist or component array like
ArrayList<Boolean> listOfMethods = new ArrayList<Boolean>(method1,method2..);
So that I can then check each through a for-each loop
for(Boolean b:listOfMethods){
Boolean successful=true;
successful = (successful && b)
}
My questions are:
1.) How do I extract the return values of these methods and use the methods to initialize the Arraylist.
2.) Using for-each loop, is there any possibility of what I'm trying to do? I none, then what do you suggest I do?
I'd appreciate any answer or suggestion. I simply want to check if every method was successful. I thought of using ?1:0:
Thanks in advance.
If I am you, I would do this. Just a sample code:
private void saveChangesOnEditButtonActionPerformed(java.awt.event.ActionEvent evt) {
if (updateMainTabsAccess()) {
if (updateUserPaymentTabPermissions()) {
if (updateUserRegistrationTabPermissions()) {
...
} else {
// error on update registration
}
} else {
// error on update payment
}
}
With the above style:
You don't execute other methods when the before one fails.
Can have detailed error messages for each error.
You need not to main a collection and iteration.
Why not use a Stream to check the results:
Stream.<Boolean>of(updateMainTabsAccess(),
updateUserPaymentTabPermissions(),
updateUserRegistrationTabPermissions(),
updateUserStudentsTabPermissions(),
updateUserFacultyTabPermissions(),
updateUserHomePermissions(),
updateUserInformation()).allMatch(b -> b);
this way you get rid of short circuit evaluation and also don't need to create method references for each method.
method references
List<Supplier<Boolean>> methods = Arrays.asList(this::updateMainTabsAccess,
this::updateUserPaymentTabPermissions,
...
);
for (Supplier<Boolean> supplier : methods) {
boolean methodResult = supplier.get();
...
}
This can hardly be considered an improvement though...
this will find all method in side your class which is return Boolean after automatically invoke method one by one and store response to successful variable
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
public class Test {
public static void main(String[] args) {
Test test = new Test();
Class c = test.getClass();
boolean successful = true;
for (Method method : c.getDeclaredMethods()) {
if (method.getReturnType().toString().equals("boolean")) {
try {
String mname = method.getName();
Object o = method.invoke(test, null);
System.out.format("%s() returned %b%n", mname, (Boolean) o);
successful = successful && (Boolean) o;
} catch (Exception e) {
e.printStackTrace();
}
}
}
System.out.println("final answer : " + successful);
}
public boolean a() {
return true;
}
public boolean b() {
return false;
}
public boolean c() {
return false;
}
}
Hope its help to you.
If you want every method to be executed and check if every method scucceded you could simply write
boolean success = updateMainTabsAccess() &
updateUserPaymentTabPermissions() &
updateUserRegistrationTabPermissions() &
updateUserStudentsTabPermissions() &
updateUserFacultyTabPermissions() &
updateUserHomePermissions() &
updateUserInformation();
You have already received some answers.
Fabian's is a good one if you are using java 8.
But to answer directly your points
1.) How do I extract the return values of these methods and use the methods to initialize the Arraylist.
ArrayList<Boolean> resultsList = new ArrayList<Boolean>();
resultsList.add(updateMainTabsAccess());
...
2.) Using for-each loop, is there any possibility of what I'm trying to do? I none, then what do you suggest I do?
boolean res = true;
for (Boolean singleResult : resultsList) {
res = res && singleResult;
}
Here is the old style way to acheive your goal when Lambdas weren't introduced by Java 8.
public class TestMethodsListCall {
public abstract class Checker {
public abstract boolean check();
}
public static void main(String[] args) {
new TestMethodsListCall();
}
public TestMethodsListCall() {
final TestMethodsListCall that = this;
List<Checker> checkers = Arrays.asList( //
new Checker() { public boolean check() { return that.methodA(); } }, //
new Checker() { public boolean check() { return that.methodB(); } } //
// , ...
);
boolean res = true;
for (Checker c : checkers) {
res = res & c.check();
if (!res) {
// Break, display some message or all together
}
}
}
public boolean methodA() {
return true;
}
public boolean methodB() {
return false;
}
}

Check enum for multiple values

I have an enum FileType
public static enum FileType {
CSV, XML, XLS, TXT, FIXED_LENGTH
}
FileType fileType = FileType.CSV;
Is there a better (cleaner) way to check fileType for multiple values than the following (like "myString".matches("a|b|c");)?
if(fileType == FileType.CSV || fileType == FileType.TXT || fileType == FileType.FIXED_LENGTH) {}
Option 1: Add a boolean field to your enum.
public static enum FileType {
CSV(true), XML(false), XLS(false), TXT(true), FIXED_LENGTH(true);
private final boolean interesting;
FileType(boolean interesting) {
this.interesting = interesting;
}
public boolean isInteresting() {
return this.interesting;
}
}
...
if (fileType!=null && fileType.isInteresting()) {
...
}
Option 2: use an EnumSet.
EnumSets use bitfields under the hood, so they are very fast and low memory.
Set<FileType> interestingFileTypes = EnumSet.of(FileType.CSV, FileType.TXT, FileType.FIXED_LENGTH);
...
if (interestingFileTypes.contains(fileType)) {
...
}
Option 3: use a switch, as kocko suggests
Why not use a switch:
switch(fileType) {
case CSV:
case TXT:
case FIXED_LENGTH:
doSomething();
break;
}
This does the same as your if statement check, but it's more readable, imho.
But the problem with this code is not the switch or the if/else statement(s). The problem is that it breaks the Open-closed principle.
In order to fix that, I would completely remove the enum and create an interface:
interface FileType {
boolean isInteresting();
}
Then, for each enum constant we used to have, I would create a separate interface implementation:
public class Txt implements FileType {
#Override
public boolean isInteresting() {
return false;
}
}
How does the switch statement change? We used to pass a fileType parameter, on which we checked the value. Now, we will pass an instance of FileType.
public void method(FileType fileType) {
if (fileType.isInteresting()) {
doSomething();
}
}
The advantage of this is that when you introduce a new FileType (which you would introduce as a new enum constant), you don't have to modify the switch/if/else statement to handle the case when this new file type is interesting or not. The code will simply work here without modification, which is the essence of the Open-closed principle: "Open for extensions, closed for modifications".
I ended up writing a method:
public static enum FileType {
CSV, XML, XLS, TXT, FIXED_LENGTH;
// Java < 8
public boolean in(FileType... fileTypes) {
for(FileType fileType : fileTypes) {
if(this == fileType) {
return true;
}
}
return false;
}
// Java 8
public boolean in(FileType... fileTypes) {
return Arrays.stream(fileTypes).anyMatch(fileType -> fileType == this);
}
}
And then:
if(fileType.in(FileType.CSV, FileType.TXT, FileType.FIXED_LENGTH)) {}
Nice and clean!
Adding a different example:
public class JavaApplication {
public enum CustomerStatus {
ACTIVE("Active"),
DISCONNECTED("Disconnected"),
PENDING("Pending"),
CANCELLED("cancelled"),
NEW("new");
}
public static void main(String[] args) {
EnumSet<CustomerStatus> setA = EnumSet.of(CustomerStatus.ACTIVE, CustomerStatus.NEW);
EnumSet<CustomerStatus> setB = EnumSet.of(CustomerStatus.PENDING, CustomerStatus.CANCELLED);
if (setA.contains(CustomerStatus.ACTIVE)) {
System.out.println("ACTIVE : customer active");
}
if (setB.contains(CustomerStatus.ACTIVE)) {
System.out.println("ACTIVE: Customer is no longer active");
}
if (setB.contains(CustomerStatus.CANCELLED) {
System.out.println("CANCELLED: Customer is no longer active");
}
}
}
**Output**:
ACTIVE : customer active
CANCELLED: Customer is no longer active

Categories

Resources