Advanced Java enums in Swift - java

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.

Related

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.

Reducing if-else statements in Java

I have the following code:
void f(String t)
{
if(t.equals("a"))
{
someObject.setType(ObjectType.TYPE_A);
}
else if(t.equals("b"))
{
someObject.setType(ObjectType.TYPE_B);
}
// 50 more similar code
}
Is there any simple way to rewrite the if-else condition so as not to have that much code?
You should use something to eliminate the repetition of someObject.setType(ObjectType....)) If ObjectType is an enum, then write a method there similar to valueOf that will achieve that. See if you like this kind of solution:
void f(String t) { someObject.setType(ObjectType.byName(t)); }
enum ObjectType {
TYPE_A, TYPE_B;
public static ObjectType byName(String name) {
return valueOf("TYPE_" + name.toUpperCase());
}
}
Use a Map (which you'll have to populate) that maps from String to whatever type your ObjectType.TYPE_x values are.
I would add this as a functionality of the enum:
public enum ObjectType {
TYPE_A("a"),
TYPE_B("b");
private String stringType;
private ObjectType(String stringType) {
this.stringType = stringType;
}
public String getStringType() {
return this.stringType;
}
public static ObjectType fromStringType(String s) {
for (ObjectType type : ObjectType.values()) {
if (type.stringType.equals(s)) {
return type;
}
}
throw new IllegalArgumentException("No ObjectType with stringType " + s);
}
}
...
void f(String t) {
someObject.setType(ObjectType.fromStringType(t));
}
If you can refactor t into a char, you could use switch instead (Java 6):
void f(char t) {
switch(t) {
case 'a`:
someObject.setType(ObjectType.TYPE_A);
break;
case 'b':
someObject.setType(ObjectType.TYPE_B);
break;
// ...
}
}
As Marko pointed out, you could go with String too in Java 7.
It isn't that much shorter, but more elegant. Moreover, I think it might be faster too, as switch works close to O(1) with jump tables (Can somebody confirm whether this is true?), whether a number of if statements is O(n).
Fore more complex implementations than just a single setType you might think of a State Pattern implementation too.
1.You can go for Switch statement if you have number of if conditions more than 3.
2.you can convert your if else statements to ternary operations
The other suggestions are great - particularly smarter enums and maps. But the first most basic refactoring I would tackle here is to extract a method to return the enum directly and have the caller perform nothing more than the setType to that method's return value.
void f(String t) {
final ObjectType type = findType(t);
if (type != null)
someObject.setType(type);
}
ObjectType findType(String t) {
if (t.equals("a")) return ObjectType.TYPE_A;
if (t.equals("b")) return ObjectType.TYPE_B;
// 50 more similar code
}
In some cases this will be sufficient in and of itself; in others the findType() method may lead you to a simple map- or enum-based solution.

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;
}
}

Java Enum on a switch statement

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.

Categories

Resources