How To Improve Conditional Logic With Java 8 - java

I'm in the process of learning Java 8 and I wanted to know if there was a clean way to re-write the below code more efficiently in Java 8:
public static Map<String, Character> parseOrg(String org) {
Map<String, Character> map = new HashMap<String, Character>();
if (org != null && !org.isEmpty()) {
String modifiedString = trimOrg(org); //private method to substring
if (modifiedString.length() == 4) {
populateMap(modifiedString.charAt(modifiedString.length()-1), modifiedString.charAt(modifiedString.length()-2), modifiedString.charAt(modifiedString.length()-3), modifiedString.charAt(modifiedString.length()-4));
} else if (modifiedString.length == 3) {
populateMap(modifiedString.charAt(modifiedString.length()-1), modifiedString.charAt(modifiedString.length()-2), modifiedString.charAt(modifiedString.length()-3), null);
} else if (modifiedString.length == 2) {
populateMap(modifiedString.charAt(modifiedString.length()-1), modifiedString.charAt(modifiedString.length()-2), null, null);
} else if (modifiedString.length == 1) {
populateMap(modifiedString.charAt(modifiedString.length()-1), null, null, null);
}
} else {
LOG.error("Null org provided");
}
return map;
}
private static void populateMap(Map<String, Character> map, Character pos0, Character pos1, Character pos2, Character pos3) {
map.put("Position 3", pos3);
map.put("Position 2", pos2);
map.put("Position 1", pos1);
map.put("Position 0", pos0);
}

You could do something like this:
Runnable r = Arrays.asList(() -> {}, YourClass::doD, YourClass::doC, YourClass::doB, YourClass::doA, () -> {})
.get(Math.min(Math.max(0, org.length()), 4));
r.run();
But honestly, it's not worth it. Just use a switch.

Your question is strange because it appears to call the same doX() method every time. If that is really what you want, you can have a simple if-statement and supply it a range:
if(modifiedString.length() >= 1 && modifiedString.length() <= 4) {
doX();
}
If indeed you meant that they are different methods and do different things depending on the modifiedString.length value, you can use a switch-statement, as suggested by others:
switch (modifiedString.length()) {
case 1:
doA();
break;
case 2:
doB();
break;
case 3:
doC();
break;
case 4:
doD();
break;
default:
//if no case match
}

Related

Solution instead of writing a bunch of if's [duplicate]

This question already has answers here:
Quick alternative to lots of if statements
(5 answers)
Closed 2 years ago.
I am trying to write code to let the user pick addition, subtraction, multiplication or division. Once the user has picked one, the program will ask them what difficulty they want, etc. Instead of writing something like:
if (operation.equals("1") || operation.equals("addition")){
if(level.equals("1")) {
} else if (level.equals("2")){
}
} else if (operation.equals("2") || operation.equals("subtraction")) {
if(level.equals("1")) {
} else if (level.equals("2")){
}
} else if (operation.equals("3") || operation.equals("multiplication")) {
if(level.equals("1")) {
} else if (level.equals("2")){
}
} else if (operation.equals("4") || operation.equals("division")) {
if(level.equals("1")) {
} else if (level.equals("2")){
}
}
And so on.
Is there an easier way to write something like this? Instead of writing a bunch of if statements?
Try a switch, for your example it would look something like this.
switch(operation) {
case "1":
case "addition":
if(level.equals("1")) {
} else if (level.equals("2")){
}
break;
case "2":
case "subtraction":
...
break;
case "3":
.
.
.
default:
...
}
default is used when none of the other cases are true.
Here is a link to a tutorial if the answer wasn't helpful.
https://www.w3schools.com/java/java_switch.asp
You could map the string into an enumeration value and the use a switch / case.
import java.util.Map;
import java.util.HashMap;
class TestMain {
public enum OPERATOR_TYPE { ADDITION, SUBTRACTION, MULTIPLICATION, DIVISION };
public static Map<String, OPERATOR_TYPE> lookup = buildMap();
public static Map<String, OPERATOR_TYPE> buildMap() {
Map<String, OPERATOR_TYPE> rv = new HashMap<String, OPERATOR_TYPE>();
rv.put("addition", OPERATOR_TYPE.ADDITION);
rv.put("subtraction", OPERATOR_TYPE.SUBTRACTION);
rv.put("multiplication", OPERATOR_TYPE.MULTIPLICATION);
rv.put("division", OPERATOR_TYPE.DIVISION);
rv.put("1", OPERATOR_TYPE.ADDITION);
rv.put("2", OPERATOR_TYPE.SUBTRACTION);
rv.put("3", OPERATOR_TYPE.MULTIPLICATION);
rv.put("4", OPERATOR_TYPE.DIVISION);
return rv;
}
public static void main(String[] args) {
String opStr = System.console().readLine();
OPERATOR_TYPE op = lookup.get(opStr.toLowerCase());
switch (op) {
case ADDITION:
System.out.println("Addition");
break;
case SUBTRACTION:
System.out.println("Subtraction");
break;
case MULTIPLICATION:
System.out.println("Multiplication");
break;
case DIVISION:
System.out.println("Division");
break;
}
}
}

Switch case implementation in Java for an integer pair combination

I have following python code -
def get_subject_from_stream_id_and_subject_id(stream_id, subject_id):
#(stream_id, subject_id): ("subject_name")
return {
(1, 1): "Accounts",
(1, 2): "English",
(1, 3): "Organization of Commerce",
(2, 1): "Physics",
(2, 2): "English",
(2, 3): "Biology"
}.get((stream_id, subject_id), "None")
In this code, I want to get subject name from the integer pair combination i.e. stream_id, subject_id e.g. (1, 2) is for English. It was implemented using python tuple.
I want to implement the same piece of code in Java.
Could someone write this in a better way in Java?
public String getSubjectFromStreamIdAndSubjectId(int streamId, int subjectId) {
switch (streamId) {
case 1:
switch (subjectId) {
case 1:
return "Accounts";
case 2:
return "English";
case 3:
return "Organization of Commerce";
default:
return null;
}
case 2:
switch (subjectId) {
case 1:
return "Physics";
case 2:
return "English";
case 3:
return "Biology";
default:
return null;
}
default:
return null;
}
}
Thank you.
I don't like the solution presented in the duplication suggestion Switching on a pair of `int`s.
for two reasons:
The solution relies on external logic (Integer.valueOf() and switch of String) while it is not probable, the implementations may vary in future JDK releases
the switch-case was designed as shorthand for series of if statements. is not the best solution for mapping input to output values. A better solution is to utilize the Map data structure
The proper solution in my eyes would involve some kind Java Tuple. while there is no Tuple in the JDK, one can be easily constructed as user defined class. In fact, there is already an SO answer about that: A Java collection of value pairs? (tuples?)
so if we use the class from the above-mentioned answer as Map key, the solution is fairly easy and much more extensible (you could, for instance, load the map from an external resource like text file or DB table):
// initialized using instance initializer
Map<Pair<Integer, Integer>, String> streamIdAndSubjectIdMap = new HashMap<>()
{
{
put(new Pair(1, 1), "Accounts");
put(new Pair(1, 2), "English");
put(new Pair(1, 3), "Organization of Commerce");
}
};
public String getSubjectFromStreamIdAndSubjectId(int streamId, int subjectId) {
return streamIdAndSubjectIdMap.get(new Pair<>(streamId, subjectId));
}
Personally, i would really recommend to not use the switch statement here, since any hacks (like String concatenation) will just complicate things. However, you could refactor this method to use a regular if expression with a return statement.
public static String getSubject(int streamId, int subjectId) {
Pair<Integer> pair = Pair.of(streamId, subjectId);
if (pair.equals(Pair.of(1, 1))) {
return "Subject";
}
if (pair.equals(Pair.of(1, 2))) {
return "English";
}
if (pair.equals(Pair.of(1, 3))) {
return "Organization of Commerce";
}
if (pair.equals(Pair.of(2, 1))) {
return "Physics";
}
if (pair.equals(Pair.of(2, 2))) {
return "English";
}
if (pair.equals(Pair.of(2, 3))) {
return "Biology";
}
return null;
}
At least to my eye, this looks very clean and there is no need to use an if-else expression. One thing to note here is that the Pair class needs to be implemented correctly regarding equals and hashCode for this to work. An example implementation might be the following (tough it can still be extended):
public class Pair<T> {
private T first;
private T second;
public static <T> Pair<T> of(T first, T second) {
return new Pair<>(first, second);
}
private Pair(T first, T second) {
this.first = first;
this.second = second;
}
public T getFirst() {
return first;
}
public T getSecond() {
return second;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Pair<?> pair = (Pair<?>) o;
return Objects.equals(first, pair.first) &&
Objects.equals(second, pair.second);
}
#Override
public int hashCode() {
return Objects.hash(first, second);
}
}
It is not always recomended but in your case i would go with a nested ternary operator. If you have more combinations than given in your example this aproach could end in confusing, unreadable code. But if you have only those well defined cases:
public static String getSubjectFromStreamIdAndSubjectId(int stream_id, int subject_id) {
return stream_id == 1 ?
subject_id == 1 ? "Accounts" :
subject_id == 2 ? "English" :
subject_id == 3 ? "Organization of Commerce" : "None":
stream_id == 2 ?
subject_id == 1 ? "Physics" :
subject_id == 2 ? "English" :
subject_id == 3 ? "Biology" : "None":
"None";
}

How can I replace a switch in Java with a list that references a variable for each case?

I was unable to find a prior question like this here (which surprises me), so..
I have a working Java program where part of it analyzes typed input. Some input 'options' are the strings in the cases below.
switch (varName.toLowerCase()) {
case "steps":
common.steps = true;
break;
case "scale":
common.scale = true;
break;
case "float":
common.fracts = false;
break;
case "fraction":
common.fracts = true;
break;
case "spaces":
common.spaces = false;
break;
... etc.
}
In C or C++, I could shorten this code by making a list (which is a structure containing a string name and a variable pointer) such as
LIST varAction[] = { { "steps", &common.steps },
{ "scale", &common.scale },
.. etc.
};
and then simply checking in a loop with i = 0 thru size of the list
if ( strcmp(varAction[i].name, input) == 0) {
*varAction[i].pointer = condition;
}
The Java switch occurs more than once and is a maintenance problem, which is why I want a better way.
I could use a hashed index into an array using the hash of the string, but that would prevent me from using the specific variable names thru the code as needed, making that code less clear... i.e. I don't want to do (pseudo-code)
hashTable[varName] instead of (for example)
if ( common.fracts )
{ do something }
There must be a better way? Is there? Thanks in advance.
From your question, it's fairly clear that you know you can't do what you've said you'd do in C/C++, but just for others coming to the question: Java doesn't have references to variables.
It's tempting to push the question out a level: Look at why you have varName in the first place and see if you can avoid it.
The Java switch occurs more than once and is a maintenance problem, which is why I want a better way.
That suggests that common should have accessor function(s) for this information, so the switch exists only in one place (the getter) or two places (the getter and the setter).
void setThingy(String name, boolean value) {
switch (name.toLowerCase()) {
case "steps":
this.steps = value;
break;
case "scale":
this.scale = value;
break;
case "float":
this.fracts = value;
break;
case "fraction":
this.fracts = value;
break;
case "spaces":
this.spaces = value;
break;
// ... etc.
}
}
boolean getThingy(String name) {
switch (name.toLowerCase()) {
case "steps":
return common.steps;
case "scale":
return common.scale;
case "float":
return this.fracts;
case "fraction":
return this.fracts;
case "spaces":
return this.spaces;
// ... etc.
}
}
If common's class isn't something you can change, a static utility function somewhere would also work, but better if it's in the class if possible.
With Java 8+ you could use something like:
Map<String, Runnable> actions = new HashMap<> ();
actions.put("steps", () -> common.steps = true);
actions.put("scale", () -> common.scales = true);
//etc.
then in your code:
actions.get(varName.toLowerCase()).run(); //need null check
You could do it with Java 7- too using anonymous classes but it would be more verbose.
Here’s an option, developing my idea from the comment just a little bit. Not sure whether you will like it, I’d like to offer it in case.
public class Common {
private Map<String, Boolean> options = new HashMap<>();
public void setOption(String varName, boolean condition) {
options.put(varName.toLowerCase(), condition);
}
public boolean isSteps() { return options.get("steps"); }
public boolean isFracts() { return options.get("fractions"); }
public boolean isScale() { return options.get("scale"); }
}
You may want to put in some defense, for instance to avoid setting non-existing options.
Edit: Drawing on David Foerster’s comments on enums, here’s a solution using them:
public enum Option {
steps, scale, fraction;
private boolean option = false;
public static void setOption(String varName, boolean condition) {
valueOf(varName.toLowerCase()).option = condition;
}
public boolean isSet() {
return option;
}
}
Now the lookup happens in the setter, not in the getter. Defence against setting non-existing options is built-in: you will get an exception if you try, this behaviour can of course be modified if you prefer. The solution is quite extensible, it’s easy to add more enum constants if the need arises.
Warning: It's been a while since I last wrote some Java, and this is probably against best practices, so continue with care! Also it's just a quick and dirty example, I wrote this on a (not up to date) mobile phone...
You could try to use reflection:
class Common {
public boolean a;
public boolean b;
public boolean tryToSet(String field, boolean value) throws java.lang.Exception {
Class<?> cl = this.getClass();
try {
Field f = cl.getDeclaredField(field);
f.setBoolean(this, value);
return true;
} catch(NoSuchFieldException e) {
return false;
}
}
}
Returning a boolean gives you the possibility to implement a "default case":
if (! c.tryToSet("x", false)) {
System.out.println("some default case");
}
Try this:
import java.util.Scanner;
public class TestCases
{
static boolean steps = false;
static boolean fracts;
static boolean scale;
public static void main( String[] args )
{
Scanner input = new Scanner( System.in );
System.out.println( "Type the input" );
String typedInput = input.nextLine();
Object[][] tests = { { "steps", steps }, { "float", fracts }, { "scale", scale } };
for( int i = 0; i < tests.length; i++ )
{
if( typedInput.equals( tests[ i ][ 0 ] ) )
{
tests[ i ][ 1 ] = true;
break;
}
}
for( int i = 0; i < tests.length; i++ )
{
for( int j = 0; j < tests[ i ].length; j++ )
{
System.out.print( tests[ i ][ j ] + " " );
}
System.out.println();
}
}
}
All necessary conversions are automatically done.

Regarding Switch conditional statement

I have the below piece of code that I have developed ..
public byte determineCardType(final IInput inputData) {
byte cardType = UNKNOWN_CARD;
try {
if (isWagRewardsLoyaltyCard(inputData))
cardType = WAG_LOYALTY_CARD_TYPE;
else if (isDRCard(inputData)) //checking that card scanned and swiped is a DR Card
cardType = DR_CARD_TYPE;
else if (isWagRewardsPartnerCard(inputData))
cardType = AARP_CARD_TYPE;
return cardType;
} catch (Exception e) {
return UNKNOWN_CARD;
}
}
please advise me can the above code can be adjusted in switch loop, if yes then please advise, Thanks in advance.
the other code that is linked to it...
if((aarpCardSupport.isAARPCard(input))||(determineCardType(input)==DR_CARD_TYPE)) {
return true;
} else if((isDRCard(input))&&(isDRLoayltyEnabled())) { //would return 1 for DR card only when isDRLoayltyEnabled returns true
return true;
}
return false ;
Switch won't help you, but conditional expressions can:
return isWagRewardsLoyaltyCard(inputData) ? WAG_LOYALTY_CARD_TYPE
: isDRCard(inputData) ? DR_CARD_TYPE
: isWagRewardsPartnerCard(inputData) ? AARP_CARD_TYPE
: UNKNOWN_CARD;
I would strongly recommend against catching Exception, btw. Catch specific exception types if you must - although in that case I'd at least log the error before returning.
EDIT: As for the second piece of code, it looks like you just want:
return aarpCardSupport.isAARPCard(input)
|| determineCardType(input) == DR_CARD_TYPE
|| (isDRCard(input) && isDRLoayltyEnabled);
Although why determineCardType(input) would return something other than DR_CARD_TYPE when isDRCard(input) returns true is a mystery...
Don't do it. If you must do it, you could do it like this:
public byte determineCardType (final IInput inputData) {
byte cardType = UNKNOWN_CARD;
try {
switch (isWagRewardsLoyaltyCard (inputData) ? 1 :
(isDRCard (inputData) ? 2 : (isWagRewardsPartnerCard (inputData) ? 3 : 4)))
{
case 1: cardType = WAG_LOYALTY_CARD_TYPE; break;
case 2: cardType = DR_CARD_TYPE; break;
case 3: cardType = AARP_CARD_TYPE; break;
default: // UNKNOWN_CARD already default
}
return cardType;
} catch (CardException ce) {
return UNKNOWN_CARD;
}
}
}
But since you return a cardType as byte, you can switch later, after setting the type. This code is harder to read than your code. Jons code is at least lean.
I see you're new to switch statements. So I elaborate a little.
A switch statement is useful if your input is in Integral form (int, byte, short, Enum), and if you can match it against a - mostly medium short list of values.
And if you otherwise would use a sequence of if/else statements. Case statements needn't be mutual exclusive, but most times they are.
In your case, you call 3 methods which return booleans, so the input isn't integral. But your output is.
Later in the code, you could write:
byte cardType = determineCardType (inputDate);
switch (cardType)
{
case WAG_LOYALTY_CARD_TYPE: doWlct (foo, bar); break;
case DR_CARD_TYPE: doDct (); break;
case AARP_CARD_TYPE: doAct (baz); foobar (); break;
case UNKNOWN_CARD: System.err.println ("Unknown card");
}
Else you would have to write:
if (cardType == WAG_LOYALTY_CARD_TYPE)
doWlct (foo, bar);
else if (cardType == DR_CARD_TYPE)
doDct ();
else if (cardType == AARP_CARD_TYPE) {
doAct (baz);
foobar ();
}
else ...
Since Java 1.7 switch over Strings is possible as well, but until then, you could only switch over integral types, and the case labels have to be literally constant and known at compile time.
In OOP, switch statements are often abandoned in favor of dynamic dispatch.
interface Card {
public abstract int authenticate ();
}
class WagLoyalityCard implements Card {
public int authenticate () {
doWlct (foo, bar);
}
}
class DrCard implements Card {
public int authenticate () {
doDct ();
}
}
// ... and so on
Card card = new DrCard ();
// authenticate:
card.authenticate ();
// depending on the card type, DrCard.authenticate () or
// WagCard.authenticate () gets called.

Use string in switch case in java

I need to change the following if's to a switch-case while checking for a String, to improve the cyclomatic complexity.
String value = some methodx;
if ("apple".equals(value)) {
method1;
}
if ("carrot".equals(value)) {
method2;
}
if ("mango".equals(value)) {
method3;
}
if ("orange".equals(value)) {
method4;
}
But I am not sure what value I'm going to get.
Java (before version 7) does not support String in switch/case. But you can achieve the desired result by using an enum.
private enum Fruit {
apple, carrot, mango, orange;
}
String value; // assume input
Fruit fruit = Fruit.valueOf(value); // surround with try/catch
switch(fruit) {
case apple:
method1;
break;
case carrot:
method2;
break;
// etc...
}
Everybody is using at least Java 7 now, right? Here is the answer to the original problem:
String myString = getFruitString();
switch (myString) {
case "apple":
method1();
break;
case "carrot":
method2();
break;
case "mango":
method3();
break;
case "orange":
method4();
break;
}
Notes
The case statements are equivalent to using String.equals.
As usual, String matching is case sensitive.
According to the docs, this is generally faster than using chained if-else statements (as in cHao's answer).
Learn to use else.
Since value will never be equal to two unequal strings at once, there are only 5 possible outcomes -- one for each value you care about, plus one for "none of the above". But because your code doesn't eliminate the tests that can't pass, it has 16 "possible" paths (2 ^ the number of tests), of which most will never be followed.
With else, the only paths that exist are the 5 that can actually happen.
String value = some methodx;
if ("apple".equals(value )) {
method1;
}
else if ("carrot".equals(value )) {
method2;
}
else if ("mango".equals(value )) {
method3;
}
else if ("orance".equals(value )) {
method4;
}
Or start using JDK 7, which includes the ability to use strings in a switch statement. Course, Java will just compile the switch into an if/else like construct anyway...
To reduce cyclomatic complexity use a map:
Map<String,Callable<Object>> map = new HashMap < > ( ) ;
map . put ( "apple" , new Callable<Object> () { public Object call ( method1 ( ) ; return null ; } ) ;
...
map . get ( x ) . call ( ) ;
or polymorphism
Just to make concrete emory's answer, the executable code is the following :
Map<String,Callable<USer>> map = new HashMap<String,Callable<User>>();
map.put( "test" , new Callable<User> () { public User call (){ return fillUser("test" ); }} ) ;
map.put( "admin" , new Callable<Utente> () { public Utente call (){ return fillUser("admin" ); }} ) ;
where user is a POJO, and then
User user = map.get(USERNAME).call();
finally the called method is somewhere :
private User fillUser(String x){
User user = new User();
// set something in User
return user;
}
Java does not support Switch-case with String. I guess this link can help you. :)
Here is a possible pre-1.7 way, which I can't recommend:
public class PoorSwitch
{
final static public int poorHash (String s) {
long l = 0L;
for (char c: s.toCharArray ()) {
l = 97*l + c;
}
return (int) l;
}
public static void main (String args[])
{
String param = "foo";
if (args.length == 1)
{
param = args[0];
}
// uncomment these lines, to evaluate your hash
// test ("foo");
// test ("bar");
switch (poorHash (param)) {
// this doesn't work, since you need a literal constant
// so we have to evaluate our hash beforehand:
// case poorHash ("foo"): {
case 970596: {
System.out.println ("Foo!");
break;
}
// case poorHash ("bar"): {
case 931605: {
System.out.println ("Bar!");
break;
}
default: {
System.out.println ("unknown\t" + param);
break;
}
}
}
public static void test (String s)
{
System.out.println ("Hash:\t " + s + " =\t" + poorHash (s));
}
}
Maybe you could work with such a trick in a generated code. Else I can't recommend it. Not so much that the possibility of a hash collision makes me worry, but if something is mixed up (cut and paste), it is hard to find the error. 931605 is not a good documentation.
Take it just as proof of concept, as curiosity.
We can apply Switch just on data type compatible int :short,Shor,byte,Byte,int,Integer,char,Character or enum type.
Evaluating String variables with a switch statement have been implemented in Java SE 7, and hence it only works in java 7. You can also have a look at how this new feature is implemented in JDK 7.
Java 8 supports string switchcase.
String type = "apple";
switch(type){
case "apple":
//statements
break;
default:
//statements
break; }
String name,lname;
name= JOptionPane.showInputDialog(null,"Enter your name");
lname= JOptionPane.showInputDialog(null,"Enter your father name");
if(name.equals("Ahmad")){
JOptionPane.showMessageDialog(null,"welcome "+name);
}
if(lname.equals("Khan"))
JOptionPane.showMessageDialog(null,"Name : "+name +"\nLast name :"+lname );
else {
JOptionPane.showMessageDialog(null,"try again " );
}
}}
Not very pretty but here is another way:
String runFct =
queryType.equals("eq") ? "method1":
queryType.equals("L_L")? "method2":
queryType.equals("L_R")? "method3":
queryType.equals("L_LR")? "method4":
"method5";
Method m = this.getClass().getMethod(runFct);
m.invoke(this);
String value = someMethod();
switch(0) {
default:
if ("apple".equals(value)) {
method1();
break;
}
if ("carrot".equals(value)) {
method2();
break;
}
if ("mango".equals(value)) {
method3();
break;
}
if ("orance".equals(value)) {
method4();
break;
}
}

Categories

Resources