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
Related
I have a code snippet similar to the one below,
public ArrayList getReport(reportJDOList,accountType)
{
String abc = "";
for(ReportJDO reportJDO : reportJDOList)
{
if(accountType.equals("something")
abc = reportJDO.getThis();
else
abc = reportJDO.getThat();
//somecode goes here
}
returning List;
}
As I know the value of accountType before the iteration, I dont want this check to happen, for every entry in a list as it would cause numerous number of checks if the size of reportJDOList is 10000 for an instance. How we remove this thing from happening? Thanks in Advance :)
You can indeed peform check once and implement 2 loops:
if(accountType.equals("something") {
for(ReportJDO reportJDO : reportJDOList) {
abc = reportJDO.getThis();
}
} else {
for(ReportJDO reportJDO : reportJDOList) {
abc = reportJDO.getThat();
}
}
Obviously you can improve your design by either
separating you loops into 2 different methods
Using command pattern, i.e. implementing loop body in different command and executing it to loop.
Using Guava's Function (it is just improvement of #2)
Using java 8 streams.
IF you want to save the String comparison, make it once before the loop and store the result in a boolean variable :
String abc = "";
boolean isThis = accountType.equals("something");
for(ReportJDO reportJDO : reportJDOList) {
abc = isThis ? reportJDO.getThis() : reportJDO.getThat();
//somecode goes here
}
I'd vote for clean coding this - perform the check once and delegate the logic into private methods, each performing the loop individually. This duplicates code for the loop but gives greatest flexibility if at some point you need to do something more in SomethingReport that's not duplicated in OtherReport.
public ArrayList getReport(reportJDOList,accountType) {
if("soemthing".equals(accountType)) {
return getSomethingReport(reportJDOList);
} else {
return getOtherReport(reportJDOList);
}
}
private ArrayList getSomethingReport(reportJDOList) {
[...]
}
interface AccountHandler {
String get(Report r);
}
AccountHandler thisHandler= new AccountHandler() {
#Override
public String get(Report r) {
return r.getThis();
}
};
AccountHandler thatHandler= new AccountHandler() {
#Override
public String get(Report r) {
return r.getThat();
}
};
//...............
AccountHandler ah;
ah = (what.equalsIgnoreCase("this")) ? thisHandler : thatHandler;
Report r=new Report();
// loop
ah.get(r);
//Using reflection:
Report r = new Report();
Method thisMethod = r.getClass().getDeclaredMethod("getThis");
Method thatMethod = r.getClass().getDeclaredMethod("getThat");
Method m = (what.equalsIgnoreCase("this")) ? thisMethod : thatMethod;
m.invoke(r);
I am a newbie in Java. I am trying to create a Class named Database that will read a text file to create an array. There is no main method in this code since I have another java file that acts as a main application, and it has the main method.
Here is my code:
public class Database {
public static String[][] items = new String[20][3];
public static String[][] fillArray(String myFile)
{
TextFileInput in = new TextFileInput(myFile);
for(int i=0; i<20; i++)
{
String line =in.readLine();
StringTokenizer token = new StringTokenizer(line, ",");
for(int j=0; j<3; j++)
{
items[i][j] = token.nextToken();
}
}
in.close();
return items;
}
public static String getName(String code)
{
for(int i=0; i<20; i++)
{
if (code.equals(items[i][0]))
return items[i][1];
}
}
public static String getPrice(String code)
{
for(int i=0; i<20; i++)
{
if(code.equals(items[i][0]))
return items[i][2];
}
}
}
Question 1: Eclipse shows errors by indicating on both methods (getName and getPrice). It says: " This method must return a result of type String". Can anyone please explain and fix this?
Question 2: This Database class includes methods and an array created by reading in the text files. And I have another java file which is the main application file that includes the main method. The main application file is the file where I would like to create object and call the methods in. I understand the concept, but I keep getting errors when I try to create a database object and call the methods on this object. Can anyone please show me an example by using this class?
Answer 1: Your return statement in getName & getPrice method is inside if block which might be executed or not based upon the condition satisfied in if hence compiler will give error.
You need to have return statement before the method returns.
Answer 2: Since all the methods in your database class are static you don't need to create object, you can invoke it directly using classname e.g.Database.getName("code")
Eclipse shows errors by indicating on both methods (getName and
getPrice). It says: " This method must return a result of type
String". Can anyone please explain and fix this?
The method signature states that the return type is String:
public static String getName(String code)
So you must return it. For example:
public static String getName(String code) {
String result = null;
// Perform work and update value in result.
return result;
}
Can anyone please show me an example by using this class?
You need to instantiate the class before invoking any instance method but not for static methods. For example:
String result = Database.getName("code"); //pass some string as input argument and get result.
On a side note why have you declared all methods static? You need to understand why you really need static methods.
Java and Eclipse cannot know if code will ever be equal to items[i][0]. That's why, there might not be a return value for getName.
public static String getName(String code)
{
for(int i=0; i<20; i++)
{
if (code.equals(items[i][0]))
return items[i][1];
}
return "";// or null
}
With This method must return a result of type String the eclipse is saying your method return type is String so you must return a String in any case but your return statement is inside if() what if the condition inside if is never true then there is no return statement so add a default return statement to your method where you are return type String.
public static String getPrice(String code) {
for (int i = 0; i < 20; i++) {
if (code.equals(items[i][0])) return items[i][2];
}
return null;
}
In your method getName and getPrice you have put the if condition, and method only return when your condition in true that is why you have the compilation issue.
To fix that add the else condition in which you should return or add return after completion of if block.
Your method declarations are
public static String getName(){...}
public static String getPrice(){...}
let's analyse this, static keyword means it's a static method.
String means this method returns a object type of String.
However you return a String array object, not a String object.
Also return is inside a if statement and it the if condition not met, it won't return anything, but you must always return a object type of String.
therefore add a return after the if statement, incase if the code never enters your if block
if(YOUR CONDITION) {
//do stuff
//return stuff
}
//if never enters if block returns null
return null;
Your deletions must be
public static String[][] getName(){...}
public static String[][] getPrice(){...}
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
I'm trying to create a simple method which I have below:
public void analyzeWithAnalytics(String data) {
for (int i = 0; i < VALUE; i++) {
if (data.equals("action1")) {
// call a method on a value
}
if (data.equals("action2")) {
// call a different method on a value
}
}
This is only a small snippet (I took a lot out of my code), but essentially I want to be able to call a specific method without testing multiple lines in my for loop for which method to call.
Is there a way for me to decide what value to call by declaring a variable at the very beginning, instead of doing so many 'if statement' tests?
OK, I have an ArrayList inside my class:
private List<Value> values;
The value object has 2 fields time and speed.
Depending on the string I pass (time or speed), I want to be able to call the specific method for that field without doing multiple string comparisons on what method I passed.
For example, I want to be able to call getSpeed() or getTime() without doing a string comparison each time I want to call it.
I just want to test it once.
Another one:
enum Action {
SPEED {
public void doSomething() {
// code
}
},
TIME {
public void doSomething() {
// code
}
};
public abstract void doSomething();
}
public void analyzeWithAnalytics(Action data) {
for (int i = 0; i < VALUE; i++) {
data.doSomething();
}
}
You can have a Map which maps the names (action1, action2, ...) to classes which common parent and one method. And make call as following:
map.getClass("action1").executeMethod();
Map<String, MethodClass> theMap = new Map<>();
interface MethodClass {
executeMethod();
}
and children:
class MethodClass1 implements MethodClass{...}
class MethodClass2 implements MethodClass{...}
Your goal is not really clear from your question. Do you want to:
avoid typing the many cases?
gain code readability?
improve performance?
In case you're after performance, don't optimize prematurely! Meaning, don't assume that this will be important for performance without checking that out first (preferably by profiling). Instead focus on readability and perhaps laziness. ;)
Anyway, you can avoid the many tests inside by simply checking data outside of the loop. But than you'd have to copy/paste the loop code several times. Doesn't make the method more beautiful...
I would also recommend using case instead of if. It improves readability a lot and also gives you a little performance. Especially since your original code didn't use if - elseif - ... which means all conditions are checked even after the first was true.
Do I get this right? data will not be changed in the loop? Then do this:
public void analyzeWithAnalytics(String data) {
if (data.equals("action1")) {
for (int i = 0; i < VALUE; i++) {
// call a method on a value
}
} else if (data.equals("action2")) {
for (int i = 0; i < VALUE; i++) {
// call a different method on a value
}
}
}
You can also switch on strings (Java 7) if you don't like ìf...
You could try something like this, it would reduce the amount of typing for sure:
public void analyzeWithAnalytics(String data) {
for (int i = 0; i < VALUE; i++) {
switch(data) {
case "action1": doSomething(); break;
case "action2": doSomething(); break;
}
}
}
I am taking in an array of methods and I want to chain them together to modify an object that I am working in.
For example I start with
"getStuff().get(1).get(3).setMoreStuff().put(stuff,6)"
I split it into an array called methods, and clean up the parameters inside each method and I try to modify this.
Object res = this;
String[] methods = targetString.split("\\.(?=\\D)");
for (String m : methods){
List<Object> params = new ArrayList<Object>();
List<Object> params = new ArrayList<Object>();
for (String p : m.split("\\(|,|\\)")) {
try {
if (p.indexOf(".") != -1){
double tempD = Double.parseDouble(p);
params.add(tempD);
} else {
int tempP = Integer.parseInt(p);
params.add(tempP);
}
} catch (Exception ex) { //not a number
params.add(p);
}
}
switch (params.size()) {
case 1:
res = res.getClass().getMethod(
params.get(0)
).invoke(res);
break;
case 2:
res = res.getClass().getMethod(
params.get(0),
params.get(1).getClass()
).invoke(res, params.get(1));
break;
case 3:
res = res.getClass().getMethod(
params.get(0),
params.get(1).getClass(),
params.get(2).getClass()
).invoke(res, params.get(1), params.get(2));
break;
}
in the end I notice that res has been modified the way that I expect. All the getters and setters are called correctly. But of course the underlying object "this" refers to has not been changed!
I guess I'm just calling the getters and setters of the copy I made in the first line!
now I can't just use
this.getClass().getMethod(...).invoke(...)
because I need to call the same getMethod on the object returned by this call.
To clarify:
Object res = this;
creates a "pointer" to this. So that when I call
res.getStuff().setStuff(foo)
this will also be modified.
but it seem that when I call
res = res.getStuff();
res = res.setStuff();
like I do in my loop,
this does not modify the underlying object this refers to?
Edit: Included more code as per request.
Edit2: added anther example, to clarify my problem.
Edit3: tried to add more code, its a bit hard to add a working program without including every class
Your general approach should be fine (although your approach to parameter conversion is somewhat ugly) - it's the specifics that are presumably causing you problems. Here's a short but complete program demonstrating calling methods and then seeing the difference afterwards:
import java.lang.reflect.*;
class Person {
private String name = "default";
public String getName() {
return name;
}
// Obviously this would normally take a parameter
public void setName() {
name = "name has been set";
}
}
class Test {
private Person person = new Person();
public Person getPerson() {
return person;
}
// Note that we're only declaring throws Exception for convenience
// here - diagnostic code only, *not* production code!
public void callMethods(String... methodNames) throws Exception {
Object res = this;
for (String methodName : methodNames) {
Method method = res.getClass().getMethod(methodName);
res = method.invoke(res);
}
}
public static void main(String[] args) throws Exception {
Test test = new Test();
test.callMethods("getPerson", "setName");
System.out.println(test.getPerson().getName());
}
}
The output is "name has been set" just as I'd expect. So see if you can simplify your code bit by bit, removing extra dependencies etc until you've got something similarly short but complete, but which doesn't work. I suspect you'll actually find the problem as you go.
Object does not change reference, its VALUE changes. So if you will call this.get("some key"), you will get value that the same value that you put using reflection.
Right?