Reflection vs Switch and case in getting fields - java

So is this faster:
for (int i = 0; i < example.length; i++) {
switch (i) {
case 0: return example.field0;
case 1: return example.field1;
case 2: return example.field2;
case 3: return example.field3;
case 4: return example.field4;
case 5: return example.field5;
case 6: return example.field6;
case 7: return example.field7;
case 8: return example.field8;
case 9: return example.field9;
case 10: return example.field10;
}
}
Or this:
for (int i = 0; i < example.length; i++) {
return example.class.getField("field" + i);
}
I just want to know because it seems a bit tedious doing the first one and I do not want to repeat lots of lines of code that are basically doing the exact same thing.

What exactly is field0...field10? Depending on the relation between these fields, you might want to organize them in an appropriate data structure.
Do you have 11 fields of the same type and (besides their index) the same meaning, like the x-coordinates of the points of a line. Then an Array or a List might be the correct data structure.
Do these 11 fields cover the same aspect of the object and could be considered to belong together but can be named individually, like e.g. metadata of a document. The you might use a map (as "Hovercraft Full Of Eels" suggests) or put them into their own object. If you put the fields into a map, you might want to use an enumeration as key.
Are these 11 fields basically independent of each other? Then please don't try to access them together but write a getter and setter per field.
"Tedious" and "many lines of code" is not a good guide. It may be a sign of a bad design that should be corrected (see above). Otherwise there's usually a workaround in your favorite IDE. Creating setters and getters should only be a click away!
Please use reflection only if there's no other way. For examples see How could Reflection not lead to code smells?. Reflection in Java has quite a few drawbacks: bad performance, complex and difficult to get right. The main argument against reflection is IMHO that the compiler and IDEs are not made for reflection. You rename field<x> to metadata<x>? The refactoring will not change [...] getField("field" + i); and the compiler will not complain!
But to answer the actual question: Reflection is most likely a lot slower than direct Java code.

Related

Clean code -- Java static functions and variable reuse

I am trying to clean up a static function. Let me provide a template of this function here. It is a static function and is used only in two places in the code base one where the isClient is true and another where isClient is false.
public static void validate(BLangFunction resource, DiagnosticLog dlog, boolean resourceReturnsErrorOrNil,
boolean isClient) {
if (!resourceReturnsErrorOrNil) {
dlog.logDiagnostic(Diagnostic.Kind.ERROR, resource.pos, "Invalid return type: expected error?");
}
switch (resource.getName().getValue()) {
case WebSocketConstants.RESOURCE_NAME_ON_OPEN:
case WebSocketConstants.RESOURCE_NAME_ON_IDLE_TIMEOUT:
validateOnOpenResource(resource, dlog, isClient);
break;
case WebSocketConstants.RESOURCE_NAME_ON_TEXT:
validateOnTextResource(resource, dlog, isClient);
break;
case WebSocketConstants.RESOURCE_NAME_ON_BINARY:
validateOnBinaryResource(resource, dlog, isClient);
break;
case WebSocketConstants.RESOURCE_NAME_ON_PING:
case WebSocketConstants.RESOURCE_NAME_ON_PONG:
validateOnPingPongResource(resource, dlog, isClient);
break;
case WebSocketConstants.RESOURCE_NAME_ON_CLOSE:
validateOnCloseResource(resource, dlog, isClient);
break;
case WebSocketConstants.RESOURCE_NAME_ON_ERROR:
validateOnErrorResource(resource, dlog, isClient);
break;
default:
dlog.logDiagnostic(Diagnostic.Kind.ERROR, resource.pos,
"Invalid resource name " + resource.getName().getValue() + " in service ");
}
}
The problem with this code is that the dlog variable is passed to all the other called functions as well as the isClient variable. And the resourceReturnsErrorOrNil is used in only one place.
I thought of refactoring the code to have non-static functions so that dlog can be a class variable and there could be two classes one for client and other for service with all the common code in a super class. Then I thought that this function is used only in two places and should we have instance classes for these?
The source code of this function can be found here.
What would be the best way to refactor based on the clean code principles?
Then I thought that this function is used only in two places and should we have instance classes for these?
That really depends on your goal. I agree, the current code is far from ideal. And the things you outlined all make sense. So, to answer your question: yes, if you think it will be helpful to the quality of your code base, having an "instance" class that only gets used in two places is perfectly fine.
The other thing to carefully look at: maybe there is a way to get rid of that switch. You could for example use a map (key: your constants, value: some Functional interface ... that makes the corresponding validation).
The method should be made non static. This way, you can utilize dependency injection for the logging feature.

Philosophy of variable's scope in a switch statement

As answered in this question here, the scope of a variable inside of a case belongs to the entire switch statement itself, not just the case. Therefore, this does not compile (duplicate local variable):
int key = 2;
switch (key) {
case 1:
String str = "1";
return str;
case 2:
String str = "2";
return str;
}
I'm interested in mainly two things...
What's the philosophy, or design principle, behind this behavior? (Maybe I'm even asking for the motivation for the switch statement as a whole?)
How does this happen? How does this code look at the bytecode, or even assembly, level?
For better or worse, the semantics of switch in Java were heavily influenced by the semantics of switch in C. And, while we as programmers tend to think of a case label followed by some statements and a break/continue/return as a logical unit, that's not actually how it works, and no such construct exists at the language level. In a switch, break and continue are just statements, and when you execute a switch, you start at the matching case label and execute the remainder of the block. It just so happens that most of the time, you'll hit a break or continue or return before that happens. (See JLS 14.11.) The key sentence is:
All statements after the matching case label in the switch block, if any, are executed in sequence.
Many people believe (IMO, reasonably so) that the switch statement in Java has its priorities backwards; the language treats fallthrough and other control flow oddities as if they were normal case, and break as the exceptional case. But of course, in real code, it's the other way around. (How did Java acquire these backward priorities? By copying from C.)
The scoping rule for switch statements flows pretty directly from this view of the world; if the body of a switch is an undifferentiated block that happens to be peppered with case labels, of course its one big scope. Never mind that this is not actually what almost all developers want almost all the time.
In addition to confusing scoping and fallthrough-by-default, Among the other things people regret about switch in Java is that it is only a statement, not an expression. See JEP 325, which addresses all of these problems (in a backward-compatible way), which will likely be a preview features in Java 12.
Just put a pair of braces around each case clause:
int key = 2;
switch (key) {
case 1: {
String str = "1";
return str;
} case 2: {
String str = "2";
return str;
}
}
This will compile.

How to achieve a switch case block which is scalable?

While starting to build an application, I stared using a switch case block with only five cases to be considered. Later when the build progressed, more cases came into picture and that started creating problems. I know I might have designed it wrongly at the first place, but if such things come as a change how do I effectively approach this? An example is given below
Starting with this
switch case 1: /*do function1()*/ break;
case 2: /*do function2()*/ break;
Later, a 100 cases come in
switch case 1: /*do function1()*/ break;
case 2: /*do function2()*/ break;
....
case 100: /*do function100()*/ break;
I am sure that converting these cases into 100 if conditions is not going to be a very good approach, so is there a way this can be done?
Please consider that the functions given in the code above are simple mathematical functions for now.
Consider an interface like this:
public interface MyFunction {
public void compute();
}
and a Map with the previous interface as values:
Map<Integer,MyFunction> myFunctionsMap = new HashMap<>();
You need to initialize the map with all of you functions:
myFunctionsMap.put(1,new MyFuntion() {
#Override
public void compute() {
/*do function1()*/
}
});
for each of your functions, the syntax might be a bit heavy with anonymous classes, you can implement you functions in separate classes and use them as well.
Now instead of the switch, you simply use the map:
myFunctionsMap.get(theValueSwitched).execute();
Depending of how you initialize the map, the values of the keys and how you use it, you might want to check myFunctionsMap.contains(theValueSwitched) (this would be your default case if you have one).
Edit: Java 8 shorter syntax would be myFunctionsMap.put(1,() -> {/*do function1()*/});
You could name your methods something like method1, method2, method3 , etc .. and use reflexion to call them, using you variable. You wouldn't have a lengthy switch, that way.
I have no ideas if that is efficient or not, though.
Here's a neat exemple, from wikipedia's reflection page.
Object foo = Class.forName("complete.classpath.and.Foo").newInstance();
// Alternatively: Object foo = Foo.class.newInstance();
Method m = foo.getClass().getDeclaredMethod("hello", new Class<?>[0]);
m.invoke(foo);
hope that helps

Is it possible to use an Integer to call methods and arrays dynamically?

For example:
3 methods exist
"map1method,
map2method,
map3mehtod"
and I want to call the right one depending on what the integer 'activemap' has currently stored in it.
I could do an If statement
"If (activemap == 1)
map1method;
elseif (activemap ==2)
..."
But is there a possible way of using the integer more efficiently?
Like a "map(activemap)method"
Also could I also call a specific array in a batch of them in the same fashion.
This is all in java by the way.
It is possible via reflection but I would urge you to stay away from that approach. Why not have all three methods built into one? One option would be to use a switch statement to handle the various cases:
void mapMethod(int activemap) {
switch (activemap) {
case 1:
// map1method
break;
case 2:
// map2method
break;
case 3:
// map3method
break;
default:
break;
}
}
Now, you can call
mapMethod(activemap)
If you want to take the reflection approach instead (which as I said I don't think you should), you can do something along the lines of
String methodName = "map" + activemap + "method";
MyClass.class.getDeclaredMethod(methodName).invoke(null);
A switch statement would be slightly easier to read:
switch(activemap) {
case 1: map1method(); break;
case 2: map2method(); break;
}
You could use reflection to build the method name up at runtime, but that wouldn't be simpler. Reflection is a lot of code.
The most effective way to do this is to either create an enum to represent the different calls and use the int as a lookup for the enum value, or if that's not possible, to use a switch statement. You can use reflection to accomplish what you're talking about (look up a method at runtime based on its name), but it's less efficient and more cumbersome than either of those options.
You can do it using Reflection, It will be something like this:
java.lang.reflect.Method method;
method = myObject.getClass().getMethod("map+"activemap"+method", param1.class, param2.class, ..);
method.invoke(object, arg1, arg2,...);

Java switch statement efficiency of default placement

Does the placing of default statement affect efficiency in Java? Is there difference between:
switch (a) {
case 0: return 0;
case 1: default: return -1;
case 2: return 2
...
case 99: return 99;
}
vs
switch (a) {
case 0: return 0;
case 1: return -1;
case 2: return 2;
...
case 99: return 99;
default: return -1;
}
Even in the most naive implementation this cannot produce a difference in performance, but with Java you are so far removed from the actual machine code this will turn into that you should definitely never even attempt to optimize this or any other similar piece of code. In fact, even if you wrote the dumbest cascade of else-ifs, you'd still stand a solid chance of JIT turning that into a superfast hash-lookup-based machine code.
No, it won't make a difference. Why? Because of this: When does the JVM know that it has to use the default body? After it checked all the other cases. So placing default: at a specific location in the which won't change performance.
I don't believe you'd see any significant performance improvements if you wrote a quick test program. At least none that would justify obscuring your code. I'd just leave the default case neatly last in the list to keep the code more readable. It's probably more important than a micro improvement in performance (if any at all)
No. The location of the switch statement makes no difference to the generated byte code other than the debugging annotations.

Categories

Resources