Trying to understand how to reference Instance functions. I've figured out how to define getters, but setters are giving me trouble. I'm not sure how to write a function for a given method signature and a given base class.
What type is Foo::setBar below?
public class Foo {
private String bar;
public String getBar() {
return bar;
}
public void setBar(String bar) {
this.bar = bar;
}
}
{
//Works great!
Function<Foo, String> func1 = Foo::getBar;
//Compile error ?
Function<Foo, String> func2 = Foo::setBar;
//Compile error ?
Function<Foo, Void, String> func3 = Foo::setBar;
}
Your Function<Foo, String> func2 = Foo::setBar; is a compile error, because public void setBar(String bar) ist not a function from Foo to String, it is actually a function from String to Void.
If you want to pass the setter as method reference, you need a BiConsumer, taking a Foo and a String like
final BiConsumer<Foo, String> setter = Foo::setBar;
Or if you already got an instance of foo, you can simply use this and use a Consumer, e.g.
Foo foo = new Foo();
final Consumer<String> setBar = foo::setBar;
As setBar has a void return type, the matching functional interface single abstract method must have void return type as well. Such functional interfaces are commonly referred as "consumers". In your particular case you need to use BiConsumer which accepts a Foo object and a new bar value:
BiConsumer<Foo, String> func2 = Foo::setBar;
Related
I have been working with java 8 functional interfaces and I noticed something unusual when I started executing below code.
interface Carnivore{
default int calories( List<String> food)
{
System.out.println("=======line ABC ");
return food.size() * 100;
}
int eat(List<String> foods);
}
class Tiger implements Carnivore{
public int eat(List<String> foods)
{
System.out.println("eating "+ foods);
return foods.size();
}
}
public class TestClass {
public static int size(List<String> names){
System.out.println("======line XYZ ");
return names.size()*2;
}
public static void process(List<String> names, Carnivore c){
c.eat(names);
}
public static void main(String[] args) {
List<String> fnames = Arrays.asList("a", "b", "c");
Tiger t = new Tiger();
process(fnames, t::eat);
process(fnames, t::calories);
process(fnames, TestClass::size ); // ----> this is where I am confused.
}
}
As you can see that static method process(List<String> names, Carnivore c) takes object type Carnivore. The method call process(fnames, TestClass::size ) works, and there's no compile time error, how is this possible? I'm not able to comprehend how internally this method call works. I was expecting an error because TestClass is not Carnivore.
The best answer I found: "You can either pass a Carnivore instance explicitly or pass a reference to a method that matches the parameter list of Carnivore's abstract method eat(List<String> foods)"
The part pass a reference to a method that matches the parameter list of abstract method is confusing to me.
Appreciated if experts help me understand what happens when process(fnames, TestClass::size ); is called.
Carnivore is a functional interface having a single abstract method int eat(List<String> foods);.
Therefore, any method that fits the signature of the eat method can be used to implement the interface.
public static int size(List<String> names) is such a method, since it takes a List<String> argument and returns an int. Therefore TestClass::size can be passed as an argument of type Carnivore, which is why process(fnames, TestClass::size); passes compilation.
BTW, Tiger does not have to implement the Carnivore interface for process(fnames, t::eat); to pass compilation, since the public int eat(List<String> foods) method also matches the signature of the functional interface's single abstract method.
This is giving an error:
class Apple(weightInGrams: Float){
fun grow() {
weightInGrams+= 2.0f
}
}
First of all, the equivalent of void (in Java) is Unit (in Kotlin), and the type a function returns goes at the end, so you should use fun grow(): Unit { ... } instead of fun void grow() { ... }. Moreover, you can omit Unit and just write fun grow() { ... } because the compiler knows that your function doesn't return any meaningful value.
Now, I'll try to explain the basics to answer your question and give you some clarity. In Java, the parameters of a constructor are visible only inside that constructor. In Kotlin, the parameters are only visible in initializer blocks and in property initializers, unless you transform them into properties. Let's explain all this with examples.
In Java, we see constructors in classes like this many times:
public class Person {
public final String name;
public final Integer age;
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
}
The parameters are used to initialize the fields of the class Person.
In Kotlin, the equivalent could be:
a) Use the parameters in initializer blocks.
class Person(name: String, age: Int) {
val name: String
val age: Int
init {
this.name = name
this.age = age
}
}
b) Use the parameters in property initializers declared in the class body.
class Person(name: String, age: Int) {
val name = name
val age = age
}
c) Declaring properties and initializing them directly in the primary constructor.
class Person(val name: String, val age: Int)
Therefore, if you write var or val, the parameters of the constructor will be also properties and you will be able to use them in your class like you want to do inside your function grow.
So, your final code should be:
class Apple(var weightInGrams: Float) {
fun grow() {
weightInGrams += 2.0f
}
}
var because you are assigning a value to weightInGrams multiple times.
make your property a class member
class Apple(var weightInGrams: Float){
fun void grow() {
weightInGrams+= 2.0f
}
}
I understand the question was already answered.
If you want to initialize an apple with an initialWeight, you can do it as below. The init block can help initialize the value and the grow function can effectively work on the actual variable without a need to declare the constructor variable as var:
class Apple(initWeight: Float){
var weightInGrams = 0.0f
init {
var weightInGrams = initWeight
}
fun grow() {
weightInGrams+= 2.0f
}
}
fun main(args: Array<String>) {
val a = Apple(10.0f)
a.grow()
println(a.weightInGrams)
};
In Java Method References
ContainingClass::staticMethodName - means that a class can refer the static method (Reference to a Static Method )
containingObject::instanceMethodName - means that a class object is created first and then that object is used to refer the instanceMethod .
My doubt is
ContainingType::methodName - what does the ContainingType mean ?
Is ContainingType a predefined class in java like String or something else ?
Java Language Specification, §4.3. Reference Types and Values:
There are four kinds of reference types: class types (§8.1), interface types (§9.1), type variables (§4.4), and array types (§10.1).
Array type don't have static methods, so that doesn't apply to static method reference, but you can do the other 3:
class MyClass {
static void doIt() {/*doing it*/}
}
interface MyInterface {
static void doIt() {/*doing it*/}
}
class Test<T extends MyClass> {
void test() {
Runnable m1 = MyClass::doIt; // class type
Runnable m2 = MyInterface::doIt; // interface type
Runnable m3 = T::doIt; // type variable
}
}
Now that link is provided in a comment, it says:
Reference to a static method
ContainingClass::staticMethodName
Reference to an instance method of a particular object
containingObject::instanceMethodName
Reference to an instance method of an arbitrary object of a particular type
ContainingType::methodName
Reference to a constructor
ClassName::new
Here, again, ContainingType refers to any of the 3 reference types mentioned above: Class, Interface, and Type Variable.
You can then make a method reference for any instance method of such a type.
class MyClass {
void doIt() {/*doing it*/}
}
interface MyInterface {
void doIt();
}
class Test<T extends MyClass> {
void test() {
Consumer<MyClass> m1 = MyClass::doIt;
Consumer<MyInterface> m2 = MyInterface::doIt;
Consumer<T> m3 = T::doIt;
}
}
https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html
In the document you gave,there is a example of the ContainingType:
String[] stringArray = { "Barbara", "James", "Mary", "John",
"Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, String::compareToIgnoreCase);
and explains:
The equivalent lambda expression for the method reference String::compareToIgnoreCase would have the formal parameter list (String a, String b), where a and b are arbitrary names used to better describe this example. The method reference would invoke the method a.compareToIgnoreCase(b).
I think,the element of the stringArray dosen't have a name (eg: String s1 = "Barbara"),so you can't refer it by containingObject::instanceMethodName(eg:s1::compareToIgnoreCase). That's why it uses ContainingType.
I think your ContainingType::methodName is a general/common form of the 2 forms above...
Think about the below code. You can replace the <methodReference> width
InterfaceA::method (for ContainingType::methodName)
ClassA::method (for also ContainingType::methodName)
ClassB::instanceMethod (for ContainingObject::instanceMethodName) or
ClassB::staticMethod (for ContainingClass::staticMethodName)
to demonstrate the mentioned cases:
public class App {
interface InterfaceA {
String method();
}
static class ClassA implements InterfaceA {
public String method() {
return "ContainingType::methodName";
}
}
static class ClassB extends ClassA {
public String instanceMethod() {
return "ContainingObject::instanceMethodName";
}
public static String staticMethod(ClassB classB) {
return "ContainingClass::staticMethodName";
}
}
public static void main(String[] args) {
System.out.println(((Function<ClassB, String>) <methodReference>).apply(new ClassB()));
}
}
public interface TestServiceIface {
default String test(String str, int flag) {
return str;
}
}
interface like this,if implements the interface, and have an instance ,how can I call default method? if use reflection, how to do?
And I only have this interface,no Impl class and no Impl instance.how to call the default method?
Or via a MethodHandle, but do notice that you actually need an implementation class of that interface:
static class Impl implements TestServiceIface {
}
And the usage:
MethodType methodType = MethodType.methodType(String.class, String.class, int.class);
MethodHandle handle = MethodHandles.lookup().findVirtual(TestServiceIface.class, "test", methodType);
String result = (String) handle.invoke(new Impl(), "test", 12);
System.out.println(result); // test
You can access interface default methods by reflection as below:
Class<TestServiceIface> type = TestServiceIface.class;
Method defaultMethod = type.getMethod("test", String.class, int.class);
String result = (String) defaultMethod.invoke(instance, "foo", 0);
However, if the subclass override the default method, then the overrided method will be called, which means interface default method also supports polymorphism.
I am looking for an way to overwrite xor on an groovy script.
I've created a base class for my script where a Object is defined. This object already has a method public Object xor(String var) which works like myobject^"foo". What I want is way to access this method like myobject^foo where foo handled like a normal String.
as i understand you want to do somehow that
(myobject^"foo") == (myobject^foo)
so, in your script you can redefine method getProperty() so in your script access to foo property will return "foo" string..
class A{
public Object xor(Object o){
println "xor $o"
return o
}
}
public getProperty(String key){
if(key in ['out'])return super.getProperty(key) //skip standard properties
return key
}
def myobject=new A()
assert (myobject^foo) == (myobject^"foo")
but i don't see any benefits :)
Based on your answer #daggett I found a method which handles missing properties:
public abstract class MyBaseScript extends Script implements GroovyObject {
protected class A {
public Object xor(String var) {
//do fancy stuff
return var;
}
}
protected A foo = new A();
//method which handles missing properties
public Object propertyMissing(String name) {
return name;
}
}
How do I start my scripts:
Binding binding = new Binding();
// passing parameters
binding.setVariable("arg0", arg0);
binding.setVariable("args", arg1);
// Compiler Config
CompilerConfiguration cc = new CompilerConfiguration();
ImportCustomizer ic = new ImportCustomizer();
// add some imports for e.g.
ic.addImports("java.awt.Color", "java.util.Calendar",...);
cc.addCompilationCustomizers(ic);
// set BaseClass
cc.setScriptBaseClass("de.MyBaseScript");
// execute script
GroovyClassLoader loader = new GroovyClassLoader();
shell = new GroovyShell(loader, binding, cc);
Script gscript = shell.parse(groovyScriptAsAFile);
Object o = gscript.run();