randomly generate variable names? - java

I've got a problem.. I've got something like...
if(condition(TEST) == true){
something (NAME) = new something(this);
}
This is inside a loop where there are many TEST variables being iterated through. I don't know how many and its possible each of them would need a "(NAME)" variable so basically I want to know how would I make java "on the fly" generate a name for these variables?
Thanks!

Are you sure you don't want to store the results in either an array or a collection?
The closest thing would be to use a Map. Randomly generate a String or an Integer key, and use it as a key to your Something value.
// Before all
Map<String, Something> myMap = new HashMap<String, Something>();
// For each of these
if(condition(TEST) == true){
String name = "VAR" + Math.random() // Don't remember the syntax here
myMap.put(name, new something(this));
}

Unless I'm misunderstanding your problem, you won't need to do this.
Variables in Java are lexically scoped, in that they are defined solely for the block in which they exist. On every iteration through the loop, your name parameter will refer to a different object, and will not be affected by the values it held on previous loops.
So you will only need as many parameters in your loop as there are attributes you want to operate on within the loop (possibly only one), which in all cases is something you'll know for sure when you write your code (at compile time) and is divorced from the (runtime) number of TEST objects.

If you're not storing them or referencing them later, and they're all the same type, you could use the same variable for all of them:
// Outside loop ...
something $name;
// Inside loop ...
if(condition(TEST) == true){
$name = new something(this);
}

The simplest way to generate in id (e.g. for a Map) is to use an AtomicInteger.
AtomicInteger counter = new AtomicInteger();
Map<String, Something> map = ...
String id = Integer.toString(counter.getAndIncrement(), 36);
map.put(id, new Something());
// later
Something s = map.get("0");
or it would be simpler to use a List which is naturally indexed.
List<Something> list = ...
list.add(new Something());
// later
Something s = map.get(0);

Related

How to get an object using a string in 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>.

Arrays.asList add ArrayList rather than specific members

I have an object which contains some package-private member variables and I'm adding them to a Google Sheets v4 ValueRange in another object. The current code looks a little bit like this:
List<List<Object>> data = new ArrayList<>();
...
/**
* Sets all the values in the ValueRange member variable
* #return the ValueRange object
*/
ValueRange requestBuilder() {
...
//For each case, add it to the value range
for (int i = 0; i < closedCases.size(); i++) {
data.add(
Arrays.asList(
closedCases.get(i).number,
closedCases.get(i).priority,
closedCases.get(i).firstResp,
closedCases.get(i).accName,
closedCases.get(i).subject,
closedCases.get(i).assigned,
closedCases.get(i).lastUpdated,
closedCases.get(i).daysOld,
closedCases.get(i).jiraCase
)
);
}
vr.setValues(data);
return vr;
}
The question that I'm seeking to answer is, is there any way to do Arrays.asList( closeCases.get(i) ) or add some kind of method on the case object to simply fill all that stuff in, rather than calling out each member variable in the Arrays.asList(). I'm also aware I can use a foreach, but would still need to use the same notation for adding items, which is what I'm trying to avoid.
In case anyone is interested, closedCases is just an ArrayList of an object with some strings and doubles in it.
You somehow need to specify what fields go into this list, in what order. If you want to capture all fields, you could use reflection to iterate over the object (potentially choosing declared, not inherited fields, and potentially choosing only package-private fields), as described here.
But that is not the idiomatic way to do it in Java.
Can you change the definition of the "object which contains some package-private member variables" so that instead it has a Map with key-value pairs?
You could add a List field in the object that is held by closedcases and call that field from inside the loop.
For instance, say the object is Foo,
Inside foo, create a field:
ArrayList<String> allFields = new ArrayList<String>{number. priority …… };
Method:
public ArrayList<String> getAll() {
return allFields;
}
And from inside the loop, just do
data.add(closedCases.get(i).getAll());
If the fields are not just string, you could create different arraylist that holds different types of object, which will increase the list again but could be substantially less that what you gave us.

How to use method in the name of variable?

I have to create a few variables like: "n23, n4, n18...".
So, they consist of two parts: letter "n" and a number witch I want to get from my method for generating random numbers(rand()).
Something like this:
for(int i = 0; i < 6; i++) {
int n*here_must_be_random_number_got_from_my_method*;
}
Is it possible to do something similar?
Java is no script language.
All identifiers, which means all package names, type names, method names, field names and variables, must be specified at compile time. So there is no way to concatenate your variable names based on values calculated at runtime.
BUT!
You do not even need to. Just use a java.util.Map. Instead of doing
int n*here_must_be_random_number_got_from_my_method* = *whatever_it_is_you_want_to_put_here*;
you can instead do
Map<Integer, Integer> myMap = new HashMap<>();
once, then put values inside the map like so:
myMap.put(*here_must_be_random_number_got_from_my_method*, *whatever_it_is_you_want_to_put_here*);
and get it back like so:
myMap.get(*here_must_be_random_number_got_from_my_method*);
You can't, but presumably you want to refer to these later, and if you were intending to refer to n123, then you can hopefully refer to them as n[123] instead. If that's the case, then you can use a java array, perhaps like this:
private int[] n = new int[999];
void populate() {
for(int i = 0; i < 6; i++) {
n[here_must_be_random_number_got_from_my_method] = something;
}
}
Note that java doesn't do sparse arrays, so the size of your array needs to be as large as the largest random number. If this us large, consider using a map as per Jan's answer.

In Java, Is it possible to concatenate the value of a variable into a variable name (Sounds messed up, but please read details)

Basically I have a variable, zlort = one;
I want to concatenate the value of zlort into a variable (object reference) name.
Like
BankAccount Accountzlort = new BankAccount;
I want the zlort in Account.zlort to actually be the replaced with value of zlort (one--meaning I want the value to be Accountone), and not zlort itself.
Is it possible to do this?
Thanks!
No you can't, but you might put the instance in a map:
Map<String,BankAccount> map = new HashMap<String,BankAccount>();
map.put("Account" + zlort, new BankAccount());
If you mean dynamically choosing the name to assign a variable to, then no.
You could use a HashMap to achieve the same effect.
It is not possible to change the name of a variable at runtime. That would lead to extreme security and stability problems when dealing with any real-world application.
However, as the two answers here have mentioned, a HashMap might acheive what you are looking for. (See the javadoc!!)
A HashMap (or any other map, for that matter) maps a Key to a Value. The concept is similar to a variable, which is a name -> value mapping. The only difference is that variables are part of the actual program code, which is effectively unmodifiable after compiling. A Map is a data structure that can be modified by the running program. This allows you to freely add key-value pairings to it.
Note that in Java, type-safety is encouraged through the use of Generics. Basically this ensures that the key can only be of one type (e.g. String) and the value can be of only one type (BankAccount). A thorough coverage of Generics can be found here.
You would declare this as follows:
Map<String, BankAccount> accounts = new HashMap<String, BankAccount>();
And then to add a key-value pair to the map, you would use the put() method (which 'puts' a value into the map, associated with a key)
String key = "Key"
BankAccount value = new BankAccount();
accounts.put(key, value);
To retrieve it, you would use the get() method.
BankAccount retrievedValue;
retrievedValue = accounts.get(key);
After reading the explanations in your comments, the fact that you can't use an array but can use an `ArrayList'...
Rather than creating a new variable name (or array element, or map value) for each BankAccount, you can probably use scope to your advantage.
Scope is the concept that a reference to a variable only has meaning within a certain part of code. If you declare a variable inside a method, that variable can only be seen within that method. A variable declared within a block (a loop, if statement, etc ) can only be seen from within that block.
Class fields have a different kind of scoping that can be adjusted with keywords (see here).
For example:
public class ScopeExample
int classInt = 10;
public void method() {
int methodInt = 0; // This integer can only be seen by code in
// this method
}
public void method2() {
//doSomething(methodInt) // This line won't compile because i is
// declared in a different method!
doSomething(classInt); // This line will compile and work
// because x is declared in the class that
// contains this method.
int index = 0;
while (index < 3) {
int whileInt = index; // This integer can only be seen from within
// this while loop! It is created each
// loop iteration.
doSomething(whileInt);
}
doSomething(whileInt); //This line won't work, whileInt is out of scope!
}
public doSomething(int a) {
System.out.println(a);
}
}
SO! If you create a BankAccount object within the loop, you don't have to worry about creating a new name for the next one. Each time the loop iterates it will become a new object (when you create it).
If you have to store it, you definitely will need to use an array or other data structure (ArrayList!).
Building on the idea of scope, you -can- have the same variable name for each new BankAccount. A variable reference name isn't guaranteed to be paired with the object that it refers to. That is a convenience to the programmer, so you don't have to know the exact memory address it is being stored in.
For example:
public static void main(String[] args) {
Object o;
int i = 0;
while (i < 5) {
Object reference = new Object(); // Create a new Object and store
// it in 'reference'
o = obj; // The Object 'o' now refers to the object in 'reference'
i++;
}
System.out.println(o); // This should print information about the
// LAST object created.
}
The new Object created in the loop does not belong to 'obj'. You as a programmer use 'obj' to point to the Object. The program doesn't really know what obj means, other than the fact that it points to the Object you just created.
Finally, you can use this along with an ArrayList to make your life easier.
public static void main(String[] args) {
// Our new ArrayList to hold our objects!
ArrayList<Object> stuff = new ArrayList<Object>();
int i = 0;
while (i < 5) {
Object obj = new Object(); // Create an object and make obj point to it.
stuff.add(obj); // Put "the object that 'obj' points to" in 'stuff'.
i++;
}
// This loop goes through all of the Objects in the ArrayList and prints them
for (int index = 0; index < stuff.size(); index++) {
System.out.println(stuff.get(i)); // This will print a single
// object in the ArrayList each time.
}
}

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!

Categories