This question already has answers here:
Can Java store methods in arrays?
(5 answers)
Closed 6 months ago.
I dont know if its posible but can I store methods or functions in an array? I know Multi dimensional array now and use it to store many arrays as i want. What i would like to do now is to store the methods or functions I create in a certain class. Because i want to store all of my functions to a certain class then call it if i want using loop. And to make my coding cleaner and easy to understand.
Example:
public String[] getDesiredFunction = {getName(),getLastname(),getMiddle()};
for(int i = 0;i<3;i++){
if(i == 1){
getDesiredFunction[i];
}
}
like that?
Is it posible?
You can't do exactly what you want, but can do something similar using an interface:
interface Function {
public void run();
}
class GetNameFunction implements Function {
public void run() {
//do stuff
}
}
...
And then you can write like this:
Function[] functions = {new GetNameFunction()};
for(int i = 0; i < functions.length; i++){
functions[i].run();
}
}
Java 6 does not have first-order functions, but you can use a functional object pattern:
interface NullaryFunction< B > {
B f();
}
public class Example {
private final Map< String, NullaryFunction< String > > mFuncs = new HashMap< String, NullaryFunction< String > >() { {
put( "getName", fncGetName );
put( "getLastname", fncGetLastname );
put( "getMiddle", fncGetMiddle );
} };
public String getName() { /* ... */ }
private NullaryFunction< String > fncGetName = new NullaryFunction< String >() {
#Override String f() { return getName(); }
};
public String getMiddle() { /* ... */ }
private NullaryFunction< String > fncGetMiddle = new NullaryFunction< String >() {
#Override String f() { return getMiddle(); }
};
public String getLastname() { /* ... */ }
private NullaryFunction< String > fncGetLastname = new NullaryFunction< String >() {
#Override String f() { return getLastname(); }
};
public String runAFunction( String strName ) {
return mFuncs.get(strName).f();
}
}
Java is not well suited for your use case. It is possible do with reflection.
As a starting point you could look into the reflection trail or see the related stackoverflow question.
You can store object instance and method name as string, using reflection can invoke this method like this:
public class Test {
public void sayHello(){
System.out.println("hello");
}
/**
* #param args
*/
public static void main(String[] args) {
Test test = new Test();
String methodName = "sayHello";
try {
Method m = test.getClass().getMethod(methodName, null);
m.invoke(test, null);
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
You need refer java refection
The way you stated in the question won't work. As a alternative you could do it like:
public String[] getDesiredFunction = {getName(),getLastname(),getMiddle()};
for(int i = 0;i<3;i++){
if(getDesiredFunction[i].equals("getName()")){
getName();
}
}
Related
Given Java source code and a preprocessor (like C++), I would like to replace all mentions of null with a function that returns null. It finds a call to null and replaces it with the following function.
public static Object returnNull(){
return null;
}
This fails because there are varied classes and:
functionThatWantsCustomClass( returnNull() ); //Object cannot be converted to CustomClass
or
if( cc == returnNull() ) //Object cannot be converted to CustomClass
etc.
Easiest solution I can imagine is having to parametrize the preprocessor, although that would require going through every single null to add the parameter maually, eg: null/*CustomClass*/.
Another method is spending a lot of time writing a much better parser so it always knows the required class for a returnTypedNull() function.
Is there a way to get through this error with minimal modification/parsing?
Use generics:
public static <T> T returnNull() {
return (T) null;
}
Follow-up from comment
The following code is as close to comment as I can decipher, and it compiles fine:
public class Test {
public static void main(String[] args) {
CustomClass cc = new CustomClass();
if (cc != returnNull())
cc.errlog( returnNull() );
}
public static <T> T returnNull() {
return (T) null;
}
}
class CustomClass {
void errlog(Exception e) {
}
}
Now, if there are 2 errlog methods with only one non-primitive parameter:
class CustomClass {
void errlog(Exception e) {
}
void errlog(String s) {
}
}
Then it will fail with error The method errlog(Exception) is ambiguous for the type CustomClass, because the compiler doesn't know whether T should be Exception or String, i.e. which of the two to call.
You have to explicitly tell the compiler:
cc.errlog( Test.<Exception>returnNull() );
Use generics ant it will work.
Example:
public class ReturnNullExample {
public static void main(String[] args) {
ReturnNullExample example = new ReturnNullExample();
example.someMethod(ReturnNullClass.returnNull());
CustomClass cc = null;
if(cc == ReturnNullClass.returnNull()) {
System.out.println("cc is null");
}
cc = new CustomClass();
if(cc != ReturnNullClass.returnNull()) {
System.out.println("cc is not null");
}
}
public void someMethod(CustomClass customClass) {
System.out.println("This method does nothing");
}
}
class CustomClass {
private int number;
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
}
class ReturnNullClass {
public static <T> T returnNull() {
return null;
}
}
I have a code that uses Field built in function in java and i could not find a way to replace it in c++ the code is shown below,
import java.lang.reflect.Field;
public class ParameterValue {
public String objectPath;
public Object objectReference;
public String fieldPath;
public String fieldPathNoCase;
public Field field;
public double value;
public ParameterValue(String path, ObjectTree tree, Field fieldInfo) {
objectPath = path;
objectReference = tree.getObject(path);
field = fieldInfo;
fieldPath = objectPath + "." + field.getName();
fieldPathNoCase = fieldPath.toLowerCase();
read();
}
public int getPrecision() {
if (field.getType().getName() == "float" || field.getType().getName() == "double")
return 2;
else
return 0;
}
public double getPrecisionMultiplier() {
return Math.pow(10, getPrecision());
}
public void read() {
String type = field.getType().getName();
try {
if (type.equals("double"))
value = field.getDouble(objectReference);
else if (type.equals("float"))
value = field.getFloat(objectReference);
else if (type.equals("int"))
value = field.getInt(objectReference);
else if (type.equals("byte"))
value = field.getByte(objectReference);
else
throw new RuntimeException();
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
value = Math.round(value * getPrecisionMultiplier()) / getPrecisionMultiplier();
}
public void write() {
String type = field.getType().getName();
try {
if (type.equals("double"))
field.setDouble(objectReference, value);
else if (type.equals("float"))
field.setFloat(objectReference, (float)value);
else if (type.equals("int"))
field.setInt(objectReference, (int)Math.round(value));
else if (type.equals("byte"))
field.setByte(objectReference, (byte)Math.round(value));
else
throw new RuntimeException();
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public void rebind(ObjectTree tree) {
objectReference = tree.getObject(objectPath);
}
}
What i have understood from the code is that i need to find a class that can convert the value in it to Double, Float,etc. I have looked for something that can do this but i was not able to do so.
reference of the code:
https://www.programcreek.com/java-api-examples/index.php?source_dir=SecugenPlugin-master/src/sourceafis/simple/Fingerprint.java#
As per my knowledge there is no equivalent class in C++. Now for your requirement first you list out what are all a java.lang.reflect.Field class provides in java. Once you listed all the utility methods, just sort list all methods that you really requires in your C++ application. Once done you do create a C++ class with the same name and methods types and implement the logic by yourself if possible.
I have a ListView and every time the selection is changed, I want to call a class with that name. For example, if the item is called "Text String" then the class TextString should be called. The code that I currently have is giving me an error saying The method insert(ArrayList<Element>) is undefined for the type Object ... Eclipse gives me a suggestion to cast the object as Element, but that doesn't do anything. The Element class is a superclass and TextString would implement that class.
Here is the code I have so far:
elementList.itemsProperty().bind(listProperty);
listProperty.set(FXCollections.observableArrayList(elementListItems));
elementList.setOnMouseClicked(new EventHandler<MouseEvent>() {
public String selectedElement = "Text String";
#Override
public void handle(MouseEvent event) {
selectedElement = (String)elementList.getSelectionModel().getSelectedItem();
selectedElement = selectedElement.replace(" ", "");
Class<?> clazz;
try {
clazz = Class.forName("elements."+selectedElement);
Constructor<?> ctor = clazz.getConstructor();
Object object = ctor.newInstance();
Method meth = clazz.getClass().getMethod("insert", new Class<?>[] { Canvas.class, ArrayList.class, GraphicsContext.class });
meth.invoke(object, canvas, objects, gc);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
});
Element.java
public abstract class Element {
public String name;
public String description;
public Canvas canvas;
public ArrayList<Element> objects;
public GraphicsContext gc;
void remove(){
}
void toggle(){
}
void setBounds(int x, int y, int w, int h){
}
public abstract void insert(Canvas canvas, ArrayList<Element> objects, GraphicsContext gc);
}
TextString.java
public class TextString extends Element {
private GraphicsContext gc;
TextString() {
super();
this.name = "Text String";
this.description = "A literal readable string of text.";
}
#Override
public void insert(Canvas canvas, ArrayList<Element> objects, GraphicsContext gc) {
this.gc = gc;
this.canvas = canvas;
this.objects = objects;
System.out.println("Text string created.");
}
}
How can I cast the object to whatever object is being selected by the listview?
You should use explicit casting.
Use clazz.getMethod(...) instead of clazz.getClass().getMethod(...)
Watchout objects to be ArrayList instance, not List.
Your code should like next:
try {
clazz = Class.forName("elements."+selectedElement);
Constructor<?> ctor = clazz.getConstructor();
Element object = (Element) ctor.newInstance();
Method meth = clazz.getMethod("insert", new Class<?>[] { Canvas.class, ArrayList.class, GraphicsContext.class });
meth.invoke(object, canvas, objects, gc);
} catch (ClassNotFoundException e) {
Tip.
I'd suggest changing the type of ArrayList parameter in insert method to List.
And also to catch only one generic Exception, instead of bunch of specific one.
Let me know if you any further issues with that.
I believe you are over complicating everything by trying to use reflection. It is optimal but sometimes I usually just rather do things simpler.
Why don't you make a factory helper that would import all the classes you might need and then use a switch to return the instance that you need?
Like:
public MyInterface returnClass(String type){
switch (type){
case: "Text String":
return new TextString():
//And so on
}
}
There is another way you can handle this, use a HashMap to store all the implementations as follows (this can be done when your application is started, the performance will be better).
Map<String, Element> objects = new HashMap<>();
objects.put("Text String", new TextString());
And the handle method becomes..
#Override
public void handle(MouseEvent event) {
selectedElement = (String) elementList.getSelectionModel().getSelectedItem();
// selectedElement = selectedElement.replace(" ", "");
objects.get(selectedElement).insert(Canvas.class, ArrayList.class, GraphicsContext.class);
}
This will be more readable and clean since we are not using Reflections.
What you need to do is simply have an interface MyElement
with method execute
Implementation of which will call whatever you need inside the "execute()"
basically I suggest command pattern, which is basis for all UI operations when doing BE
my 2 cents, implemntation example from my old-old project
CommandFactory factory = CommandFactory.getInstance();
Command command = factory.createCommand(relativeURL);
if(command != null){
command.execute( /* Object */ input);
}
}
into factory
/**
* Factory for commands
*
* #author andre
*/
public class CommandFactory {
// singleton instance
protected static CommandFactory instance = new CommandFactory();
//cache of objects
Map<String, Command> cache = new HashMap<>();
// protected constructor prevents creating object outside
protected CommandFactory(){
}
// return signleton instance of factory
public static CommandFactory getInstance(){
return instance;
}
/**
* create and return appropriate command
*
* #return found command
* #throws exception if something bad happened
*/
public Command createCommand(String classname){
try {
Command com = cache.get(URL);
if(com == null){
Command temp = (Command) Class.forName(classname).newInstance();
if(temp != null){
cache.put(URL, temp);
com = cache.get(URL);
}
}
return com;
} catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException ex) {
Logger.getLogger(getClass().getName()).error(ex);
return new Error404();
}
}
}
into interface
public interface Command{
void execute(Object input);
}
and implementation example
public class EditUserInfo implements Command {
#Override
public void execute(Object object) {
callWhatever((String) object);
}
private void callWhatever(String textFromField){
// inner logic example
}
}
I'm implementing custom logic in setters and enums in realm object class like this.-
public class SellerProducts extends RealmObject{
public Boolean isValid=true;
public String is_valid="";
public String quantity;
public int quantity_;
public String enumvalue;
public void setIs_valid(String is_valid){
if (is_valid.equals("0")) {
this.isValid = false;
}
this.is_valid=is_valid;
}
public String getIs_valid(){
return this.is_valid;
}
public void setQuantity(String quantity){
this.quantity=quantity;
try {
quantity_ = Integer.parseInt(this.quantity);
} catch (NumberFormatException e) {
e.printStackTrace();
}
if (!this.isValid) {
setEnum(ProductType.IN_ACTIVE);
} else if (this.quantity_ <= 0) {
setEnum(ProductType.OUT_OF_STOCK);
} else {
setEnum(ProductType.ACTIVE);
}
}
public String getQuantity(){
return this.quantity;
}
public enum ProductType {
ACTIVE, IN_ACTIVE, OUT_OF_STOCK
};
public void setEnum(ProductType val) {
this.enumvalue=val.toString().toUpperCase();
}
public ProductType getEnum() {
return ProductType.valueOf(enumvalue);
}
}
when i am calling getEnum from the other fragment class it is returning null exception like this
*java.lang.NullPointerException: name == null
at java.lang.Enum.valueOf(Enum.java:189)
at com.localwizard.realm_db.SellerProducts$ProductType.valueOf(SellerProducts.java:331)
at com.localwizard.realm_db.SellerProducts.getEnum(SellerProducts.java:348)*
I'm new to realm so I don't know where I'm wrong?
Ashish, i think you are not setting the ProductType enum and trying to get it and you geeting the exception. Here is the code which i have tried and it is working fine -
public class OtherFragment {
public static void main(String[] aa)
{
SellerProducts sp = new SellerProducts();
sp.setQuantity("10"); // setting the quantity
System.out.println(sp.getEnum()); // ACTIVE is set as Enum
System.out.println(sp.getQuantity()); // 10
System.out.println(sp.getEnum() == ProductType.ACTIVE); // true
sp.setEnum(ProductType.IN_ACTIVE); // Now IN_ACTIVE is set
System.out.println(sp.getEnum() == ProductType.ACTIVE); // false
}
}
If this is not what you want then please add your peace of code, how you meant to set the quantity and trying to get the enum value.
If it answers your question then please accept the answer.
I need to invoke the field accessor methods, i.e the getter of a generic enum, but cannot figure out how to invoke the methods, or more specifically how to pass a generic enum as a parameter for the invoke-method.
Thanks in advance, any help is appreciated.
this is what I'd like to do more or less.
public void(Class<? extends Enum<?>> enumType) {
Enum<?>[] enumConstants = enumType.getEnumConstants();
String[] text = new String[enumConstants.length];
String[] names = new String[enumConstants.length];
for (int i = 0; i < enumConstants.length; i++ ) {
Method[] methods = enumConstants[i].getClass().getDeclaredMethods();
for (Method m: enumConstants[i].getClass().getDeclaredMethods()) {
System.out.println(enumConstants[i].name() + ": " + m.getName() + "()");
try {
if (GET_KEY_METHOD_NAME.equalsIgnoreCase(m.getName())) {
Object value = m.invoke(I HAVE NO IDEA WHAT TO PUT HERE, "");
System.out.println(value.toString());
}
if (GET_VALUE_METHOD_NAME.equalsIgnoreCase(m.getName())) {
Object value = m.invoke(I HAVE NO IDEA WHAT TO PUT HERE, "");
System.out.println(value.toString());
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
The parameters for the Method.invoke method are always the instance the method is called for, followed by the list of parameters.
Object value = m.invoke(enumConstants[i]);
is most likely what you need.
Also you should add a type parameter to the method:
public <T extends Enum<T>> void myMethod(Class<T> enumType) {
T[] enumConstants = enumType.getEnumConstants();
BTW: Have you considered using a interface containing those methods? This would allow you to access the methods without having to use reflection.
Also take a look at the getDeclaredMethod method and keep in mind that enum constants may instances of a subclass of the enum class, so you should use the methods not containing Declared. Also find the methods for the enum class, not for the individual classes for less lookups:
For example consider the following:
public enum MyEnum implements M1M2Interface {
ONE() {
#Override
public String m1(String s) {
return "1";
}
}, TWO() {
#Override
public int m2(BigInteger i) {
return 2;
}
}
;
}
public interface M1M2Interface {
default String m1(String s) {
return "2";
}
default int m2(BigInteger i) {
return 1;
}
}
public static <T extends Enum<T>> void testEnum(Class<T> enumType) throws NoSuchMethodException {
T[] enumConstants = enumType.getEnumConstants();
Method m1 = enumType.getMethod("m1", String.class);
Method m2 = enumType.getMethod("m2", BigInteger.class);
for (int i = 0; i < enumConstants.length; i++) {
System.out.println(enumConstants[i].name() + ":");
try {
System.out.println(" m1:" + m1.invoke(enumConstants[i], "Hello World"));
System.out.println(" m2:" + m2.invoke(enumConstants[i], (BigInteger) null));
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
ex.printStackTrace();
}
}
}
getDeclaredMethod wouldn't work here, since the methods could be declared/implemented by:
The interface (declared only prior to java 8)
the enum class
the enum constant (if there is no declaration at a "higher level" the method cannot be accessed using EnumName.CONSTANT_NAME.methodName() so it's unlikely to be done...)
Reflection is rarely the correct answer to anything. Consider having your enum classes implement a common interface, like StandardCopyOption and Month do.
If you can't modify the enum classes, and if you're using Java 8, you can pass the getter method as an argument:
public <E extends Enum<E>> E findMatch(Class<E> enumClass,
Function<E, String> nameGetter,
Predicate<String> matcher) {
for (E value : EnumSet.allOf(enumClass)) {
String name = nameGetter.apply(value);
if (matcher.test(name)) {
return value;
}
}
return null;
}
Example usage:
public static enum Season {
SPRING("Spr"),
SUMMER("Sum"),
FALL("Fal"),
WINTER("Win");
private final String abbreviation;
private Season(String abbrev) {
this.abbreviation = abbrev;
}
public getAbbreviation() {
return abbreviation;
}
}
public void doStuff() {
// ...
String abbrToFind = "Sum";
Season match = findMatch(Season.class,
Season::getAbbreviation,
Predicate.isEqual(abbrToFind));
}
If you're using a version older than Java 8, you can still do the same thing, but you'll need to define and implement the interfaces yourself:
public interface Function<A, B> {
B apply(A input);
}
public interface Predicate<T> {
boolean test(T value);
}
public void doStuff() {
// ...
final String abbrToFind = "Sum";
Season match = findMatch(Season.class,
new Function<Season, String>() {
#Override
public String apply(Season season) {
return season.getAbbreviation(),
}
},
new Predicate<String>() {
#Override
public boolean test(String name) {
return Objects.equals(name, abbrToFind);
}
});
}