Passing and enforcing member function in java

I am trying to create a work queue class (FooQueue) that has:

  • a set of functions that do the job (do *). Each of them accepts one parameter having the same type (FooItem).
  • function 'add', which takes 2 parameters: one of the above functions and FooItem. Most importantly, the add function should only accept a member function of the FooQueue class, and not a member function of another class with a similar signature

The code compiles when the do function is static, but not when the function is non-static, although in accordance with this the definition of an instance function member.

What needs to be changed to compile / run?

public class App { public static void main( String[] args ) { FooQueue q = new FooQueue(); q.add( FooQueue::dos, new FooItem() ); // this compiles q.add( q::do1, new FooItem() ); // this does not: // does not consider q::do1 'delegate' // as taking 2 parameters, // with q being the first one FooQueue q2 = new FooQueue2(); q.add( FooQueue2::dos, new FooItem() ); // want this to give compiler error q.add( FooQueue2::do1, new FooItem() ); // want this to give compiler error } } public class FooQueue { public static void dos( FooQueue q, FooItem item ) { System.out.println( "FooQueue:sdo" ); } public void do1( FooItem item ) { System.out.println( "FooQueue:do1" ); } public void add( java.util.function.BiConsumer<FooQueue,FooItem> func, FooItem wi ) { System.out.println( "FooQueue:addWorkItem2" ); func.accept( this, wi ); } } public class FooItem { } public class FooQueue2 { public static void dos( FooQueue2 q2, FooItem item ) { System.out.println( "FooQueue2:sdo" ); } public void do1( FooItem item ) { System.out.println( "FooQueue2:do1" ); } } 
+5
source share
1 answer

This does not apply to the static / non-stationary method, nor to generics, but only to the BiConsumer definition.

BiConsumer requires two parameters, so you need a lambda that requires two parameters and does not return any.

To fix this, use the instance method description :

 FooQueue q = new FooQueue(); q.add(FooQueue::do1, new FooItem()); 

Do not confuse it with a reference to a static method. FooQueue::do1 is the syntax sugar for lambda:

 (qInstance, item) -> qInstance.do1(item)); 

This approach only accepts methods from FooQueue .

Note that q:do1 not compatible with BiConsumer , as it converts to:

 (item) -> q.do1(item) 

Read more about Instance Method Link


Full example with different classes

 public class App { public static void main(String[] args) { FooQueue q = new FooQueue(); FooQueue2 q2 = new FooQueue2(); q.add(FooQueue::do1, new FooItem()); // Equals to: q.add((qInstance, item) -> qInstance.do1(item), new FooItem()); // q.add(FooQueue2::do1, new FooItem()); // not compile } } class FooQueue { void do1(FooItem item) { System.out.println("FooQueue:do1"); } void add(BiConsumer<FooQueue, FooItem> func, FooItem wi) { System.out.println("FooQueue:addWorkItem"); func.accept(this, wi); } } // class that pretends to be FooQueue class FooQueue2 { void do1(FooItem item) { System.out.println("FooQueue2:do1"); } } class FooItem { } 
+7
source

Source: https://habr.com/ru/post/1265054/


All Articles