I got a problem where I am not allowed to use switch/case or if/else queries.
I got a config file I read which is this:
650;0;1.5;month
614;0;2.88;year
466;0;2.48;week
716;0;4.6;half-year
718;0;2.6;quarter
I am splitting those Strings at the ";", so it is saved in an array. The problem I have, that I need to do other things in the code for each time given in that array ar[3], so if it is a month I need other calculations then when it is a full year.
But I am not allowed to do this with Switch/case or If/Else, now I am getting confused.
If (ar[3] = month){
do this;
else if (ar[3] = year) {
do this;
}
How am I doing this object oriented? Thanks for every help :)
Polymorphism by Inheritance is your friend
It seems like you need some sort of inheritance structure based on the time period in ar[3]. The special do this method could be coded for each case. That way you get the ability to do something different for each case. You just need a way to instantiate the correct subtype in the first place. There are a number of ways you could approach this.
The Conditional Operator
The most direct approach IMHO is the conditional operator, ?:.
So the code would look something like this:
MyClass x = ar[3].equals("month") ? new MyClassMonth() :
(ar[3].equals("year") ? new MyClassYear() :
(ar[3].equals("week") ? new MyClassWeek() :
(ar[3].equals("half-year") ? new MyClassHalfyear() :
new MyClassQuarter())));
x.doSomething();
The nested conditional expressions give you the ability to select the right class, and the inheritance gives you the polymorphic behavior you want.
But you mentioned in comment that you also can't use ?:. What next?
A Map of Stateless Objects
Suppose you wrote MyClassMonth in a way that nothing in it depended on any remembered state, i.e. the doSomething() method has no side effects. Then you could create a Map<String, MyClass> to store one instance of each subclass, then pull the relevant one out of the map when you needed to invoke.
You'd initialize the map like this:
final Map<String, MyClass> themap = new HashMap<>();
{
themap.add("month", new MyClassMonth());
themap.add("year", new MyClassYear());
themap.add("week", new MyClassWeek());
themap.add("half-year", new MyClassHalfyear());
themap.add("quarter", new MyClassQuarter());
}
And invoke doSomething() with ar as argument:
MyClass x = themap.get(ar[3]);
if (x != null)
x.doSomething(ar);
Other Options
There are other ways to do this. Sticking with the Map concept, you could store class literals in the Map instead of instances, then instantiate them reflectively. You could also keep a lambda in the Map and invoke it.
Enums
#OldCurmudgeon suggested using enums. If you put those enums into the Map and add a lambda to the enum, you can grab the enum and invoke the lambda. That would work and has a certain appeal, but it seems unnecessary. You'd be better off just invoking the lambda directly.
You could use an enum as a command factory pattern and implement the choice with a Map lookup.
// Lookups for teh period.
static final Map<String, Period> lookup = new HashMap<>();
enum Period {
Month("month") {
#Override
void process(int x, int y, double v) {
// Processing for "month" records here.
System.out.println(this + "-process(" + x + "," + y + "," + v + ")");
}
},
Year("year") {
#Override
void process(int x, int y, double v) {
// Processing for "year" records here.
System.out.println(this + "-process(" + x + "," + y + "," + v + ")");
}
},
Quarter("quarter") {
#Override
void process(int x, int y, double v) {
// Processing for "quarter" records here.
System.out.println(this + "-process(" + x + "," + y + "," + v + ")");
}
},
HalfYear("half-year") {
#Override
void process(int x, int y, double v) {
// Processing for "half-year" records here.
System.out.println(this + "-process(" + x + "," + y + "," + v + ")");
}
};
Period(String inData) {
// Record me in the map.
lookup.put(inData, this);
}
abstract void process(int x, int y, double v);
static void process(String data) {
String[] parts = data.split(";");
Period p = lookup.get(parts[3]);
if (p != null) {
p.process(Integer.parseInt(parts[0]), Integer.parseInt(parts[1]), Double.parseDouble(parts[2]));
}
}
}
public void test() {
String[] test = {"650;0;1.5;month",
"614;0;2.88;year",
"466;0;2.48;week",
"716;0;4.6;half-year",
"718;0;2.6;quarter",};
for (String s : test) {
Period.process(s);
}
}
correctly prints:
Month-process(650,0,1.5)
Year-process(614,0,2.88)
HalfYear-process(716,0,4.6)
Quarter-process(718,0,2.6)
Note that there is one if in there but that is only defensive to avoid bad data - it is not part of the lookup mechanism.
Something like this:
public interface Calculator {
double calculate(int p1, int p2, double p3);
}
public class YearCalculator implements Calculator {
public double calculate(int p1, int p2, double p3) {
double value = 0.0;
// do year calculations
return value;
}
}
public class CalculatorFactory {
public Calculator getInstance(String type) {
Calculator calculator = null;
if (type != null) {
} else {
throw new IllegalArgumentException("calculator type cannot be null");
if ("year".equalsIgnoreCase(type)) {
} else {
System.out.println(String.format("No such type: %s", type));
}
}
return calculator;
}
}
You have to have if/else logic in the factory, but not when you're parsing the text.
Your processing code:
CalculatorFactory factory = new CalculatorFactory();
// contents is a List of Strings from your input file.
for (String line : contents) {
String [] tokens = line.split(";");
Calculator calculator = factory.getInstance(tokens[3]);
double value = calculator.calculate(Integer.parseInt(tokens[0]), Integer.parseInt(tokens[1]), Double.parseDouble(tokens[2]));
}
Building upon the suggestion given by Codebender as an alternative solution:
You need 5 classes, one for each case, with a common interface but different implementations.
Your interface may look something like this:
public interface MyCalculator {
public double calculate(double a, double b, double c);
}
Then you will need to implement your 5 classes similar to this. You will need a different class with a different implementation for calculate for month, year, week, half-year and quarter:
public class MyMonthCalculator implements MyCalculator {
#Override
public double calculate(double a, double b, double c) {
// Do your calculations here then return
}
}
Then, before your parsing logic, you can add the five classes to a Map.
map.put("month", new MyMonthCalculator());
// Repeat for year, week, half-year and quarter
To actually perform a calculation:
double result = map.get(ar[3]).calculate(Double.parseDouble(ar[0]), Double.parseDouble(ar[1]), Double.parseDouble(ar[2]));
You can simulate if or case with arrays of options. Only problem here would be finding index of our element in such array. We can't use if and case but I assume that while is an option.
So your code can be similar to something like:
String[] options = { "foo", "bar", "baz" };
Runnable[] action = { new Runnable() {
#Override
public void run() {
System.out.println("handling foo");
}
}, new Runnable() {
#Override
public void run() {
System.out.println("handling bar");
}
}, new Runnable() {
#Override
public void run() {
System.out.println("handling baz");
}
} };
String choice = "bar";
int matched = 0;
int i = -1;
while (matched != 1) {
i++;
matched = boolToInt(options[i].equals(choice));
}
action[i].run();
I used method like this to convert boolean to integer where 1=true, 0=false
public static int boolToInt(Boolean b) {
return 5 - b.toString().length();
}
Instead Runnable you can provide your own interface.
Related
I have a collection of Java objects where I want to run a single function across multiple values I might find in some of the object's member variables. I'm looking for a nice way to pass in which getter should be used so I can have one method do all that work. I was thinking about something like a Supplier, but that would mean I have to have one per instance of the class. Here's an example of what I'm trying to do (only I would like to do this without the if statement or with potentially n getters a switch statement:
import java.util.ArrayList;
import java.util.List;
public class TestSupplier {
private int varA;
private int varB;
public TestSupplier(int varA, int varB) {
this.varA = varA;
this.varB = varB;
}
public int getA() {
return this.varA;
}
public int getB() {
return this.varB;
}
public static void main(String[] args) {
List<TestSupplier> testList = new ArrayList<>();
testList.add(new TestSupplier(1, 11));
testList.add(new TestSupplier(2, 22));
// Can I pass something like a generic supplier instead of a bool?
TestSupplier.someCollectorFunction(testList, true);
TestSupplier.someCollectorFunction(testList, false);
}
public static void someCollectorFunction(List<TestSupplier> list, boolean isA /* what if I want more than one getter*/) {
int sum = 0;
for (TestSupplier obj: list) {
// This is where I wish I could have a generic supplier or something
if (isA) {
sum = sum + obj.getA();
}
else {
sum = sum + obj.getB();
}
}
System.out.println("I have a sum: " + sum);
}
}
Is there something is Java's functional API that would let me do this?
It sounds like what you want is
ToIntFunction<TestSupplier> fn = isA ? TestSupplier::getA : TestSupplier::getB;
for (TestSupplier obj: list) {
sum += fn.applyAsInt(obj);
}
It's up to you whether you consider that an improvement.
You could also pass in the ToIntFunction instead of the boolean, passing in TestSupplier::getA instead of true etc.
I'm developing a game in which there're many classes. The game appears like a grid plane. I have a function which can detect whether a grid consist of any kind of specified class of object. This function return true if the grid contain any one of the specified type of object and return false if there's none.
However, when the number of classes needed to be detected increase, the parameter list can easily become awfully long, does anyone know how can I resolve that problem? Any design pattern would help? Or my design is acceptable in this case?
public boolean sameClass(int x, int y, String... className) {
for (Entity entity : entities) {
if (entity.getX() == x && entity.getY() == y) {
for (String name : className) {
if (name == entity.getClassName()) {
return true;
}
}
}
}
return false;
}
examples of using the method
sameClass(x, y - 1, "Boulder", "Enemy", "Wall")
sameClass(x, y - 1, "Player")
You can send Collection to your method:
Set<String> params = new HashSet("Boulder", "Enemy", "Wall");
boolean result = sameClass(x, y - 1, params);
You can use Builder-like pattern:
boolean result = new Checker(x, y - 1)
.param("Boulder")
.param("Enemy")
.param("Wall")
.check();
Also, if "Boulder", "Enemy", "Wall" are class of unit, it's better to use Enum instead of strings.
=== Example of possible solution ===
public class Checker {
private int x;
private int y;
private Set<Type> params = new HashSet();
// Entity related code here
public Checker(int x, int y) {
this.x = x;
this.y = y;
}
public Checker param(Type type) {
this.params.add(type);
return this;
}
public boolean check() {
for (Entity entity : entities) {
if (entity.getX() == x && entity.getY() == y) {
return params.contains(entity.getType());
}
}
return false;
}
public enum Type {
BOULDER,
ENEMY,
WALL,
PLAYER
}
}
First of all, don't ever try to compare java strings for equality using '==' unless otherwise you are testing for reference equality only. Rather use .equals() method. Read How do I compare strings in Java? to know more on this aspect.
And, for your actual problem, you can use different techniques. I would prefer to send array of Strings as parameter to keep the method call simple.
Implement your method like below:
public boolean sameClass(int x, int y, String[] className) {
for (Entity entity : entities) {
if (entity.getX() == x && entity.getY() == y) {
for (String name : className) {
if (name.equals(entity.getClassName())) {
return true;
}
}
}
}
return false;
}
Then create a class to store all the possible class name check combination you want to check for:
public class ClassNameCollection {
public static final String[] detectMultiple = new String[]{ "Boulder", "Enemy", "Wall" };
public static final String[] detectPlayer = new String[]{ "Player" };
}
When using this method, try something like below:
sameClass(x, y - 1, ClassNameCollection.detectMultiple);
sameClass(x, y - 1, ClassNameCollection.detectPlayer);
This is actually similar to the way you are handling it using var..args but one advantage of using this way I have described is, for a particular purpose (in your case- detecting wall, detecting equipable , etc.) you can create array of strings once and can call the method using that array variable multiple number of times without the need of writing those large number of lists of class names several times.
I want to list all names that end with "Reda" and ignore case sensitivity, I have tried the condition in the toString method at the bottom, but it would not print any thing.
public class Customer {
public static void main(String[] args) throws IOException {
File a = new File("customer.txt");
FileWriter v = new FileWriter(a);
BufferedWriter b = new BufferedWriter(v);
PrintWriter p = new PrintWriter(b);
human Iman = new human("Iman", 5000);
human Nour = new human("Nour", 3500);
human Redah = new human("Redah", 0);
human iman = new human("iman", 200);
human MohamedREDA = new human("MohamedREDA", 3000);
human Mohamed_Redah = new human("Mohamed Redah", 2000);
human[] h = new human[6];
h[0] = Iman;
h[1] = Nour;
h[2] = Redah;
h[3] = iman;
h[4] = MohamedREDA;
h[5] = Mohamed_Redah;
p.println(Iman);
p.println(Nour);
p.println(Redah);
p.println(iman);
p.println(MohamedREDA);
p.println(Mohamed_Redah);
p.flush();
}
}
class human {
public String name;
public double balance;
public human(String n, double b) {
this.balance = b;
this.name = n;
}
#Override
public String toString() {
if (name.equalsIgnoreCase("Reda") && (name.equalsIgnoreCase("Reda"))) {
return name + " " + balance;
} else
return " ";
}
}
Please avoid putting condition in toString method. Remove the condition there
public String toString() {
return name + " " + balance;
}
and change your logic in Customer class
human[] h = new human[6];
h[0] = Iman;
h[1] = Nour;
h[2] = Redah;
h[3] = iman;
h[4] = MohamedREDA;
h[5] = Mohamed_Redah;
for (int i = 0; i < h.length; i++) {
if (h[i].name.toLowerCase().endsWith("reda")) { // condition here
p.println(h[i]);
}
}
And make use of loops do not duplicate the lines of code.Every where you are manually writing the lines.
Check Java String class and use required methods to add condition.
String redahname = ("Redah").toLowerCase(); //put your h[0] instead of ("Redah")
if(name.endsWith("redah")){ //IMPORTANT TO BE IN LOWER CASE, (it is case insenitive this way)
//your code here if it ends with redag
System.out.println(redahname);
} //if it does not end with "redah" it wont out print it!
You can use this, but can you please explain your question more? What exactly do you need?
try this
#Override
public String toString() {
if (name.toLowerCase().endsWith("reda"))) {
return name + " " + balance;
} else
return " ";
}
String.equals() is not what you want as you're looking for strings which ends with "Reda" instead of those equal to "Reda". Using String.match or String.endsWith together with String.toLowerCase will do this for you. The following is the example of String.match:
public class Reda {
public static void main(String[] args) {
String[] names = {"Iman", "MohamedREDA", "Mohamed Redah", "reda"};
for (String name : names) {
// the input to matches is a regular expression.
// . stands for any character, * stands for may repeating any times
// [Rr] stands for either R or r.
if (name.matches(".*[Rr][Ee][Dd][Aa]")) {
System.out.println(name);
}
}
}
}
and its output:
MohamedREDA
reda
and here is the solution using endsWith and toLowerCase:
public class Reda {
public static void main(String[] args) {
String[] names = {"Iman", "MohamedREDA", "Mohamed Redah", "reda"};
for (String name : names) {
if (name.toLowerCase().endsWith("reda")) {
System.out.println(name);
}
}
}
}
and its output:
MohamedREDA
reda
You shouldn't put such condition in toString() method cause, it's not properly put business application logic in this method.
toString() is the string representation of an object.
What you can do, is putting the condition before calling the toString() , or making a helper method for this.
private boolean endsWithIgnoringCase(String other){
return this.name.toLowerCase().endsWith(other.toLowerCase());
}
None of your humans are called, ignoring case, Reda, so your observation of no names printed is the manifestation of properly working logic.
Your condition is redundant: you perform the same test twice:
name.equalsIgnoreCase("Reda") && (name.equalsIgnoreCase("Reda"))
If you need to match only the string ending, you should employ a regular expression:
name.matches("(?i).*reda")
toString is a general-purpose method defined for all objects. Using it the way you do, baking in the business logic for just one special use case, cannot be correct. You must rewrite the code so that toString uniformly returns a string representation of the object.
I know that there isn't way to access to the links of variables in java (like in &C or &php). But for example I have such task:
public class JustTest {
private int n = 1;
private int x = 10;
public int[] getIntegers() {
return new int[] { n, x };
}
public void filledInteger() {
int[] vals = getIntegers();
System.out.println("Before change");
System.out.println(Arrays.toString(vals));
vals[0] = 2;
vals[1] = 20;
System.out.println("After change");
System.out.println(Arrays.toString(vals));
System.out.println("Values of name & xml");
System.out.println(n);
System.out.println(x);
System.out.println("calling getIntegers");
System.out.println(Arrays.toString(getIntegers()));
}
public static void main(String[] args) {
JustTest t = new JustTest();
t.filledInteger();
}
}
The result is:
Before change
[1, 10]
After change
[2, 20]
Values of name & xml
1
10
calling getIntegers
[1, 10]
So, I want to change values of "n" and "x" fields of the class instance. I can't do this by setting straightly (this->n = 20;), because I may dont know what fields do I have. Only method getIntegers knows.
(No in this code, but for example I have child class with its own fields and in the parent class I have a method filledInteger() which should change specified properties of the child class ( he knows about this properties from the method getIntegers which is abstract in the parent class and implemented in the child class))
Here is simple implementation (without inheritance), using links in php
<?php
class JustTest {
private $n = 1;
private $x = 10;
public function getIntegers() {
return array( &$this->n, &$this->x );
}
public function filledInteger() {
$vals = $this->getIntegers();
echo("Before change" . "<br/>");
echo(print_r($vals, true) . "<br/>");
$vals[0] = 2;
$vals[1] = 20;
echo("After change" . "<br/>");
echo(print_r($vals, true) . "<br/>");
echo("Values of n & x". "<br/>");
echo $this->n , "<br/>";
echo $this->x , "<br/>";
echo("call getIntegers again" . "<br/>");
echo(print_r($this->getIntegers(), true) . "<br/>");
}
}
$t = new JustTest();
$t->filledInteger();
?>
The result is:
Before change
Array ( [0] => 1 [1] => 10 )
After change
Array ( [0] => 2 [1] => 20 )
Values of n & x
2
20
call getIntegers again
Array ( [0] => 2 [1] => 20 )
That is what I exactly need. Im just curious how do I implement this in java
Hope you understood.
Next example:
public abstract class ParentTest {
abstract int[] getIntegers();
public void fillIntegers(int[] newIntegers) {
int[] integersOfChild = getIntegers();
for (int i = 0; i < integersOfChild.length; i++) {
integersOfChild[i] = newIntegers[i];
}
}
}
public class ChildTest extends ParentTest {
private int x;
private int y;
#Override
int[] getIntegers() {
return new int[] {x, y};
}
}
public class UseTest {
void main() {
List<ParentTest> list;
for (ParentTest item : list) {
item.fillIntegers(myItegers);
}
}
}
This is what I need. I have a list of ParentTest instances (it may be ChildTest, or ChildTest2, or ChildTest3; but they all children of a ParentTest) and I need to fill all fields with my integer values, but I dont know if items in the list instances of a ChildTest, or ChildTest2, or ChildTest3 class
How do I implement this in Java?
With great pain via the Reflection API. If you want to write code like this, the best idea is to use another language.
Consider programming in Groovy instead. You can use array syntax to directly access class members by name: t["n"] = 2; This works with legacy Java code, so there is no need to modify TestClass to support this usage.
The concept you are talking about is called pass by reference. Java has for the most part abandoned it - it creates too many side-effects, like the one you are seeing here.
The issue is that while unfortunately you can't do this here, it actually prevents a huge number of unintentional bugs being released.
What about something like that:
public final class JustTest {
private final Map<String, Object> fields;
public void filledInteger() {
System.out.println("Before change\n" + this.fields);
fields.put("N", 2);
fields.put("X", 20);
System.out.println("After change\n" + this.fields);
System.out.println("Values of name & xml\n" + fields.get("N")
+ "\n" + fields.get("X"));
}
private JustTest() {
this.fields = Maps.newHashMap(); // guava
fields.put("N", 1);
fields.put("X", 10);
}
public static void main(String[] args) {
final JustTest t = new JustTest();
t.filledInteger();
}
}
You can't do individual fields without reflection, but you can change the contents of collections. Note that this is not really intended behavior, but rather something you have to be careful of when using collections.
This outputs 5 3 2 4 2 4
public class Test
{
public Vector<Integer> args = new Vector<Integer>();
public void fillArgs()
{
args.add(5);
args.add(3);
}
public Vector<Integer> getArgs()
{
return args;
}
public static void main(String args[])
{
Test s = new Test();
s.fillArgs();
Vector<Integer> temp = s.getArgs();
for (Integer i : temp)
System.out.println(i);
temp.setElementAt(2, 0);
temp.setElementAt(4, 1);
for (Integer i : temp)
System.out.println(i);
for (Integer i : s.getArgs())
System.out.println(i);
}
}
Your php example does not return an array of ints, but rather an array of int pointers. This is NOT something you can do in Java, in fact, this is NOT something you want to do in Java. Give a use case, and there is likely a better way to solve the problem you have.
If you want to return an object that others can affect and that are contained as member variables, do that. An ArrayList, HashMap, etc... there are plenty of things that can fit your needs. If you are given someone elses class and you must stick your nose in their code, you can get around their private declaration doing the following:
public void setN(JustTest j, int n) {
//You would handle some exceptions here also
Field f = JustTest.class.getDeclaredField("n");
f.setInt(j, n);
}
I am looking for an algorithm in Java that creates an object thats attributes are set to the first not-null value of a string of objects. Consider this array (I will use JSON syntax to represent the array for the sake of simplicity):
{
"objects": [
{
"id": 1,
"val1": null,
"val2": null,
"val3": 2.0
},
{
"id": 2,
"val1": null,
"val2": 3.8,
"val3": 6.0
},
{
"id": 3,
"val1": 1.98,
"val2": 1.8,
"val3": 9.0
}
]
}
In the end, I want one object that looks like this:
{
"id": 1,
"val1": 1.98,
"val2": 3.8,
"val3": 2.0
}
Where val1 comes from the third object, val2 from the secound and val3 and id from the first, because these are the first objects found where the attribute isn't null.
What I have done so far in Java and what works really fine is this:
// Java code that proceeds a deserialized representation of the
// above mentioned array
int k = 0;
while (bs.getVal1() == null) {
k++;
bs.setVal1(objectArray.get(k).getVal1());
}
However, I am not satisfied, because I would have to write this code four times (getId, getVal1, getVal2, getVal3). I am sure there must be a rather generic approach. Any Java guru who could give a Java beginner an advice?
Before getting to your actual question, here's a better way of writing your existing loop: (replace Object with whatever the actual type is)
for (Object o : objectArray) {
Double d = o.getVal1();
if (d != null) {
bs.setVal1(d);
break;
}
}
Considering the way your objects are laid out now, there isn't a better way to do it. But you can do better if you change the structure of your objects.
One way is to put your different value fields (val1, val2, ...) into an array:
Double val[] = new Double[3]; // for 3 val fields
public Double getVal(int index) {
return val[index];
}
public void setVal(int index, Double value) {
val[index] = value;
}
Then you can simply access the fields by their index and set all fields of bs in one iteration of the object array:
for (Object o : objectArray) {
for (int i = 0; i < 3; i++) {
Double d = o.getVal(i);
if (d != null) {
bs.setVal(i, d);
break;
}
}
}
+1 - Code repetition is a problem that can sometimes be hard to overcome in Java.
One solution is to create an Iterable class which allows you to iterate over the values in one of those objects as if they were in an array. This takes away some of the repetition from your code without sacraficing the legibility benefits of named variables.
Note that In my code below, I've created a separate iterable class, but you could also simply make the POD class iterable (which one of these is the best option for you depends on details you didn't cover with your example code):
(warning - not tested yet)
import java.util.Iterator;
public class Main {
static class POD{
Integer id; Double val1; Double val2; Double val3;
public POD(Integer i, Double v1, Double v2, Double v3){
id=i; val1=v1; val2=v2; val3=v3;
}
public POD(){ }
}
static class PODFields implements Iterable<Number>{
private POD pod;
public PODFields(POD pod){
this.pod=pod;
}
public PODFieldsIterator iterator() {
return new PODFieldsIterator(pod);
}
}
static class PODFieldsIterator implements Iterator<Number>{
int cur=0;
POD pod;
public PODFieldsIterator(POD pod) {
this.pod=pod;
}
public boolean hasNext() { return cur<4; }
public Number next() {
switch(cur++){
case 0:
return pod.id;
case 1:
return pod.val1;
case 2:
return pod.val2;
case 3:
return pod.val3;
}
return null;//(there are better ways to handle this case, but whatever)
}
public void remove() { throw new UnsupportedOperationException("You cannot remove a POD field."); }
}
public static void main(String[] args) {
POD [] objectArray = {new POD(1,null,null,2.0),
new POD(1,null,null,2.0),
new POD(1,null,null,2.0),
new POD(1,null,null,2.0)};
POD finalObject=new POD();
for (POD cur : objectArray){
PODFieldsIterator curFields = new PODFields(cur).iterator();
for (Number finalValue : new PODFields(finalObject)){
Number curValue = curFields.next();
if (finalValue==null)
finalValue=curValue;
}
}
for (Number finalValue : new PODFields(finalObject))
System.out.println(finalValue);
}
}
Edit: Oops - looks like I forgot Numbers are immutable. I suppose you could overcome this by having the iterator return functors or something, but that's possibly going a bit overboard.
Whenever you want to eliminate code duplication, one of the first things you look for is whether you can extract a reusable method. Reflection helps you call arbitrary methods in a reusable way. Its not the prettiest thing in the world, but this method works for you:
#SuppressWarnings("unchecked")
public <T> T firstNonNull(String methodName, TestObject... objs) {
try {
Method m = TestObject.class.getMethod(methodName, (Class[])null);
for (TestObject testObj : objs) {
T retVal = (T)m.invoke(testObj, (Object[])null);
if (retVal != null) return retVal;
}
return null;
} catch (Exception e) {
//log, at a minimum
return null;
}
}
Testing with a class like this:
public class TestObject {
Integer id;
String val1;
Map<String, Boolean> val2;
public int getId() {
return id;
}
public String getVal1() {
return val1;
}
public Map<String, Boolean> getVal2() {
return val2;
}
}
This JUnit test demonstrates its usage:
#org.junit.Test
public void testFirstNonNull() {
TestObject t1 = new TestObject();
t1.id = 1;
t1.val1 = "Hello";
t1.val2 = null;
TestObject t2 = new TestObject();
Map<String, Boolean> map = new HashMap<String, Boolean>();
t2.id = null;
t2.val1 = "World";
t2.val2 = map;
TestObject result = new TestObject();
result.id = firstNonNull("getId", t1, t2);
result.val1 = firstNonNull("getVal1", t1, t2);
result.val2 = firstNonNull("getVal2", t1, t2);
Assert.assertEquals(result.id, (Integer)1);
Assert.assertEquals(result.val1, "Hello");
Assert.assertSame(result.val2, map);
}