How to get an object using a string in Java - java

I've been trying to make my code more efficient, and I'm stuck on an issue where I have to repeat myself a lot to create 40+ objects (which results in 40+ functions with basically the same code, just different objects and different values). I am wondering if there is a way to make something like this in Java:
public void createObject(String objectName) {
getObject(objectName).setType(ymlFile.getString(objectName + ".type"));
// getObject(objectName) would be the object which has the same name as the value of the string objectName
}
Currently I have to have basically this code (with more variables) for over 40 objects, so I was wondering if it is possible to be able to retrieve the object by using the value in the string called objectName, thus meaning that I only have to call the method 40 times, instead of having the big block of code 40 times.
Thanks.
EDIT:
No, this isn't to do with YAML (not really anyway, just showing some of the code). My main issue is I need to be able to retrieve objects by using values of a string.
As for examples of the repetitive code, it's basically this:
public void createObject1() {
object1.setType(type1);
}
public void createObject2() {
object2.setType(type2);
}
// etc. for about 40 objects. basically i want to be able to change that to this:
public void createObject(String objectName) {
objectName.setType("value"); // so basically, retrieve the object that has the same name as the value of objectName
}

This looks like a case of the XY problem to me.
You probably just want to use two arrays to keep track of all objects and types, especially since it's really bad practice to name variables something1, something2 and so on.
So replace your object and type variables with:
YourClass[] objects = new YourClass[40];
Type types = new Type[40];
and replace your creatObject() methdod with:
public void createObject(int index) {
objects[index].setType(types[index]);
}
which you could even loop over like this:
// This condition is overkill since both arrays should have the same size,
// but if you plan on doing something different than that, this should work.
for(int i = 0; i < objects.length && i < types.length; i++)
createObject(i);
If you really want to use strings though, you could do the same thing with a Map<String, YourClass> and a Map<String, Type>.

Related

Java - Manual object validation against a white list

I'm trying to write a class to take a mega object, and ensure that only certain fields have been changed, normally you would annotate / add validation this way, but that is not an option in this case unfortunately, the only thing I can change is the one class I am working on, which will receive the very large (and very nested!) object that I'm supposed to somehow validate.
My initial thoughts was to make a 'list' of things that can be changed, then iterate over all properties in the object and check if anything has been updated that is not on the 'whitelist', I have the old version of the object, so I can check each field against the old one to confirm, but I'm not entirely sure how to do this, or if there is a better solution. I've never tried something like this before.
Any suggestions are appreciated. If there aren't any better solutions, how should I create the white list / iterate over all properties / nested properties of the mega object?
UPDATE:
Based on the suggestions, here is what I'm trying out, it still have a few problems though (Please note I'm just throwing things around, this is by no means my final class or good programming yet):
isTraversable works on collections, but I'm not sure how to get check custom classes, eg. a Person class, which would still need to be iterated through.
There are cyclic refs all over the place, not sure how to handle those either.
public class Test {
private Object obj1;
private Object obj2;
private List<String> whitelist;
public void validate(Object objectToTraverse,
Object objectToCompareTo,
List<String> whitelist){
this.obj1 = objectToTraverse;
this.obj2 = objectToCompareTo;
this.whitelist = whitelist;
traverseAndCompare(obj1, obj2);
}
private void traverseAndCompare(Object objectToTraverse,
Object objectToCompareTo){
try {
for (Field field : objectToTraverse.getClass()
.getDeclaredFields()) {
field.setAccessible(true);
Object fieldValue = field.get(objectToTraverse);
if (isTraversable(field)) {
traverseAndCompare(field.get(objectToTraverse),
field.get(objectToCompareTo));
} else {
getFieldValuesAndCompare(field, obj1, obj2);
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
private boolean getFieldValuesAndCompare(Field field,
Object obj1,
Object obj2)
throws Exception{
Object value1 = field.get(obj1);
Object value2 = field.get(obj2);
return compare(value1, value2);
}
private boolean compare(Object value1,
Object value2){
return Objects.equals(value1, value2);
}
private boolean isTraversable(Field field){
// This should handle collections, but it does not work
// on custom classes, eg. Person class
if (Collection.class.isAssignableFrom(field.getType())) {
return true;
}
// Need to somehow figure out is this is a class with
// properties I can traverse, or something with a value,
// like String, Long, etc, hopefully
// without listing everything
return false;
}
}
Putting descriptive answer since object can not be shared due to legal reason.
You have couple of choices. Each with pro and con.
Reflection
You can maintain a list of fields not allowed to change with their full path. Like a.b.c. You can then write pure reflection code or use common utils like http://commons.apache.org/proper/commons-beanutils/ to get values (even deep in object tree) and compare.
It needs less code and less maintenance. But you need to know exact list of blacklist fields. Performance wise it will take little bit more time.
Simple plain code technique
Write your own comparator or method in java to go through all fields that can not change and decide. Need lot of code but very easy to maintain and performance wise best.

int vs Integer vs a user made class to achieve effective pass by reference behavior in Java

Let's say you have a class of object with three
integer fields that you want to possibly change, all in the same way, with one method.
Let's keep it simple and say all that the method does is add 1 to the parameter passed to it.
That is to say, the desired behavior is that by the time the method has completed, the relevant field has increased by 1.
This is impossible to achieve in Java using the primitive type "int" for those fields.
I know about how Java is "always" pass by value, and not pass by reference,
- and - i've heard whisperings on the internet that this is one reason that the Integer class exists, along with other object "wrapper" classes
for ordinarily primitive types such as int and double.
Sending an object as an argument to a method should, in theory, provide a way to [effectively, if not technically] pass by reference, since the value that is passed, is supposedly the value of the reference to the object.
Very tricky. BUT - and this is where my annoyance comes in - I've tried achieving this very simple task by passing an Integer argument instead of an
int, and the desired behavior was still not accomplished. 1 was not added to the relevant field.
And yet, when I made my very own object, which consisted of just one field, an int value, and passed an instance of this object as an argument
to an appropriate method which would simply add 1 to the passed parameter, the desired behavior was in fact accomplished. 1 was added to the relevant field.
So the questions orbiting around this query are - Is it really going to be necessary to craft my own homemade class just to carry a simple integer value
every time I want to achieve this desired behavior? Can the existing tool provided by Java, Integer, really not perform this simple task?
Instead of having one nice, neat method to handle all three of the hypothetical integer fields i mentioned in the beginning, I felt compelled (in a separate, similar project that ultimately provoked this line of thinking) to make a separate method corresponding to each of the three fields, with essentially the same exact code in each one. This seems very inefficient.
It may not seem like a big deal, on the surface, to write three similar methods instead of one, but to clarify why this dismays me - imagine instead of an object with three integer fields as I stated, there are say, i don't know, four thousand. It would be so much better to write just one thing to perform the same kind of behavior, instead of copying and pasting (and changing whatever little bits necessary) four thousand times.
So I suppose the ultimate question is,
Why doesn't Integer function in a reasonable way? What's the point of wrapping a primitive in an Object at all, if it doesn't even help perform something this simple? Am I missing something simple about how to get Integer to function in the desired way? (Hopefully so) The answer seems close yet infuriatingly out of reach since "RInteger" produces the desired behavior, yet "Integer" doesn't.
The entire source code I used while trying to figure out how to construct this painstaking question is below.
package r9mp;
import javax.swing.SwingUtilities;
public class RefTest2 {
//[main m]
public static void main(String[] args){
SwingUtilities.invokeLater(new Runnable(){
public void run(){
new RefTest2();
}
});
}
//[fields]
int i;
Integer I;
RInteger RI;
//[constr]
public RefTest2(){
intTest();
IntegerTest();
RIntegerTest();
display();
}
//[methods]
private void intTest(){
i = 100;
intMethod(i);
}
private void IntegerTest(){
I = 100; //boxing? auto?
IntegerMethod(I);
I = 100; //just in case.
IntegerMethod2(I);
}
private void RIntegerTest(){
RI = new RInteger(100);
RIntegerMethod(RI);
}
private void intMethod(int ipar){
ipar = ipar + 1;//no change. expected.
}
private void IntegerMethod(Integer IPar){
IPar = IPar + 1;//no change. frustrating.
pln("From inside IntegerMethod: IPar = " + IPar );
pln("From inside IntegerMethod: I = " + I );
}
private void IntegerMethod2(Integer IPar){
IPar = new Integer(IPar+1);//still no change. there are no set methods for Integer, or I'd try them.
}
private void RIntegerMethod(RInteger riPar){
riPar.value = riPar.value + 1;
}
private void display(){
pln(
"Display... \n" +
"i: " + i + "\n" +
"I: " + I + "\n" +
"RI: " + RI + "\n" +
"--------"
);
}
private void pln(){
pln("");
}
private void pln(String s){
System.out.println(s);
}
//[internal class]
private class RInteger{
int value;
public RInteger(int v){
value = v;
}
public String toString(){
return ""+value;
}
}
}
And, here is the output...
How about one method for primitives and their wrappers?
private int incInteger(int value)
{
return value + 1;
}
and call for it:
int intVal = 100;
intVal = incInteger(intVal);
Integer integerVal = 200;
integerVal = incInteger(integerVal);
First of all, you need to read up on immutability to find out why it is a very good thing to have. There even exist entire languages (functional, mostly) that capitalize on it.
Once you have read about that, then read Eric Lippert's series of articles on immutability. Start here: https://blogs.msdn.microsoft.com/ericlippert/2007/11/13/immutability-in-c-part-one-kinds-of-immutability/ Mind = blown.
But to give you a quick hint as to why primitive wrappers like Integer are immutable, let me just say that these classes are often used as keys in Hash Maps, and a key must be immutable, so that its hashCode will never change, otherwise the hash map will fail with very difficult to track down behaviour. Mutable keys in hashmaps are nasty bugs.
You can achieve what you want with a class of your own devise which plays the role of a reference, or by simply passing an array and modifying the element at array[0].
My personal preferences are as follows:
I would try to do as much as possible with return values.
When return values are inapplicable, (as the case is with invokeLater,) then inner/nested/anonymous classes that have access to the fields of the enclosing class are my next preference.
When that's not an option either, then special classes crafted precisely for the application at hand are my next option. (MyMutableNumberWrapper.)
And when I just want something quick and dirty, then general-purpose classes like Ref<T> (or even single-element arrays) would be my final option.

How to access a struct via an ArrayList in Java

I have following lines of code:
private ArrayList<wordClass>[] words;
and
public class wordClass {
public String wordValue = null;
public int val = 0;
public boolean used = false;
}
Is there anyway I can access wordValue, val, and used via words? Like words[5].val? I know I can do that if they are just in an array of wordClass, but I want a dynamic array to make it easier to add and subtract from the array.
And yes, I know the values should be private. Just don't want to write getters and setters yet.
Thanks.
Do you really want an Array of an ArrayList?
It doesn't seem correct.
In Arrays, you use [] to access (words[0]).
In ArrayLists, you should use words.get(0).
The way you have coded, you should use: words[0].get(0).val to get the very first value.
But I recommend you to review your words definition.
ArrayList Documentation: http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html
Regards,
Bruno
Your code is a bit off for a dynamic array (Java has immutable arrays), so you need an ArrayList. Also, Java uses Capital Letters for class names (please follow the convention) -
// like this, changing wordClass to WordClass. Also, using the diamond operator
private ArrayList<WordClass> words = new ArrayList<>();
To access your WordClass fields you can use something like -
for (WordClass wc : words) {
if (wc.used) {
System.out.println(wc.wordValue + " = " + wc.val);
}
}
Note, you still need to create WordClass instances and place them into the words List.
Write wrapper classes for each value. e.g. What you call "getters".
Then call:
words[1].getWordValue() ==> None
Voila

Can I print out the name of the variable?

I have created a no. of constant variables, more than 1000, those constants are unique integer.
public static final FOO 335343
public static final BAR 234234
public static final BEZ 122424
....
....
....
Is there a way to print out the FOO, BAR and BEZ, the variable of the names in Java?
I am not familiar with java reflection. I don't know if that helps.
if ( FOO == 335343)
---> output "FOO"
if ( BAR == 234234 )
---> ouptut "BAR"
....
Actually asking this question behind is that I want to write log into the file
say
System.out.println("This time the output is " + FOO);
and the actual output is
This time the output is 335323
I want to know which variable comes from 335323.
Is there any other way apart from putting those variable and its associate constant into hashMap?
Thanks
There are some 'special case' that u can have workaround for this (which is told by other), but the most important question is: why would you want to do this (printing out variable name)?
From my experience, 99.9% of similar questions (how to print variable name? how to get variable depends on user inputting variable name? etc) is in fact raised by beginner of programming and they simply have made incorrect assumptions and designs. The goal they are trying to achieve normally can be done by more appropriate design.
Edit
Honestly I still do not think what you are trying to do is the way to go, but at least I think the following is a workable answer:
It is more or less a combination of previous answer:
(Haven't try to compile but at least it give u an idea)
class Constants {
public static final int FOO = 123;
public static final int BAR = 456;
private static Map<Integer, String> constantNames = null;
public static String getConstantName(int constVal) {
if (constantNames == null) {
Map<Integer, String> cNames = new HashMap<Integer, String>()
for (Field field : MyClass.class.getDeclaredFields()){
if ((field.getModifiers() & (Modifier.FINAL | Modifier.STATIC)) != 0) {
&& int.class == field.getType()){
// only record final static int fields
cNames.put((Integer)field.get(null), field.getName());
}
}
constNames = cNames;
}
return constantNames.get(constVal);
}
}
assuming you want to get a constant name, just do:
Constants.getConstantName(123); // return "FOO"
As I noted in my comment to the original post, I have a strong suspicion that the best solution for your current problem is to solve it in a completely different way. You seem to want to associate an int with a String, and one way to do this is to use a Map such as a HashMap. For e.g.,
import java.util.HashMap;
import java.util.Map;
public class MapDemo {
public static void main(String[] args) {
Map<Integer, String> myMap = new HashMap<Integer, String>();
myMap.put(335343, "FOO");
myMap.put(234234, "BAR");
myMap.put(122424, "BEZ");
int[] tests = {335343, 234234, 122424, 101010};
for (int i : tests) {
// note that null is returned if the key isn't in the map
System.out.printf("%d corresponds to %s%n", i, myMap.get(i));
}
}
}
Edit 1:
Per your recent comments and update to your original question, I take it that you have many numbers and their associated Strings involved in this program and that your need is to find the String associated with the number. If so, then you need to think re-design, that the numbers and their strings should not be hard-coded into your program but rather be part of the program's data, perhaps in a text file with one column being the numbers and the next column (separated by a space perhaps), the associated text. This way you could read in the data and use it easily in a HashMap, or data base, or really any way that you desire. This will give your project much greater flexibility and robustness.
You can use something like:
for (Field field : MyClass.class.getDeclaredFields()){
if (field.getType().toString().equals("int")){
int val = (Integer)field.get(MyClass.this);
switch (val){
case 335343:
case 234234:
System.out.println(field.getName());
}
}
}
Remember to change MyClass for your class name and that at least one instance should exist to get the value of the field. So, if you are planning on testing the code in a main method, you should change MyClass.this to something like new Myclass().
Another thing to remember is that the fields are attributes and not method variables (so it won't work if you are using this to access variables declared inside a method).
You can use enum.
If these numbers just need to be unique, you can say
public enum Yourname {
FOO, BAR, BEZ
}
and refer to the name as Yourname.FOO and the value as Yourname.FOO.ordinal(). You can use enums for if-blocks, switch-statements.
If you want to have the numbers you gave in the question, so if FOO needs to be 335343, you can create numbered enums. Have a look at is-it-possible-to-assign-numeric-value-to-an-enum-in-java and number-for-each-enum-item.
I would suggest that you print out the line number, not the variable name. That should give you enough to determine where the message is coming from. Here's more info on how to do that:
How can we print line numbers to the log in java
I had a similar problem with a long list of int variables that I had to print the name of each variable and its value (main goal was to create a text file that was going to be imported in an Excel file).
Unfortunately I'm quite new in Java programming, so the only solution that I found (probably wrong) is to use two different arrays: one String array for the String name and another Int array for the corresponding values.
For example:
int varName01, varName02, ....
String[] listNames = new String {"varName01", "varName02", .....
int[] listValues = new int {varName01, varName02, .....
for (int i=0; i<listValues.length;i++)
{
print String.format("%s %d", listNames[i], listValues[i]);
}
Probably this is not the correct way to do it, so any opinion from some Java expert would be more than welcome. Thanks!

Can Java store methods in arrays?

Well I wrote some code and all I was doing was for loops, but changing which method I called. I tried using a for loop so it'd be a bit neater (and out of curiosity to see if it could be done), but it doesn't compile when I do it this way, because it doesn't recognize an item in an array as a method, I think. This is what I have:
String[] moveArray = {moveRight,moveDown,moveLeft,moveUp};
for (i = 0; i < 4; i++) {
while (myWumpus.moveArray[i]) {
myWumpus.moveArray[i];
generator.updateDisplay();
}
}
When I try compile I get
not a statement myWumpus.moveArray[i]();
';' expected myWumpus.moveArray[i]();
(It refers to the first statement in the while loop)
So, I think it's maybe because I'm making it an Array of type String? Is there a type Method? Is this at all possible? Any solutions welcome :). Also, I can get it to work using 4 while loops, so you don't need to show me that solution.
You cannot store methods directly in arrays. However you can store objects, which implement the same method differently. For example:
Mover[] moveArray = {new RightMover(), new DownMover() new LeftMover(), new UpMover() };
for (i = 0; i < 4; i++) {
while (myWumpus.moveArray[i]) {
moveArray[i].move();
generator.updateDisplay();
}
}
Yes, you can store methods in arrays using Reflection, however it is likely that what you actually want to do in this situation is use polymorphism.
As an example of polymorphism in relation to your problem - say you created an interface as follows:
public interface MoveCommand {
void move();
}
You can then create implementations as follows:
public class MoveLeftCommand implements MoveCommand {
public void move() {
System.out.println("LEFT");
}
}
etc. for the other move options. You could then store these in an MoveCommand[] or collection like a List<MoveCommand>, and then iterate over the array/collection calling move() on each element, for example:
public class Main {
public static void main(String[] args) {
List<MoveCommand> commands = new ArrayList<MoveCommand>();
commands.add(new MoveLeftCommand());
commands.add(new MoveRightCommand());
commands.add(new MoveLeftCommand());
for (MoveCommand command:commands) {
command.move();
}
}
}
Polymorphism is very powerful, and the above is a very simple example of something called the Command Pattern. Enjoy the rest of your Wumpus World implementation :)
You can't store methods in arrays in Java, because methods aren't first-class objects in Java. It's a reason some people prefer to use other languages like Python, Scheme, etc.
The work-around is to create an interface which contains one method, then create four classes implementing that interface - the MoveRight, MoveLeft, etc... classes. Then you can store instances of those classes in your array and call them all the same way.
You can't call methods like that. But you can using reflection:
Just change the first line in the while-loop to:
Method m = myWumps.getClass().getMethod(moveArray[i]); // if the method is void
m.invoke(myWumps);
(you will have to declare/catch a few exceptions)
But you'd better avoid reflection, and use the Command pattern instead.
Updated answer for Java 8 and onwards-
Since the introduction of lambda expressions and method references in Java 8, storing various methods in variables is now possible. One main issue is that arrays don't currently support generic objects in Java, which makes storing the methods in arrays less doable. However they can be stored in other data structures like a List.
So for some simple examples you can write something like:
List<Comparator<String>> stringComparators = new ArrayList<>();
Comparator<String> comp1 = (s1, s2) -> Integer.compare(s1.length(), s2.length());
stringComparators.add(comp1);
or
List<Consumer<String>> consumers = new ArrayList<>();
Consumer<String> consumer1 = System.out::println;
consumers.add(consumer1);
and then loop/iterate through the List to get the methods.

Categories