How can I call a method that is passed on through a parameter in a method in Java 8?
Small example I have a method like that:
void output(String text) {
System.out.println(text)
}
Now I want to pass that method to another class which should call output and set something for text. Is that possible?
The class you want to pass the function to must take a parameter of type Consumer<String>. This class represents a function that takes a parameter of some type (String in this case), and has return type void. A Consumer has a method accept that takes the parameter and calls the function.
You can create you class like this:
class Test {
Test(Consumer<String> consumer) {
consumer.accept("This is a string!");
}
}
Now, when you want to instantiate this class, you need to pass your function to it like this:
Test t = new Test(this::output);
The :: notation is called a method reference. The this (before the colons) means that the method is located in the object you're in. It can be changed to, for example, MyClass::output if it is a static method on MyClass, or myObject::output if it is a method on the object myObject.
Related
I'm experimenting with this code:
interface Callee {
public void foo(Object o);
public void foo(String s);
public void foo(Integer i);
}
class CalleeImpl implements Callee
public void foo(Object o) {
logger.debug("foo(Object o)");
}
public void foo(String s) {
logger.debug("foo(\"" + s + "\")");
}
public void foo(Integer i) {
logger.debug("foo(" + i + ")");
}
}
Callee callee = new CalleeImpl();
Object i = new Integer(12);
Object s = "foobar";
Object o = new Object();
callee.foo(i);
callee.foo(s);
callee.foo(o);
This prints foo(Object o) three times. I expect the method selection to take in consideration the real (not the declared) parameter type. Am I missing something? Is there a way to modify this code so that it'll print foo(12), foo("foobar") and foo(Object o)?
I expect the method selection to take
in consideration the real (not the
declared) parameter type. Am I missing
something?
Yes. Your expectation is wrong. In Java, dynamic method dispatch happens only for the object the method is called on, not for the parameter types of overloaded methods.
Citing the Java Language Specification:
When a method is invoked (§15.12), the
number of actual arguments (and any
explicit type arguments) and the
compile-time types of the arguments
are used, at compile time, to
determine the signature of the method
that will be invoked (§15.12.2). If
the method that is to be invoked is an
instance method, the actual method to
be invoked will be determined at run
time, using dynamic method lookup
(§15.12.4).
As mentioned before overloading resolution is performed at compile time.
Java Puzzlers has a nice example for that:
Puzzle 46: The Case of the Confusing Constructor
This puzzle presents you with two Confusing constructors. The main method invokes a constructor,
but which one? The program's output depends on the answer. What does the program print, or is it
even legal?
public class Confusing {
private Confusing(Object o) {
System.out.println("Object");
}
private Confusing(double[] dArray) {
System.out.println("double array");
}
public static void main(String[] args) {
new Confusing(null);
}
}
Solution 46: Case of the Confusing Constructor
...
Java's overload resolution process operates in two phases. The first phase selects all the methods or constructors that are accessible and applicable. The second phase selects the most specific of the methods or constructors selected in the first phase. One method or constructor is less specific than another if it can accept any parameters passed to the other [JLS 15.12.2.5].
In our program, both constructors are accessible and applicable. The constructor
Confusing(Object) accepts any parameter passed to Confusing(double[]), so
Confusing(Object) is less specific. (Every double array is an Object, but not every Object is a double array.) The most specific constructor is therefore Confusing(double[]), which explains the program's output.
This behavior makes sense if you pass a value of type double[]; it is counterintuitive if you pass null. The key to understanding this puzzle is that the test for which method or constructor is most specific does not use the actual parameters: the parameters appearing in the invocation.
They are used only to determine which overloadings are applicable. Once the compiler determines which overloadings are applicable and accessible, it selects the most specific overloading, using only the formal parameters: the parameters appearing in the declaration.
To invoke the Confusing(Object) constructor with a null parameter, write new
Confusing((Object)null). This ensures that only Confusing(Object) is applicable. More
generally, to force the compiler to select a specific overloading, cast actual parameters to the declared types of the formal parameters.
Ability to dispatch a call to a method based on types of arguments is called multiple dispatch. In Java this is done with Visitor pattern.
However, since you're dealing with Integers and Strings, you cannot easily incorporate this pattern (you just cannot modify these classes). Thus, a giant switch on object run-time will be your weapon of choice.
In Java the method to call (as in which method signature to use) is determined at compile time, so it goes with the compile time type.
The typical pattern for working around this is to check the object type in the method with the Object signature and delegate to the method with a cast.
public void foo(Object o) {
if (o instanceof String) foo((String) o);
if (o instanceof Integer) foo((Integer) o);
logger.debug("foo(Object o)");
}
If you have many types and this is unmanageable, then method overloading is probably not the right approach, rather the public method should just take Object and implement some kind of strategy pattern to delegate the appropriate handling per object type.
I had a similar issue with calling the right constructor of a class called "Parameter" that could take several basic Java types such as String, Integer, Boolean, Long, etc. Given an array of Objects, I want to convert them into an array of my Parameter objects by calling the most-specific constructor for each Object in the input array. I also wanted to define the constructor Parameter(Object o) that would throw an IllegalArgumentException. I of course found this method being invoked for every Object in my array.
The solution I used was to look up the constructor via reflection...
public Parameter[] convertObjectsToParameters(Object[] objArray) {
Parameter[] paramArray = new Parameter[objArray.length];
int i = 0;
for (Object obj : objArray) {
try {
Constructor<Parameter> cons = Parameter.class.getConstructor(obj.getClass());
paramArray[i++] = cons.newInstance(obj);
} catch (Exception e) {
throw new IllegalArgumentException("This method can't handle objects of type: " + obj.getClass(), e);
}
}
return paramArray;
}
No ugly instanceof, switch statements, or visitor pattern required! :)
Java looks at the reference type when trying to determine which method to call. If you want to force your code you choose the 'right' method, you can declare your fields as instances of the specific type:
Integeri = new Integer(12);
String s = "foobar";
Object o = new Object();
You could also cast your params as the type of the param:
callee.foo(i);
callee.foo((String)s);
callee.foo(((Integer)o);
If there is an exact match between the number and types of arguments specified in the method call and the method signature of an overloaded method then that is the method that will be invoked. You are using Object references, so java decides at compile time that for Object param, there is a method which accepts directly Object. So it called that method 3 times.
Groovyc: [Static type checking] - Cannot find matching method io.swagger.client.util.EmUtil#addLobList(java.lang.Object, java.lang.Object). Please check if the declared type is correct and if the method exists.
I am calling this function in a static block in groovy, as shown below:
static {
Arrays.asList(LOBEnum.values()).forEach {lob -> EmUtil.getInstance().addLobList(lob.name(), lob.getLob())}
EmUtil.getInstance().setPrefix("CCB_Reference_Data_")
EmUtil.getInstance().init()
}
This calls a java function, as shown below:
public void addLobList(String lob, String licenseLob) {
lobList.add(lob);
lobLicenseList.add(licenseLob);
}
It looks like lob.name() and lob.getLob() each have a return type of Object. If you want to use the return values of those methods as parameters to your addLobList method, the static type checker needs to make sure those are String instance. You can cast those with (String). Alternatively, you could change the return value of those methods to String.
I am new to java and started working on constructors. I am seeing few examples where constructor is passed as parameter to a Method. Please tell me what happens when a constructor is passed as a parameter to a method..or suggest me some links where can i get enough knowledge about using constructors
Depending on the purpose why do you need to pass the constructor you may consider passing the instance of Supplier instead (JavaDoc - https://docs.oracle.com/javase/8/docs/api/java/util/function/Supplier.html).
For example you have a method which suppose to create an account and fill everything in it. You can make this method to accept Supplier as a parameter:
public Account createNewAccount(Supplier<Account> accountConstructor) {
var account = accountConstructor.get();
account.fillEverything();
return account;
}
And after that pass constructor to this method either using lambda:
createNewAccount(() -> new UserAccount());
Or using method reference:
createNewAccount(UserAccount::new);
Both variants are working.
Constructors can be passed as arugments to methods using a method reference, somewhat like a function pointer in C++.
See: http://www.baeldung.com/java-8-double-colon-operator
This can be a Function type with one argument or a BiFunction type with two arguments, either way its a lambda returning a class of the type it constructs.
Like Turing85 said though I don't think this is what you want. Passing constructors as parameters is a pretty niche use case. If you just want information on constructors,
https://docs.oracle.com/javase/tutorial/java/javaOO/constructors.html
Here is an example class that holds two constructors as instance variables and invokes one of them when the constructItem method is called. The first constructor is stored as a Supplier that returns an object of type S and the second takes a Function that takes type T and returns type S.
public class ConstructorWrapper<T, S> {
private final Supplier<S> construct;
private final Function<T, S> constructFromObject;
public ConstructorWrapper(Supplier<S> constructWithNothing, Function<T, S> constructWithObject) {
this.construct = constructWithNothing;
this.constructFromObject = constructWithObject;
}
public S constructItem(T k) {
if (k != null) return this.construct.get();
else return constructFromObject.apply(k);
}
}
We can use the class like this to wrap creation of ArrayLists from Sets. x is created by invoking the constructor with no parameters and y is created by invoking the constructor with one parameter.
ConstructorWrapper<Set, ArrayList> setToArrayList = new ConstructorWrapper<>(ArrayList::new, ArrayList::new);
ArrayList x = setToArrayList.constructItem(null);
ArrayList y = setToArrayList.constructItem(new HashSet<>());
Or like this to wrap creation of Sets from ArrayLists:
ConstructorWrapper<ArrayList, HashSet> arrayListsToSets = new ConstructorWrapper<>(HashSet::new, HashSet::new);
HashSet x = arrayListsToSets.constructItem(null);
HashSet y = arrayListsToSets.constructItem(new ArrayList<>());
I used raw ArrayLists and Sets because I didn't want to clutter the code with more generics
I'm basically trying to create a static method that will serve as a wrapper for any method I pass and will execute something before and after the actual execution of the method itself. I'd prefer to do it using Java 8 new coding style. So far I have a class that has a static method, but I'm not sure what the parameter type should be so it can take any method with any type of parameter and then execute it. Like i mentioned I want to do some stuff before and after the method executes.
For example: executeAndProcess(anyMethod(anyParam));
Your method can accept a Supplier instance and return its result:
static <T> T executeAndProcess(Supplier<T> s) {
preExecute();
T result = s.get();
postExecute();
return result;
}
Call it like this:
AnyClass result = executeAndProcess(() -> anyMethod(anyParam));
Sometimes we call className.methodName() without creating object for it, I mean without using syntax as className objectName = new constructor() and then call as object.methodName()
When to use className.methodName()?
When to call method using object as object.methodName()?
Explanation of above two cases with example will be appreciated.
What you're referring to is a static method.
Assume that I have this :
public class A {
public static void foo(){
System.out.println("Hooray! I work!");
}
}
You can now do this anywhere else in any other class :
A.foo();
This is because the method is static, which means that it can be called on by the CLASS.
This means that it doesn't require an instance of that class in order for the method to be called.
However, even though it isn't required, you can still do this :
A a = new A();
a.foo();
But since the method foo() is static, instantiating an object A is not required in order to run the foo() method.
First. When you're create at least one static method of a class, you can use this method without creating an instance of class. This is useful, for example, for the creation of methods with independent logic. For example:
public class Checker {
public static Boolean month(int value) {
return (value >= 1 && value <= 12);
}
}
You need check correct value of month many times. But what to do each time to create the object. It is much effective to use a static method.
Second. When you create the object, the object is stored in the memory and you get a link to it. Then the object can be used for example to save at the list.
Method at this object is specific. You can save class data and do specific operation with member of this class. For example:
List<Animals> animalsList = new ArrayList<>();
Animal animal = new Animal("dog");
int legs = animal.getCountLegs(); // specific function for object
animalList.add(animal); //save if you need
// use list of object
For every class, we have a Object called as class object which is YourClass.class object. static methods are invoked based on meta-data on those objects. For instances of a class, methods are invoked on the actual instances. Both static and non-static methods are present on method area.
There is no different between 1 and 2 point, because in during compilation compiler makes ClassName.staticMethod() instead of instance.staticMethod().
Static methods in java belong to the class (not an instance of it). They use no instance variables and will usually take input from the parameters, perform actions on it, then return some result. Instances methods are associated with objects and, as the name implies, can use instance variables.