I have this piece of code right here , I really don't get it why is that there is a "this" keyword in the switch statement, take a look at this code
public enum InstrumentType{
GUITAR,BANJO,MANDOLIN,DOBRO, FIDDLE ,BASS,
public String toString(){
switch(this){
case GUITAR:
return "Guitar";
case BANJO:
return "Banjo";
case DOBRO:
return "Dobro";
case FIDDLE:
return "Fiddle";
case BASS:
return "Bass";
case MANDOLIN:
return "Mandolin";
default:
return "Unspecified";
}
}
}
Here this refers to the current InstrumentType value
static void MyFunc( )
{
InstrumentType f = InstrumentType.GUITAR;
String s = f.toString();
}
When f.toString() is invoked. this will have GUITAR value
It refers to the current instance.
If you had an anum instance "foo":
String s = foo.toString();
this points to its container class/struct/enum like elements. in this case, this is used for InstrumentType. it's a basic rule for most of the OO languages.
Related
So I'm currently doing a first year university assignment and I'm a little stuck on one of the questions. It goes as such.
Modify the setType() and setPlan() methods to return a boolean true/false if the chosen type or plan was invalid. I.e if the type was "Bogus", ignore the type, and return a "false" to the call. Modify the Test class to add an "if" statement that will report a false call.
My current line of code for the method looks like this:
public void setType(String newType) {
switch (newType) {
case "Basic":
mType = newType;
break
case "Enhanced":
mType = newType;
break
default:
break
}
My question is, how do I go about adding an if statement and does anything need to be changed to make the void method return a true/false value?
Try this:
public boolean setType(String newType) {
switch (newType) {
case "Basic":
case "Enhanced":
mType = newType;
return true;
default:
return false;
}
}
You don't actually need an extra if statement for doing this, and you can check two or more cases in a switch by using a fallthrough (two or more consecutive case).
You could define an array with all valid types in some globally accessible spot in your app:
public static final String[] VALID_TYPES = {"Basic","Enhanced"};
and then have a method that just iterates all those types and checks if a given value matches one of them:
public static boolean isValidType(String candidate){
for(String validType : VALID_TYPES){
if(validType.equals(candidate)){
return true;
}
}
return false;
}
The nice thing about this - in contrast to using switch statements - is that you can easily modifiy the list of valid types (add/change/remove types) without the need to touch your method that checks a given type for validity. So it's easy to maintain and less error-prone (in a switch, you might forget to add a case statement for each possible value, or you might forget to add a break statement somewhere, etc)
Best practice would say this is "parameter checking", and it's cleaner too to fail early:
public boolean setType(String newType) {
if (!newType.matches("Basic|Enhanced")) {
return false;
}
type = newType; // or whatever you need to do
return true;
}
Options for testing also include:
if (!Arrays.asList("Basic", "Enhanced").contains(newType))
which also neatly handles newType being null without extra code.
But the best way to deal with this is to use an enum, which would not allow bad values in the first place.
The other answers are good. Here's my take. The ternary operator, ? and : expression, is logically an "if then else".
public boolean setType(String newType) {
boolean result = (newType.equals("Basic") || newType.equals("Enhanced"));
mType = result ? newType : mType;
return result;
}
public class YourClass{
private String mType;
private static final List<String> VALID_TYPES = Arrays.asList("Basic","Enhanced");
public boolean setType(String newType){
if(!VALID_TYPES.contains(newType)){
return false;
}
mType = newType;
return true;
}
}
And similar for the setPlan method, just define another list of VALID_PLANS.
And about your test class:
if(!yourClassObject.setType("Some Invalid Type")){
System.err.println("Invalid type!");
}
adding a boolean property of class,like this:
public class Test
{
private boolean flag;
}
I'm reading some Java textbooks trying to learn a new language and I came across this method.
private String monthName (int month) { // bad example since this method needs to return a String
switch (month) {
case 1:
return "January";
case 2:
return "February";
...
case 12:
return "December";
}
}
The statement following this code says:
The compiler will reject this code because it is possible to reach the
end with- out returning a value.
So in Java, I assume that if a method has the word "String" before the method name, it MUST return a String? The problem with this switch statement is that perhaps no case statement condition is satisfied and execution just drops out of the bottom? Is it necessary for methods that are not labeled to void to ALWAYS return a value?
A method signature is a contract that specifies what it takes as arguments and what it is obligated to return. A method declared to return something other than void must either return something or throw something, it's not allowed to fall off the end without returning anything (if it did, the variable getting assigned the return value from the method call would still have to be assigned something).
Specifically, if a method is declared to return a String, either every possible path taken through that method must end with returning a String, returning null (null is an allowed value of any reference type), or throwing an instance of Throwable. That's what the quoted passage is telling you, the compiler can detect that you haven't done this and will complain about it.
Here you could have your code throw an exception if the integer passed in is not in the expected range. It's a good thing to have your methods validate that they are receiving reasonable values for their arguments. Using a default value or returning null is not as good because instead of exposing the problem immediately it sticks the caller with a value that may not make sense for it, and makes it harder to debug what happened because the place where the error is visible may be a long way from where the cause of the problem originated. This method could be written as:
private String monthName (int month) { // bad example since this method needs to return a String
switch (month) {
case 1:
return "January";
case 2:
return "February";
...
case 12:
return "December";
default:
throw new IllegalArgumentException("found unexpected value " + month);
}
}
so that the compiler won't complain, and any out-of-range values will come to your attention.
Be aware:
There is a convention many people adhere to that advocates that all switches should contain a default case, so that unhandled cases are not passed over silently.
The java.util Date/Calendar API numbers months from 0, not from 1 as in your example; if you use a Calendar to find a month and pass that int to this method it would be easy to return the wrong month. Error handling as near to the source as possible makes tracking down problems much easier.
No, I think the book is referring to the fact, that the compiler will go through the Switch statement, and if it doesn't hit case 1,2 or 12, then it won't return anything at all.
Any method that has a return type, must return that type. So in this example, you MUST return a String.
To fix that code, I'd do something like the following:
private String monthName (int month) { // bad example since this method needs to return a String
String retVal = "";
switch (month) {
case 1:
retVal = "January";
break; // essential in a switch statement
case 2:
retVal = "February";
break;
case 12:
retVal = "December";
break;
default:
retVal = "Invalid Month number";
break;
}
return retVal;
}
You may notice that I set the return value at the top of the method, then simply assign a value to it within the switch statement, then simply return the retVal at the end of the function. That way the compiler is satisfied. Another issue with your code sample is there are no break(s) in your switch/case block.
If that happens, then every single line would be executed regardless of which case is hit.
if a method has the word "String" before the method name, it MUST return a String
That is almost correct, it could also return a special value, 'null'.
It is possible for method to not return a value, in this case the String would instead be replaced with void, which indicates no return value.
Yes. A method that has a return type (in this case String) must always return a String.
Interestingly in this case, it's not straightforward why there is a compiler error. Let's simply to show why.
// Won't compile
String foo(boolean a) {
if (a) {
return "foo";
}
}
This throws a compiler error because not all branches of the program return something. It's possible to get to the end of the function (if a is not true) and still have not returned a String.
But it's not always the case that a method must end in a return statement. The compiler is smart enough to realize when all branches return.
// Compiles
String foo(boolean a) {
if (a) {
return "foo";
} else {
return "bar";
}
}
This will compile even though there is no return statement after the else because it figures out that each branch of the if/else ends in a return.
Let's move over to the switch statement.
// Won't compile
String foo(char c) {
switch (c) {
case 'a':
return "foo";
}
}
The above code will not compile, because for all inputs where c != 'a' there is no return statement. But we can fix that by adding a default.
// Compiles
String foo(char c) {
switch (c) {
case 'a':
return "foo";
default:
return "bar";
}
}
Here for all values of c, there is a return, so the compiler doesn't complain.
Let's look at some edges cases where the compiler isn't smart enough to do branch prediction.
// Won't compile
String foo(char c) {
if (c != 'a') {
return "bar";
}
switch (c) {
case 'a':
return "foo";
}
}
Compiler doesn't understand that going into the switch, 'c' must equal 'a' so even thought it might seem like this should compile it won't.
Here's a confusing case where all branches are covered, but the java compiler has still chosen to fail compilation.
// Won't compile
enum B { T, F }
String foo(B a) {
switch (a) {
case T:
return "foo";
case F:
return "bar";
}
}
It looks like the switch statement has all branch coverage. There are no other instances of B besides T and F. This can be solved by creating a default branch that handles new potential enum values.
I have a number of Java classes I need to convert to Swift code.
One of the classes has an advanced enum:
public enum Student {
STUDENT_ONE("Steve", "Jobs")
STUDENT_TWO("Tim", "Cook")
private String _firstName;
private String _lastName;
}
How can I replicate the same behavior in Swift?
After some thought, I agree with godmoney that aksh1t's solution is better that my solution using Strings.
Anyway, here is a more concise variant of aksh1t's solution, using only one computed property returning a tuple: (tested in Swift 2.0)
enum Student {
case STUDENT_ONE, STUDENT_TWO
typealias Details = (firstName: String, lastName: String)
var details : Details {
switch(self) {
case STUDENT_ONE : return ("Steve", "Jobs")
case STUDENT_TWO : return ("Tim", "Cook")
}
}
}
// Usage:
func test(sd: Student.Details) {
print(sd.firstName)
print(sd.lastName)
}
test(Student.STUDENT_ONE.details)
I was trying to do the same thing with converting Java code to Swift, and ended up doing something like this :
public enum Student {
case STUDENT_ONE
case STUDENT_TWO
var firstName: String {
get {
switch self {
case .STUDENT_ONE:
return "Steve"
case .STUDENT_TWO:
return "Tim"
}
}
}
var lastName: String {
get {
switch self {
case .STUDENT_ONE:
return "Jobs"
case .STUDENT_TWO:
return "Cook"
}
}
}
}
Now, this is really long and messy and I'm not really sure whether this is the right way to do it, but I couldn't find anything else that worked. I would love to know if there is some other better way to do it.
This is what I ended up doing - not sure about this at all:
struct Students {
enum Students {
case STUDENT_ONE(String, String)
case STUDENT_TWO(String, String)
}
let STUDENT_ONE = Students.STUDENT_ONE("Steve", "Jobs")
let STUDENT_TWO = Students.STUDENT_TWO("Steve", "Two")
}
Enums are not necessarily the best choice to represent this type of data. I choose structs and this works well, using the correct accessors:
public struct Student {
public let firstName : String
public let lastName : String
public static let STUDENT_ONE = Student(firstName: "Steve", lastName: "Jobs")
public static let STUDENT_TWO = Student(firstName: "Tim", lastName: "Cook")
}
Moved here from another question marked as a duplicate so the variable names don't match up exactly, however, the concepts all do.
The most obvious way would be:
public enum EnumWeapon {
case WOODEN_SWORD
case STONE_SWORD
case STEEL_SWORD
func getName() -> String {
switch self {
case WOODEN_SWORD: return "Wooden Sword"
case STONE_SWORD: return "Stone Sword"
case STEEL_SWORD: return "Steel Sword"
}
}
func getDamage() -> Int {
switch self {
case WOODEN_SWORD: return 4
case STONE_SWORD: return 6
case STEEL_SWORD: return 8
}
}
}
If you have a single value to associate with each enum case, you can use the raw value syntax, or just use it to simplify the enum case above:
public enum Weapon : Int {
case WOODEN_SWORD = 4
case STONE_SWORD = 6
case STEEL_SWORD = 8
func getDamage() -> Int {
return rawValue
}
func getName() -> String {
switch self {
case .WOODEN_SWORD: return "Wooden Sword"
case .STONE_SWORD: return "Stone Sword"
case .STEEL_SWORD: return "Steel Sword"
}
}
}
Obviously, if you don't need the name, you can omit the getName function. Likewise you can omit the getDamage function and just use weapon.rawValue
An even simpler way, and yet more analogous to the actual Java implementation, would be to use a struct instead of an enum, as:
public struct Weapon {
public let name : String
public let damage : Int
private init(name:String, damage:Int) {
self.name = name
self.damage = damage
}
public static let WOODEN_SWORD = Weapon(name: "Wooden Sword", damage: 4)
public static let STONE_SWORD = Weapon(name: "Stone Sword", damage: 6)
public static let STEEL_SWORD = Weapon(name: "Steel Sword", damage: 8)
}
and, be redefining operator ==, you can get equality comparisons:
func == (lhs:Weapon, rhs:Weapon) -> Bool {
return lhs.name == rhs.name && lhs.damage == rhs.damage
}
and, by redefining operator ~= you can get switch to work as expected:
func ~= (lhs:Weapon, rhs:Weapon) -> Bool {
return lhs == rhs
}
func test(sword:Weapon) {
switch sword {
case Weapon.STONE_SWORD: print("stone")
default: print("something else")
}
}
test(Weapon.STONE_SWORD)
A whole lot of options, mostly it just depends on what you're really trying to do and how much data you need to wrap in the enum.
Am getting error - case expressions must be constant expressions , when am trying to use enum class in switch case statements :
My enum class is,
public enum TestEnumClass {
TEST1("TEST1"),
TEST2("TEST2"),
TEST3("TEST3");
private String enumConstant;
private TestEnumClass(String algoConstant) {
this.enumConstant = algoConstant;
}
public String getEnumConstant() {
return enumConstant;
}
}
And am trying to use enum TestEnumClass as below in another class file,
public class TestIndexOf {
public static void main(String[] args) {
String str = args[0];
switch(str){
case TestEnumClass.Test1.getEnumConstant() : System.out.println("test1"); break;
case TestEnumClass.Test2.getEnumConstant() : System.out.println("test2"); break;
}
}
}
Its giving me compile time error :
case expressions must be constant expressions
Please suggest me, where am I going wrong.
You can't use the result of methods as cases in a switch statement. Switches are optimised for constant cases. Enums are very suitable for this, but you would have to have:
TestEnumClass value = TestEnumClass.valueOf(str);
switch (value) {
case TEST1: ...
case TEST2: ...
}
your switch expression is on a String, you need to change it to a variable of type TestEnumClass
You are doing switch over String but the case TestEnumClass.TEST1.getEnumConstant() is not compile time constant according to JLS. A case statement requires compile time constant value. In order to correct the error you can do like this
String str = args[0];
TestEnumClass e = TestEnumClass.valueOf(str);
switch(e){
case TEST1: System.out.println("test1"); break;
case TEST2 : System.out.println("test2"); break;
}
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;
}
}