I've got a marker interface
public interface Marker{}
and two enums which implement the Marker
public enum Sharpie implements Marker{
RED,
BLUE,
BLACK
}
public enum Crayola implements Marker{
PURPLE,
ORANGE,
GREEN
}
What I'm trying to do is utilize a switch statement, such as
public boolean isOwned(Marker m){
// Take in a marker of either Sharpie, or Crayola
switch(m){
case BLUE:
case BLACK:
case GREEN:
return true;
default:
return false;
}
}
Is there a way to do this without using an expensive instanceof call?
Something like this would work, but I'm trying to avoid using instanceof, and frankly it looks kind of ugly.
public boolean isOwned(Marker m){
// First determine instanceof and then cast the marker
// to the appropriate Type before utilizing the switch statement
if (m instanceof Sharpie){
switch((Sharpie) m){
Case BLUE:
Case BLACK:
return true;
default:
return false;
}
} else {
switch((Crayola) m){
case Green:
return true;
default:
return false;
}
}
}
Looks like a good scenario to try new Java Feature Sealed Interface and Pattern Matching for switch Expressions(* this is a preview feature as at jdk 17)
First make Marker as sealed interface
public sealed interface Marker permits Crayola, Sharpie {}
Then we can use switch expression to get rid of those instanceof checking.
public boolean isOwned(Marker marker) {
boolean isOwned = switch (marker) {
case Sharpie s -> s == Sharpie.BLACK || s == Sharpie.BLUE;
case Crayola c -> c == Crayola.GREEN;
};
return isOwned;
}
Just change the switch to if. There is no need for instanceof:
public boolean isOwned(Marker m){
if(m == Sharpie.BLUE || m == Sharpie.BLACK || m == Crayola.GREEN)
return true;
return false;
}
i don't know what are you doing. this example is using unique function for 2 diffrents enum. i think you should use extending in enum like this.
Related
I have 6 values in the enum and using 6 if-else is really a bad practice.
Can we implement this in any better way? Below is my scenario :
ExampleEnum value = getEnumValue();
if(ExampleEnum.A == value){
doA();
}else if(ExampleEnum.B == value){
doB();
}else if(ExampleEnum.C == value){
doC();
}else if(ExampleEnum.D == value){
doD();
}else if(ExampleEnum.E == value){
doE();
}else if(ExampleEnum.F == value){
doF();
}
I was thinking of switch, but is is not making much difference also i need to return a boolean value inside doA() depending on certain parameters.
Thanks in advance.
You have a few options:
A chain of else-ifs
Leave your code as-is. Hard to read and write.
Switch
switch (value) {
case A:
doA();
break;
case B:
doB();
break;
case C:
doC();
break;
case D:
doD();
break;
case E:
doE();
break;
case F:
doF();
break;
}
Note that this is the classic switch. If you have access to newer Java versions, it is probably possible to get rid of the breaks.
EnumMap
You can also create an EnumMap:
EnumMap<ExampleEnum, Runnable> enumMap = new EnumMap<>(Map.<ExampleEnum, Runnable>of(
ExampleEnum.A, Main::doA, // 'Main', or wherever your do* methods are.
ExampleEnum.B, Main::doB,
ExampleEnum.C, Main::doC, // I'm using method references. But you could
ExampleEnum.D, Main::doD, // also use lambda expressions: '() -> doD()'.
ExampleEnum.E, Main::doE,
ExampleEnum.F, Main::doF
));
ExampleEnum value = getEnumValue();
enumMap.get(value).run();
If you want to use a switch statement and you're on Java 12 or newer, consider using extended switch expressions that avoid the pitfalls of break statements:
switch (value) {
case A -> doA();
case B -> doB();
case C -> doC();
case D -> doD();
case E -> doE();
case F -> doF();
}
You can add the do method inside the enum.
public enum ExampleEnum {
A {
public void doIt() { ... }
},
B {
public void doIt() { ... }
},
...
abstract public void doIt();
}
ExampleEnum value = getEnumValue();
if (value != null) {
value.doIt();
}
I have a list of objects, lets say Shapes.
I would like to process them using a stream and return another object - ShapeType - based on what is in the list.
Normally I will just return ShapeType.GENERIC, however if there is a Rectangle in there, I would like to return ShapeType.RECT. If there is a hexagon in a list I would like to return ShapeType.HEXA.
When both rectangle and square are present, I would like to return ShapeType.HEXA.
Now, when it comes to code I would like something like this:
public ShapeType resolveShapeType(final List<Shape> shapes) {
shapes.stream()
.filter(shape -> shape.getSideCount() == 6 || shape.getSideCount() == 4)
// I should have a stream with just rectangles and hexagons if present.
// what now?
}
You can use
public ShapeType resolveShapeType(final List<Shape> shapes) {
int sides = shapes.stream()
.mapToInt(Shape::getSideCount)
.filter(count -> count==4 || count==6)
.max().orElse(0);
return sides==6? ShapeType.HEXA: sides==4? ShapeType.RECT: ShapeType.GENERIC;
}
This maps each element to its side count and reduces them to the preferred type, which happens to be the maximum count here, so no custom reduction function is needed.
This isn’t short-circuiting, but for most use cases, it will be sufficient. If you want to reduce the number of operations to the necessary minimum, things will be more complicated.
public ShapeType resolveShapeType(final List<Shape> shapes) {
OptionalInt first = IntStream.range(0, shapes.size())
.filter(index -> {
int count = shapes.get(index).getSideCount();
return count == 6 || count == 4;
})
.findFirst();
if(!first.isPresent()) return ShapeType.GENERIC;
int ix = first.getAsInt(), count = shapes.get(ix).getSideCount();
return count==6? ShapeType.HEXA: shapes.subList(ix+1, shapes.size()).stream()
.anyMatch(shape -> shape.getSideCount()==6)? ShapeType.HEXA: ShapeType.RECT;
}
We know that we can stop at the first HEXA, but to avoid a second pass, it’s necessary to remember whether there was an occurence of RECT for the case there is no HEXA. So this searches for the first element that is either, a RECT or HEXA. If there is none, GENERIC is returned, otherwise, if the first was not a HEXA, the remaining elements are checked for an element of the HEXA kind. Note that for processing the remainder after the first RECT, no filter is needed as it is implied that shapes that are neither, RECT nor HEXA, can’t fulfill the condition.
But it should also be obvious that this code, trying to minimize the numbers of checks, is harder to read than an equivalent for loop.
Assuming that only the three types of shapes can be present in the list, an alternative would be:
Set<Integer> sides = shapes.stream()
.map(Shape::getSideCount)
.collect(toSet());
if (sides.contains(6)) return HEXA;
else if (sides.contains(4)) return RECTANGLE;
else return GENERIC;
But I think the most straightforward (and efficient) way would be a good old for loop:
ShapeType st = GENERIC;
for (Shape s : shapes) {
if (s.getSideCount() == 6) return HEXA;
if (s.getSideCount() == 4) st = RECTANGLE;
}
return st;
If I understand what you're trying to do, then you can use anyMatch. Like,
public ShapeType resolveShapeType(final List<Shape> shapes) {
if (shapes.stream().anyMatch(shape -> shape.getSideCount() == 6)) {
return ShapeType.HEXA;
} else if (shapes.stream().anyMatch(shape -> shape.getSideCount() == 4)) {
return ShapeType.RECT;
} else {
return ShapeType.GENERIC;
}
}
One way to do this (streaming shapes once) would be to preserve the shape presence with an array. Like,
public ShapeType resolveShapeType(final List<Shape> shapes) {
boolean[] bits = new boolean[2];
shapes.stream().forEach(shape -> {
int sides = shape.getSideCount();
if (sides == 4) {
bits[0] = true;
} else if (sides == 6) {
bits[1] = true;
}
});
if (bits[1]) {
return ShapeType.HEXA;
} else if (bits[0]) {
return ShapeType.RECT;
} else {
return ShapeType.GENERIC;
}
}
Can also do something like this:
ShapeType r = shapes.stream()
.map(s -> ShapeType.parse(s.getSides()))
.filter(c -> c == ShapeType.Hexagon || c==ShapeType.Square)
.max(ShapeType::compareTo)
.orElse(ShapeType.Generic);
Here, I've taken a little liberty with your ShapeType:
enum ShapeType {
Square(4), Hexagon(6), Generic(Integer.MAX_VALUE);
int v;
ShapeType(int v) {
this.v = v;
}
static ShapeType parse(int v) {
switch (v) {
case 4: return Square;
case 6: return Hexagon;
default:
break;
}
return Generic;
}
public String toString(){
return Integer.toString(v);
}
}
TBH you can avoid the parse operation if you add a getShapeType() method which returned the correct type per Derived type. Then the map() operation will only extract the type, for example .map(Shape::getShapeType).
The .filter() will find the group you are interested in, the largest shape is deemed the label of the collection...
Sounds like a case for 'reduce' or 'collect/max'.
Assume you have a method that selects the 'dominant' type (you can put it in a lambda, but IMHO it's more readable as a method):
public class Util{
public static ShapeType dominantType(ShapeType t1, ShapeType t2){
if(t1==HEXA || t2==HEXA) return HEXA;
else if (t1==RECTANGLE || t2==RECTANGLE) return RECTANGLE;
else return GENERIC;
}
}
There are several ways to use it, one reduce example would be:
shapes.stream()
.filter(shape -> shape.getSideCount() == 6 || shape.getSideCount() == 4)
.map(shape -> shape.getSideCount()==6? HEXA:RECTANGLE)
.reduce( GENERIC, Util::dominantType);
// using GENERIC in case of empty list
You may also want to look into collectors.maxBy.
BTW whatever approach you take, please give some thought to the behavior in case of an empty list...
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
I've got a situation in which I need to check multiple conditions, where every combination has a different outcome. In my specific condition, I've got 2 variables, which are enum types, that can each be 2 different values.
enum Enum1
{
COND_1,
COND_2
}
enum EnumA
{
COND_A,
COND_B
}
Enum1 var1;
EnumA varA;
This gives me 4 possible conditions, which requires 4 different outcomes. I've come up with a few different ways of doing this, either using if statements or switch statements:
if(var1 == Enum1.COND_1 && varA == EnumA.COND_A)
{
// Code
}
else if(var1 == Enum1.COND_1 && varA == EnumA.COND_B)
{
// Code
}
else if(var1 == Enum1.COND_2 && varA == EnumA.COND_A)
{
// Code
}
else if(var1 == Enum1.COND_2 && varA == EnumA.COND_B)
{
// Code
}
Or:
switch(var1)
{
case COND_1:
switch(varA)
{
case COND_A:
// Code
break;
case COND_B:
// Code
break;
}
break;
case COND_2:
switch(varA)
{
case COND_A:
// Code
break;
case COND_B:
// Code
break;
}
break;
}
I've thought of others, but don't want to fill this up with code :P I'd like to know what the best way to do this is. I think the switch is a bit easier to read, but the ifs are shorter. I think it'd be really cool if switches could have multiple conditions, but I haven't heard of it. This also begs the question: what's the best way to do this with an arbitrary number of variables and possible values?
For your small use case I would probably go for nested if statements. But if you have plenty of enum constants, perhaps a pattern using streams could make your code easier to read and maintain (for a small performance penalty). You could solve it using a stream like this:
Stream.of(new Conditional(COND_1, COND_A, () -> {/* do something */}),
new Conditional(COND_1, COND_B, () -> {/* do something */}),
new Conditional(COND_2, COND_A, () -> {/* do something */}),
new Conditional(COND_2, COND_B, () -> {/* do something */}))
.filter(x -> x.test(var1, varA))
.findAny()
.ifPresent(Conditional::run);
That would require a supporting class:
class Conditional implements BiPredicate<Enum1, EnumA>, Runnable
{
private final Enum1 var1;
private final EnumA varA;
private final Runnable runnable;
public Conditional(Enum1 var1, EnumA varA, Runnable runnable) {
this.var1 = var1;
this.varA = varA;
this.runnable = runnable;
}
#Override
public boolean test(Enum1 enum1, EnumA enumA) {
return var1 == enum1 && varA == enumA;
}
#Override
public void run() {
runnable.run();
}
}
Performance differences are probably negligible here, so I would focus on shortness and readability. So I would just simplify the if's a bit by using temporary variables:
boolean is_1 = (var1 == Enum1.COND_1);
boolean is_A = (varA == EnumA.COND_A);
if(is_1 && is_A)
{
// Code
}
else if(is_1 && !is_A)
{
// Code
}
else if(!is_1 && is_A)
{
// Code
}
else if(!is_1 && !is_A)
{
// Code
}
I prefer the if variant without nesting, since it is short and you have all the conditions in one line.
When stopping through the code during debugging, it can get tedious though, since you have to step over all preceding conditions, which is O(n). When executing the code, this shouldn't matter since the compiler will probably optimize the code.
There is no obvious best way, so you will have to experiment a bit.
I definitely prefer the flat version, it could just use a little less duplication:
// If you can't make the variables final, make some final copies
final Enum1 var1 = Enum1.COND_2;
final EnumA varA = EnumA.COND_B;
class Tester { // You could also make an anonymous BiPredicate<Enum1, EnumA>
boolean t(Enum1 v1, EnumA vA) {
return var1 == v1 && varA == vA;
}
};
Tester tes = new Tester();
if (tes.t(Enum1.COND_1, EnumA.COND_A)) {
// code
} else if (tes.t(Enum1.COND_1, EnumA.COND_B)) {
// code
} else if (tes.t(Enum1.COND_2, EnumA.COND_A)) {
// code
} else if (tes.t(Enum1.COND_2, EnumA.COND_B)) {
// code
}
Run it here. You could maybe make it even shorter and less redundant by doing a static import of the enums to avoid mentioning the enum names, e.g. tes.t(COND_1, COND_B). Or if you're willing to give up some compile time safety you can pass a string which gets converted to the two enum values, e.g. tes.t("COND_1 COND_A") (the implementation is left to the reader).
Maybe crazy idea but you could construct an int or a byte using the flags and use it in a single switch.
private int getIntegerStateForConditions(boolean... conditions ){
int state = 0;
int position = 0;
for(boolean condition: conditions){
if(condition){
state = state || (1 << position++);
}
}
return state;
}
...
switch(getIntegerStateForCondition((var1 == Enum1.COND_1), (var2 == EnumA.COND_A)){
case 0: ... //both condition false
case 1: ... //first condition true second false
case 2: ... //first false, second true ...
}
...
I think this is very far from being clean code but it looks better.
If I were you I would rely on bit flags in order to have only one byte (as you have only 4 use cases) to deal with and use a switch statement on this byte to manage all your use cases.
Something like this:
private static final int COND_2 = 1;
private static final int COND_B = 2;
private byte value;
public void setValue(Enum1 enum1) {
if (enum1 == Enum1.COND_1) {
this.value &= ~COND_2;
} else {
this.value |= COND_2;
}
}
public void setValue(EnumA enumA) {
if (enumA == EnumA.COND_A) {
this.value &= ~COND_B;
} else {
this.value |= COND_B;
}
}
public Enum1 getEnum1() {
return (this.value & COND_2) == COND_2 ? Enum1.COND_2 : Enum1.COND_1;
}
public EnumA getEnumA() {
return (this.value & COND_B) == COND_B ? EnumA.COND_B : EnumA.COND_A;
}
Then your tests would be:
switch (value) {
case 0 :
// 1-A;
break;
case 1 :
// 2-A;
break;
case 2 :
// 1-B;
break;
case 3 :
// 2-B;
break;
}
I would personally prefer this:
if(understandableNameInContextName1(var1, varA))
{
// Code
}
else if(understandableNameInContextName2(var1, varA))
{
// Code
}
else if(understandableNameInContextName3(var1, varA))
{
// Code
}
else if(understandableNameInContextName4(var1, varA))
{
// Code
}
private boolean understandableNameInContextName1(Object var1, Object varA){
return (var1 == Enum1.COND_1 && varA == EnumA.COND_A);
}
private boolean understandableNameInContextName2(Object var1, Object varA){
return (var1 == Enum1.COND_1 && varA == EnumA.COND_B);
}
private boolean understandableNameInContextName3(Object var1, Object varA){
return (var1 == Enum1.COND_2 && varA == EnumA.COND_A);
}
private boolean understandableNameInContextName4(Object var1, Object varA){
return (var1 == Enum1.COND_2 && varA == EnumA.COND_B);
}
And the names of the methods could be like, isOrderShippedAndDelivered(), isRequestSendAndAckRecieved().
The reason is that this is going to make the code a lot more readable.
Unless you have data that leads you back to these if statement there is not going to be much gain optimizing these.
See:
https://softwareengineering.stackexchange.com/questions/80084/is-premature-optimization-really-the-root-of-all-evil
Kind of depends on the complexity of the code and number of combinations but another option is a dictionary with the key comprising a Tuple of your enumerations and a value of a delegate to the code.
Hi I am working with the Stack class in java, the problem that I have is that in this Stack I want to insert (to push) elements of type String, but i also want to insert a tree, the code is the following:
public static void Expression(Stack<String> exp)
{
boolean error = false;
String leftExp,rightExp = "";
Stack<String> stackOp = new Stack<String>();
while(!exp.empty() && (error == false))
{
switch(elementType(exp.peek())){
case 'I':
error = true;
break;
case 'O':
if(stackOp.size() < 2)
error = true;
else
{
rightExp = stackOp.pop();
leftExp = stackOp.pop();
Tree subTree = new Tree();
subTree.insertNode(exp.peek());
subTree.insertNode(rightExp);
subTree.insertNode(leftExp);
stackOp.push(subTree);//here is were I have the mistake
}
break;
default:
stackOp.push(exp.peek());
}
}
}
public static char elementType(String car){
char c = 'Z';
if(car.equals("("))
c = 'I';
else if(car.equals(")"))
c = 'D';
else if(car.equals("+") || car.equals("-") || car.equals("*") || car.equals("/"))
c = 'O';
return c;
}
This code basically transforms a math expression into a binary tree, for this I need an input, which is the expression, an output which is the binary tree, and another local stack that contains variables, numbers, and subtrees. But how can i make a Stack that contains elements of different types?
Create a class that can hold anything you want to put on the stack -- I think using a string to designate your operation is a bit clumsy, but suit yourself. If you have a class that is StackElement, it can contain a type indicator (look into Java enums) and methods to do or obtain whatever you want.
You could define StackElement to contain a reference to one of several types, then also define all the methods of all the types it might contain; the ones that apply would be pass-throughs (if the type is an operation, a pass-through for getOperationType()), and the others would throw illegalOperationException, or something. So if you try to call getOperationType() on a value, it throws an exception, same for calling getValue() on an operation, etc.
A nice thing about doing it this way is that you do not have to do any instanceof testing of the types you have stored. You can declare your FILO queue to hold StackElement objects, create them with the types you want, and use them, all without instanceof or otherwise breaking OO style.
public class StackElement
{
private StackElementType type;
private StackOperation operation;
private StackValue value;
public StackElementType getType() { return type; }
public StackOperation getOperation()
{
switch (type)
{
case StackElementType.OPERATION: return operation;
default: throw IllegalOperationException
("getOperation() on type " + type.toString());
}
}
public StackValue getValue()
{
switch (type)
{
case StackElementType.VALUE: return value;
default: throw IllegalOperationException
("getValue on type " + type.toString());
}
}
}
I have these long statements that I will refer to as x,y etc. here.
My conditional statements' structure goes like this:
if(x || y || z || q){
if(x)
do someth
else if (y)
do something
if(z)
do something
else if(q)
do something
}
else
do smthing
Is there a better, shorter way to write this thing? Thanks
I don't see a big problem with how you write it now.
I do recommend using curly braces even for single statement if-blocks. This will help you avoid mistakes in case you have to add more code lines later (and might forget to add the curly braces then). I find it more readable as well.
The code would look like this then:
if (x || y || z || q) {
if (x) {
do something
} else if (y) {
do something
}
if (z) {
do something
} else if (q) {
do something
}
} else {
do something
}
Another variant that avoids the multiple checks and the errorprone complex logical expressions might be:
boolean conditionhandled = false;
if (x) {
do something
conditionhandled = true;
} else if (y) {
do something
conditionhandled = true;
}
if (z) {
do something
conditionhandled = true;
} else if (q) {
do something
conditionhandled = true;
}
if (!conditionhandled) {
do something
}
This seems pretty clear to me (and clear is good).
What you can do is first evaluate x,y,z and q and store those as variables so you don't have to do that twice.
Maybe this is a little easier to read. But now you will perform one extra check. If it is not mission critical code then maybe you can use the following:
if (x)
do something;
else if (y)
do something;
if (z)
do something;
else if(q)
do something;
if !(x || y || z || q)
do something completely different.
I'm not recommending the following, in fact, I think what you got is fine, but:
s = true;
if (x) {
do something;
s = false;
} else if (y) {
do something;
s = false;
}
if (z) {
do something;
s = false;
} else if (q) {
do something;
s = false;
}
if (s) {
so something;
}
Can you make some assumptions about x,y,z,q?
e.G. just one of them can be true. Than you could see it as a State
enum State {
X{
void doSomething(){
doItTheXWay();
}
},
Y{
void doSomething(){
doItTheYWay();
}
},
Z{
void doSomething(){
doItTheZWay();
}
},
Q{
void doSomething(){
doItTheQWay();
}
};
void doSomething(){
}
}
and in your code where you used the if statements
you could assign a state and just do the right thing
State state = getAState();
state.doSomething();
In case you don't like enums State could be an Interface and X to Q could be implementing classes.
The benefits in this case are in multiple usage of the same if else construct. Say some codelines later you would begin with
if(x)
do_the_next_thing_with_X();
...
or you could just extend your enum with another function and make one single call
state.doTheNextThing();