Quick alternative to lots of if statements - java

I'm beginner at java, and I'm making a simple program where I type in something, and if what I type in matches one of the things on the "database" then it'll print some text. Is there a simpler way to check this rather than doing this:
int 1;
int 2;
int 3;
etc.
if([USER INPUT].equals("1")) {
System.out.println("TEST");
}
400 times.

Use a switch statement or a HashMap.
Switch statement: Readable, but compiles similarly (if not identically) to an if-else chain.
switch([USER_INPUT]) {
case 1:
System.out.println("TEST");
break;
case 2:
System.out.println("HELLO");
break;
// And so on.
}
Hash Map: Much more readable and simpler. This is preferred.
// Initialization.
Map<Integer,String> map = new HashMap<Integer,String>();
map.put(1,"TEST");
map.put(2,"HELLO");
// Printing.
String s = map.get(USER_INPUT);
if (s == null)
System.out.println("Key doesn't exist.");
System.out.println(s);

Use a HashMap, with key as Integer, and value as text.
System.out.println(myMap.get(USER_INPUT));
Where you have done myMap.put(1, "TEST"); etc, this keeps your code much OO.
the underlying bytecode of switch and if are very comparable, and personally don't see any advantage of switching to switch (unless you want fall through, which means don't include break statement).

A fun alternative would be to use an enum. This would work if you want to define all of the values in a class. It would simplify the code used to get the text value. And it gives you some more fun options beyond what a switch statement would give you.
enum NumberText {
HELLO(1),
WORLD(2);
private static final HashMap<Integer,NumberText> map = new HashMap<Integer,NumberText>();
static{
for (ConnectionGenerator c : ConnectionGenerator.values()) {
map.put(c.code, c);
}
}
Integer code;
NumberText(Integer pCode) {
this.code = pCode;
}
Static ConnectionGenerator getTextFor(Integer code) {
return map.get(code);
}
}
Then to get the text, simply do this:
NumberText nt = NumberText.getTextFor(USER_INPUT);
System.out.println(nt);
You can get fancier and put an additional constructor variable into the enum and have a specific string of text.
enum NumberText {
HELLO(1, "Hello to You"),
GOODBYE(2, "Goodbye");
private static final HashMap<Integer,NumberText> map = new HashMap<Integer,NumberText>();
static{
for (ConnectionGenerator c : ConnectionGenerator.values()) {
map.put(c.code, c);
}
}
Integer code;
String text;
NumberText(Integer pCode, String pText) {
this.code = pCode;
this.text = pText;
}
ConnectionGenerator getNumberTextFor(Integer code) {
return map.get(code);
}
getText() {
return this.text;
}
}
Then you could get the text like this:
NumberText.getNumberTextFor(USER_INPUT).getText();

Use a switch statement.
switch(i){
case 1:
System.out.println("Hi");
break;
case 2:
System.out.println("Ok");
break;
// ...
}

You can use a switch statement.
Here's a quick tutorial and some more in-depth explanation.
http://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html

Related

Changing the name of the method called dynamically in java

I have an object "JudgesSubmission" with the following methods:
public String getInnovationGrade1() {
return innovationGrade1;
}
public String getInnovationGrade2() {
return innovationGrade2;
}
public String getInnovationGrade3() {
return innovationGrade3;
}
public String getInnovationGrade4() {
return innovationGrade4;
}
Now, when calling these methods, I want to put them in a loop where the called method name gets the index of the loop attached to its end changing the method called. Is this possible?
For example, the following code would never work, but I am writing it to explain what I need:
judgesSubmission metricScores= new judgesSubmission;
int metricSum=0;
for (int i=0;i<4;i++){
metricSum=metricSum
Integer.parseInt(metricScores.getInnovationGrade+"i"());
}
Is there a way to do that or do I always have the full method name written?
What you want to do is not possible... but with reflection such as :
MyObject.class.getMethod("mymethod"+i);
Without reflection you could use a Supplier<String> :
public void process(Supplier<String>... suppliers){
judgesSubmission metricScores= new judgesSubmission;
int metricSum=0;
for (Supplier<String> supplier : suppliers){
Integer.parseInt(supplier.get());
}
}
And call it such as :
MyObject myObject = new MyObject();
process(()->myObject.getInnovationGrade1(),
()->myObject.getInnovationGrade2(),
()->myObject.getInnovationGrade3(),
()->myObject.getInnovationGrade4());
It is not possible without reflection (and is highly not recommended)
Instead you may want to use other methods:
An array of the data (either replacing the 4 methods, or in addition)
String[] getInnovationGrades()
{
return new String[]{innovationGrade1, innovationGrade2, innovationGrade3, innovationGrade4};
}
Then later you can use
for(String innovationGrade : getInnovationGrades())
//do stuff
An argument to get the data you want
String getInnovationGrade(int i)
{
switch(i)
{
case 1:
return getInnovationGrade1();
case 2:
return getInnovationGrade2();
case 3:
return getInnovationGrade3();
case 4:
return getInnovationGrade4();
default:
return ""; //or throw exception, depends on how you wish to handle errors
}
}
Then later you can use
for(int i = 1; i <= 4; i++)
getInnovationGrade(i); //and do stuff with it

Any better way of assigning String value, eliminating multiple If Else blocks in Java

I wanted to assign a String constant based on other string value which is sent as a parameter from the other program. like shown below
test is the String variable sent from Main program, in this helper method I need to compare and assign some other string value and send the result back to Main Program
For example :
public String assignString(String test){
String returnString = new String();
if(test.startsWith("hi"))
returnString = "Condition 1";
else if(test.startsWith("hello"))
returnString = "Hello Welcome";
else if(test.startsWith("Sunday"))
returnString = "Today is Sunday";
else if(test.startsWith("monday"))
returnString = "today is Monday";
else{
returnString = "today is good day";
}
return returnString;
}
Above way is one way of doing.
Other would be using Switch statement
But I am trying to find any other alternative and better way of implementing the same solution.
SOme how I am not satisfied with Lot of if Else statements and its cumbersome to maintain. In the above example I have used only 3, but in real time application its more than 15 checks I need to do.
Please suggest and Thanks in advance
Dave Newton suggestion is good.
A alternative and close way would be to introduce a class with two methods :
boolean matches(String test)
String getValue()
This way avoids the infernal switch case but allows also to isolate the logic rule. In this way you can unit test it easily and also reuse the class for similar processing as it has a broad contract matcher.
If it makes sense, you could even introduce a Rule interface.
public class RuleImpl {
private String startPattern;
private String value;
public RuleImpl(String startPattern, String value){
this.startPattern = startPattern;
this.value = value;
}
public boolean matches(String test){
if(test.startsWith(startPattern)){
return true;
}
return false;
}
public String getValue(){
return value;
}
}
You can write now :
List<RuleImpl> rules = Arrays.asList(
new RuleImpl("monday", "today is Monday"),
new RuleImpl("hello", "Hello Welcome"),
new RuleImpl("Sunday", "Today is Sunday")
);
And the processing could be now :
String test = "string to test";
for (RuleImpl rule : rules){
if (rule.matches(test)){
return rule.getValue();
}
}
return null;
The same logic as if-else but with a properly formated nested ternary operators could look like :
public static String assignString(String test){
return test.startsWith("hi") ?"Condition 1"
:test.startsWith("hello") ?"Hello Welcome"
:test.startsWith("Sunday") ?"Today is Sunday"
:test.startsWith("monday") ?"today is Monday"
:"today is good day";
}
If you can get away with not using String.startsWith, you might try something like this:
private static final Map<String, String> greetings = new HashMap<>();
static {
greetings.put("hi", "Condition 1");
greetings.put("hello", "Hello Welcome");
greetings.put("sunday", "Today is Sunday");
greetings.put("monday", "today is Monday");
}
public String assignString(String test) {
return greetings.getOrDefault(test.toLowerCase(), "today is good day");
}

More elegant syntax for logical operators for equals() method in Java?

I have some code like so:
if (input.equals("north") || input.equals("n")) { direction = Cardinals.NORTH; }
Is there any way to use a less verbose syntax for this, along the lines of:
if (input.equals("north" || "n") { direction = Cardinals.NORTH; }
I know this doesn't work, but I hope there is some equivalent?
Starting from Java 7 and assuming input to be a String, you can switch on String literals like so
switch(input) {
case "n":
case "north":
direction = Cardinals.NORTH;
break;
case "s":
...
}
and so on. Very readable!
EDIT: As proposed by #DaoWen in the comments, if you extract this switch into its own method (say findCardinal(input)), you can drop the break; and just return the correct Cardinal, which will lead to a nice one-liner where you need the direction like so: direction = findCardinal(input);.
Why not using the enum directly:
public enum Cardinals {
NORTH("n", "north"),
SOUTH("s", "south"),
EAST("e", "east"),
WEST("w", "west"),
ERROR("", "");
private final List<String> matchingStrings;
Cardinals(String... matchingStringsAr) {
this.matchingStrings = Arrays.asList(matchingStringsAr);
}
public static Cardinals formStr(String str){
for (Cardinals cardinals : Cardinals.values()){
if (cardinals.matchingStrings.contains(str)){
return cardinals;
}
}
return ERROR;
}
}
// .....
Cardinals direction = Cardinals.formStr("n");
You could use a Map -
Map<String, Cardinals> cardinals = new HashMap<>();
cardinals.put("north", Cardinals.NORTH);
cardinals.put("n", Cardinals.NORTH);
cardinals.put("s", Cardinals.SOUTH); // if you also have SOUTH, I mean
Store your Cardinals here, and then return it like this -
direction = cardinals.get(your_string_key);
You can make a list of the options if there are only a few:
import java.util.Arrays;
//....
if (Arrays.asList("n", "north").contains(input)) {
direction = Cardinals.NORTH;
}
However, the Map idea is probably better if all you're doing based off this is a single assignment. If you'd like to make this even more succinct, you could also lift this into a utility method:
public static boolean checkEq(Object needle, Object... haystack) {
return Arrays.asList(haystack).contains(needle);
}
//....
if (checkEq(input, "n", "north")) {
direction = Cardinals.NORTH;
}
String[] options = { "night","n" };
if (Arrays.asList(options).contains(input))
{ direction = Cardinals.NORTH; }

Can I avoid multiple if-else statements in this case?

What is the better way to handle this piece of code
I have a method as shown below , which will accept a parameter i String and returns a int value
below code works fine .
public static int getLoggerLevel(String level)
{
int loglevel = 3;
if (level.equals("INFO")) {
loglevel = 3;
}
else if (level.equals("ERROR")) {
loglevel = 4;
} else if (level.equals("FATAL")) {
loglevel = 5;
}
return loglevel;
}
I thought of putting the Key Values in Map , and retrieve that based on the String , but dont want to create an Map i guess which will consume memory
Assuming Java 7:
public static int getLoggerLevel(String level)
{
switch(level){
case "ERROR": return 4;
case "FATAL": return 5;
case "INFO":
default: return 3;
}
}
On a more general note, you should probably use an enum instead of a string for this sort of thing. It's a perfect fit. Moreover, it will also work in Java 6.
Here is an alternative solution using enums:
public enum SeverityLevel {
ERROR, FATAL, INFO
}
public static int getLoggerLevel(SeverityLevel level)
{
switch(level){
case ERROR: return 4;
case FATAL: return 5;
case INFO:
default: return 3;
}
}
No quotes around them, they are enum values, this approach also mitigates bugs caused by typing errors. The big bonus is conceptual though, getLoggerLevel now accepts a SeverityLevel and not a string.
A map would work and would hardly consume any memory, especially if scoped appropriately so that it was just created once.
Use Switch- case simple to read and understand.
public static int getLoggerLevel(String level)
{
switch(level){
case "ERROR": return 4;
case "FATAL": return 5;
case "INFO":
default: return 3;
}
}
Also, in your code , you can avoid 1st if block.
And once you found correct match.. use return there which will avoid checking further code.
which will make your code as below
public static int getLoggerLevel(String level)
{
int loglevel = 3;
if (level.equals("ERROR")) {
return 4;
} else if (level.equals("FATAL")) {
return 5;
}
return loglevel;
}

Returning switch capable value based on String

Not sure how I'm going to attack this.
Basically what I have is input of varying length, one or multiple times, that will cause an action. It being from typed input, file etc.
I have no idea on by what and how to tackle this. Would it be best to have a function returning an int that correspond to an public static final int FOO = 1;, an enum, an other way?
What I have as of now is a series of if statements as in:
if (str.equals("foo") || str.equals("F")) {
blah;
} else if (str.equals("beach")) {
more blah;
}
Is this good as any, or is there a better way? Have had a peek at enum but seems like that is more to it then in e.g. C. This is probably wrong, but would it be something in the direction of this?
class Mother
{
HappyCamping() {
switch (ValInput(str)) {
case FOO: do fo; break;
case BAR: do bar; break;
case BAZ: do fo bar: break
...
}
private enum ValInput(String str)
{
FOO("foo"), BAR("bar"), BAZ("baz");
private int value;
private ValInput(String str) {
if (str.equals("blah"))
this.value = 1;
...
}
}
}
Point being having a cleaner approach and separate out the "parsing" from the main routine. What would be a good way here?
One approach would be to write a parser that returns tokens. The tokens could be represented by ints or Enums. That modularizes your code in a way you suggest you want.
The other way is to use enums.
public enum Token {
FOO("foo", "f"),
BAR("bar", "b");
private String keyword;
private String abbreviation;
private Token(String keyword, String abbreviation) {
this.keyword = keyword;
this.abbreviation = abbreviation;
}
public String getKeyword() {
return this.keyword;
}
public String getAbbreviation() {
return this.abbreviation;
}
public static Token valueOf(String s) {
for (Token token : values()) {
if (token.getKeyword().equals(s) || token.getAbbreviation().equals(s)) {
return token;
}
}
throw new IllegalArgumentException("No such keyword: " + s);
}
}
Then you can do something like:
switch (Token.valueOf(inputString)) {
case BAR : doBarStuff(); return;
case FOO : doFooStuff(); return;
}
Is this good as any, or is there a better way? Have had a peek at enum but seems like that is more to it then in e.g. C. This is probably wrong, but would it be something in the direction of this?
Then go learn how enum works. Don't avoid a feature that may solve your problem just because it has more features. Chances are your design will want to make use of Java-style enums if you want a fixed set of actions.
enum Action { CLICK("click"), CLEAR("erase"); }
etc. is a good start.
Java (I think since 6, possibly 7) also supports switch taking strings instead of integer or enum values.
Not sure that I understand the entire problem, but you can convert a string to an enum easily in Java.
If the entry strings are limited and predefined, and you want to parse it as an enum using
EnumType.valueOf("foo")
I recommend reading on Java enums, they are quite powerful compared to C enums.
In Java 7 you can use String in a switch expression. Refer to this article:
switch (str) {
case "blah":
// some action
break;
case "beach":
// another blah
break;
default:
// default action
break;
}
Your if statements seems the most logical way to tackle this problem. No need to make your life complex, just keep it simple. Any other method has trade offs and complexity.
Consider using a Map and the command pattern as shown here. You can hide all map a keyword to functionality and never have to use an if or switch.

Categories