I would like to write a function that would enable me to do the following
inputs: variable number of objects of any type
output: a string that would be NameObj1=ValueObj1, ..., NameObjN=ValueObjN
All objects I would pass to the function would have a toString() method.
Example:
double x=1.1; int y=2; ClassA a
theFunction(x,y,a)
=> this would output "x=1.1, y=1, a=[whatever a.toString() output]"
Is that possible ?
here's something close:
you can write a var-arg function like so:
public static String describeArguments (Object... arguments) {
StringBuilder output = new StringBuilder();
int counter = 1;
for (Object argument : arguments) {
output.append("object #").append(counter++).append(": ").append(argument.toString());
}
return output.toString();
}
strictly speaking method arguments dont have names. you could retrieve the argument parameter name using reflection if the symbol tables werent stripped out #compile time, but its brutish and ugly.
There's no way of getting what you wrote to be the "name" of a variable, because the only way of referencing it, is by itself, and by value is not possible as well.
As mentioned in other answers and comments there is no "name of an object". But if the objects you are interested in are all fields of one class, you could write a function that uses reflection to access that objects fields and prints their names.
Take a look at the reflection tutorial. There is also an example that is very close to what you might have in mind.
You can create a map like
Map<String,Object> map= new HashMap<String,Object>();
map.put("x", 1.1);
map.put("y",2);
map.put("a", MyClass.class);
And call theFunction(map), where theFunction is:
public void theFunction(HashMap<String,Object> list) {
StringBuilder sb = new StringBuilder();
for(String key:list.keySet()) {
try {
Object currentObject = list.get(key);
sb.append(key+"="+currentObject.getClass().getMethod("toString").invoke(currentObject)+" ");
}
catch(Exception e){}
}
System.out.println(sb.toString());
}
Related
I'm new to java lambda expression so i don't know exactly if what i'm asking is possible. If not possible please suggest a better way if any.
I have an class Object such as:
class Loan {
private String customerId;
private Integer tenure;
private Double amount;
...
}
I need to convert this object into a list of string. The way I'm doing it right now is:
List<String> loanAsList = getListFromLoan(loan);
public List<String> getListFromLoan(Loan loan) {
List<String> loanAsList = new ArrayList<>();
loanAsList.add(loan.getCustomerId());
loanAsList.add(Integer.toString(loan.getTenure());
loanAsList.add(Double.toString(loan.getAmount());
}
Can this be done using a lambda expression?
Loan has many more fields I have only shown a few. I want an expression in which no matter the number of field I could get a List.
A lambda function is just a function. Could you do what you need with a regular method?
If you want to achieve what you say (a method that, no matter how many attributes your class has, adds them all to a list) you'll need to either do it manually and update it every time you add/remove an attribute or use reflection
Something like this:
Loan loan = ...
List<String> loanAsList = new ArrayList<>();
for (Field f : loan.getClass().getDeclaredFields()) {
field.setAccessible(true);
Object value = field.get(loan);
loanAsList.add(value.toString());
}
Object someObject = getItSomehow();
for (Field field : someObject.getClass().getDeclaredFields()) {
field.setAccessible(true); // You might want to set modifier to public first.
Object value = field.get(someObject);
if (value != null) {
System.out.println(field.getName() + "=" + value);
}
}
Lambda Expressions don't do magic in Java 8(well they do but not what you are expecting if I understood you right).
Look at lambda expression as an alternate to anonymous classes, with the advantage that you don't need to wrap it in a class for it implement a function(method in pre java 8 terms). Look up "Behaviour Parameterisation" for a better understanding.
Saying that you can use "Function" functional interface provided by jdk. Represents a function that accepts one argument and produces a result. So you can write a method
public List<String> getListOfAttributes(Loan loan, Function<Loan, List<String>> myFunction) {
return myFunction.apply(loan);
}
and then call this method
getListOfAttributes(loan, (loan) -> {
List<String> loanAsList = new ArrayList();
loanAsList.add(loan.getCustomerId());
loanAsList.add(Integer.toString(loan.getTenure());
loanAsList.add(Double.toString(loan.getAmount());
return loanAsList;
}
so because of "behaviour parameterisation" you can pass in different functionalities to get the different List.
Suppose I want to send following parameters :
key1: value1,
key2: value2
But currently I can't decide what will be there at place of key1,key2
That may be any string. key1 may be city,key2 may be code. Or key 1 may be companyName and key 2 is domain. So how can I set any custom unknown parametrs in method of java? Consider that I know total number of parameters and data type of their values, but can't determine their exact keys now. How to implement it in java?
You can send an array of objects in your method:
Object[] myObjects = new Object[2];
myObjects[0] = "This is a string";
myObjects[1] = 5;
myMethod(myObjects);
public void myMethod(Object[] myObjects){
// DoSomethingOverHere
}
If you only have Strings you can do the same but specify an array of Strings instead of objects. If you use objects, make sure to check the instance of the objects before using it.
I assume what you mean to achieve is a method that can accept any type of argument and still do the work.
Below is the approach I would use:
Lets say you want to use myMethod:
class MainClass {
public Object myMethod(Object A,Object B)
{
Object C=(Object) (A.toString()+","+B.toString());
System.out.println(C.toString());
return C;
}
}
And you can call it with any type of parameters:
public class TesterClass {
MainClass mainClass=new MainClass();
mainClass.myMethod(123, "PQR");
mainClass.myMethod(123.00, "PQR");
mainClass.myMethod(123.00, 123);
mainClass.myMethod(new int[]{1,2,3}, "PQR");
}
Your output will be:
123,PQR
123.0,PQR
123.0,123
[I#659e0bfd,PQR
last one is array, you can manipulate its processing)
I have a clas called as MyFunctions that defines different functions func1, func2, etc. Also I have a class Process that stores the function name assigned to the object of this class:
Process p1 = new Process();
String fName1 = "func1";
p1.setFunctionName(fName1);
Process p2 = new Process();
String fName2 = "func2";
p2.setFunctionName(fName2);
In order to run a proper function, I do the following:
MyFunctions f = new MyFunctions();
if (p.getFunctionName() == "func1") {
output = f.func1(inputdata);
} else if (p.getFunctionName() == "func2") {
output = f.func2(inputdata);
}
I´m not sure that this approach is efficient. Is there any other way to solve this task?
Another question: is it possible to do something like this in JAVA?:
String fName = p.getFunctionName();
output = f."+fName+"(input);
First, this approach is not exactly correct. Never use == to compare objects. Use equals() instead:
MyFunctions f = new MyFunctions();
if ("func1".equals(p.getFunctionName())) {
output = f.func1(inputdata);
} else if ("func2".equals(p.getFunctionName())) {
output = f.func2(inputdata);
}
Second, I'd suggest you to use enum instead.
public enum FunctionInvoker {
func1 {
public Object invoke(MyFunctions o, Object ... arg) {
o.func1(arg[0]);
}
},
func2 {
public Object invoke(MyFunctions o, Object ... arg) {
o.func2(arg[0], arg[1]);
}
},
}
Now the usage looks like:
String functionName = ...; // probably read from file, etc.
Object result = FunctionInvoker.valueOf(functionName).invoke(args);
Java's Reflection API will most likely be useful to you. It allows you (among other things) to find methods in classes at runtime (when you have for example the method name in a string) and call methods that way.
A simple example:
String inputdata = "Hello";
// Finds the method "func1" in class MyFunctions that takes a String argument
Method method = MyFunctions.class.getMethod("func1", String.class);
// Calls the method on a new MyFunctions object, passing in inputdata
// as the argument
Object result = method.invoke(new MyFunctions(), inputdata);
System.out.println("Return value: " + result);
If you have a determined set of functions, then use public static constants to declare the names of the functions.
Example:
public static String FUNCTION1 = "func1";
public static String FUNCTION2 = "func2";
For you second question, yes it is possible using java reflection.
You can use reflection to find the function to execute.
For instance:
f.getClass().getDeclaredMethod(p.getFunctionName).invoke();
I´m not sure that this approach is efficient. MyFunctions f = new MyFunctions();
if (p.getFunctionName() == "func1") {
No. AFAIK it will not work. You are comparing references of String instead of comparing it's content.
if (p.getFunctionName() == "func1")
use .equals instead of == to compare 2 strings.
is it possible to do something like this in JAVA? output = f."+fName+"(input);
You can use reflection in java to do what you want.
Use an enum to decouple:
public enum Function {
ONE {
public void call(Functions functions) {
functions.func1();
},
TWO {
...
};
public abstract void call(Functions functions);
}
An the process:
Process p1 = new Process(Function.ONE);
MyFunctions f = new MyFunctions();
p1.call(f);
Hope you got the idea :)
Is it possible to get a Object that is instanced in the Code by a String at Runtime?
Somthing like that:
public String xyz = "aaaa_bbb";
getObject("xyz").some function of String (e.g.: .split("_"))
Thanks
Here's an example
If it's a class field, you can get it by name like this.
import java.lang.reflect.Method;
public class Test {
public String stringInstance = "first;second";
public void Foo() {
try {
Object instance = getClass().getDeclaredField("stringInstance").get(this);
Method m = instance.getClass().getMethod("split", String.class);
Object returnValue = m.invoke(instance, ";");
if(returnValue instanceof String[])
{
for(String s : (String[])returnValue )
{
System.out.println(s);
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String a[]){
new Test().Foo();
}
}
If it's a local method variable you are trying to invoke on, then you might be able to get at to the variable in from the current method from the call stack Thread.currentThread().getStackTrace() maybe.
It is hard to make out what you are asking, but you can fetch field values by name using reflection. Something like this:
Class c = this.getClass(); // or Someclass.class
Field f = c.getDeclaredField("xyz");
String value = (String) f.get(this);
... = value.split("_");
(I've left out a lot of exception handling ...)
But as a comment points out, if you are really trying to implement an associative array, there are better ways of doing this in Java; e.g. using a Map class.
You might have to rephrase the question.
If you just want to get the "aaaa" and "bbb" strings from the initial string, you can use StringTokenizer
If your String is a member field of your object, you can go take a look at the Field class.
However, I have to warn you that the code that you'll end up with will be by far longer than what you expect here. Indeed, you'll have to do some operations :
Get the Field obejct associated to xyz
Get method from its name and parameters list (using as an example Class#getDeclaredMethod(...))
Invoke the method on this particular instance
Each of these steps will eb a rather obscure line of code, with a bunch of throwed exceptions.
So, if you have an alternative, well, use it !
I have custom components on a jPanel and i would like to work with them without repainting them. I knwo if i use a List or Map that it is possible but i have to change the value in the Map and then repaint the GUI with the infomration in the Map.
I'm trying to create a class that can instantiate arrays at runtime by giving each array a "name" created by the createtempobjectname() method. I'm having trouble making this program run. I would also like to see how I could access specific objects that were created during runtime and accessing those arrays by either changing value or accessing them. This is my mess so far, which compiles but gets a runtime exception.
import java.lang.reflect.Array;
public class arrays
{
private static String temp;
public static int name = 0;
public static Object o;
public static Class c;
public static void main(String... args)
{
assignobjectname();
//getclassname();//this is supposed to get the name of the object and somehow
//allow the arrays to become updated using more code?
}
public static void getclassname()
{
String s = c.getName();
System.out.println(s);
}
public static void assignobjectname()//this creates the object by the name returned
{ //createtempobjectname()
try
{
String object = createtempobjectname();
c = Class.forName(object);
o = Array.newInstance(c, 20);
}
catch (ClassNotFoundException exception)
{
exception.printStackTrace();
}
}
public static String createtempobjectname()
{
name++;
temp = Integer.toString(name);
return temp;
}
}
Create a Map then you can add key/value pairs when the key is your name and the value is your array.
Following up from #Ash's answer, here is some illustrative code. Notice that there is no reflection involved.
Map<String, Object> myMap = new HashMap<String, Object>();
...
Object myObject = ...
myMap.put("albert", myObject); // record something with name "albert"
...
Object someObject = myMap.get("albert"); // get the object named "albert"
// get("albert") would return null if there nothing with name "albert"
EDIT I've edited the example to use the type Object, since that is more closely aligned with what you are trying to do (I think). But you could use any type instead of Object ... just replace the type throughout the example. And you can do the same with an ArrayList; for example:
List<Date> dates = new ArrayList<Date>();
dates.add(new Date());
Date firstDate = dates.get(0);
Notice that no typecasts are required.
I expect you're getting a ClassNotFoundException from this line:
c = Class.forName(object);
The value of object the first time it's called is "1", which is not a valid class name.
Class.forName requires a class name as input, such as "java.lang.Integer". Trying to "name" your array in this way doesn't make sense to me. You need to pick an appropriate Java class name.
If you want to "name" an array instance (after you've created it), you could always store the instance as the value in a Map, using the name as the key.