I've just started working with Java 8 and I'm struggling with this code snippet:
paramsValues[idx++] = new ReplyMessage<JsonObject>() {
#Override
public void reply(JsonObject reply) {
message.reply(reply);
}
};
How to convert this to Lambda style?
If ReplyMessage is a functional interface, you could do
paramsValues[idx++] = reply -> message.reply(reply);
Here's a full example with stub implementations of the other classes in your question:
// Stub classes
class JsonObject { }
#FunctionalInterface
interface ReplyMessage<T> {
void reply(T jo);
}
class LambdaDemo {
public static void main(String args[]) {
// Dummy variables
ReplyMessage<JsonObject> message = new ReplyMessage<JsonObject>() {
public void reply(JsonObject jo) {}
};
ReplyMessage[] paramsValues = new ReplyMessage[5];
int idx = 0;
// Your code, lambdafied
paramsValues[idx++] = reply -> message.reply(reply);
// Or,
// paramsValues[idx++] = message::reply;
// But then you could perhaps do with just ...
// paramsValues[idx++] = message;
}
}
Lambda expressions are only possible with Functional Interfaces (Interfaces with only one method, such as Runnable or ActionEvent)
If ReplyMessage is a functional interface, you can do:
paramsValues[idx++] = reply -> message.reply(reply);
Lambda expressions are formed in this pattern: parameters that the method should take, then -> then the method body
Here is the code of how ReplyMessage interface should look like:
#FunctionalInterface
interface ReplyMessage<T> {
void reply(T jo);
}
For more information, consider reading this.
paramValues[idx++] = reply -> message.reply(reply);
Or
paramValues[idx++] = reply -> {
return message.reply(reply);
}
It will work as long as ReplyMessage<JsonObject> is functional interface and paramValues is of type ReplyMessage<JsonObject>.
Related
My program requires that I accept a user input and, based on this input, a method is to be carried out. My basic thoughts are described well by the following question/answer:
How to call a method stored in a HashMap? (Java)
To do this, I have created an array of lambda expressions:
public final Runnable[] userCommandMethods = {
() -> userCommand1(),
() -> userCommand2(),
};
And an array of keys:
public final String[] userCommandKeys = {
commandKey1,
commandKey2,
};
Which are joined to create a HashMap using the following method:
public Map<String, Runnable> mapArrays (String[] array1, Runnable[] array2) {
Map<String, Runnable> mappedArrays = new HashMap<String, Runnable>();
for (int i = 0; i < array1.length; i ++) {
mappedArrays.put(array1[i], array2[i]);
}
return mappedArrays;
}
When I attempt to run a method by using myHashMap.get(userInput).run(); it works perfectly, provided none of the methods in userCommandMethods require input parameters.
My question:
How would I pass an input parameter (specifically a Hash Map) into the methods contained within userCommandMethods?
When the userCommand1() method takes an input parameter, but the lambda expression does not, I get the following error:
The method userCommand1(Map<String, String>) in the type ProgramCommands is not applicable for the arguments ()
However, when I do pass a parameter to the method, it states that it cannot be resolved to a variable.
Edit: to elaborate:
When the userCommand1() method takes no arguments:
public void userCommand1 () {
// Do some stuff
}
It works perfectly fine. However, I am unsure how to use the lambda expressions if the method does take an input parameter:
public void userCommand1 (Map<String, String> myMap) {
// Do some stuff
}
You just need to choose another functional interface (not Runnable).
For example, if your methods all take a String parameter, you should use Consumer<String>. If they take a String and an int, then you should use BiConsumer<String, Integer>. If your methods need more than 2 parameters, you need to create your own functional interface. For an example, see my answer here.
// use a list instead of an array, because arrays don't work well with generic types
public final List<Consumer<String>> userCommandMethods = List.of(
x -> userCommand1(x),
x -> userCommand2() // it's fine if the method takes fewer parameters
);
Instead of run, you would call accept, which is what Consumer and BiConsumer's single abstraction method is called.
Note that you can also use the method reference syntax. If userCommand1 is static, x -> userCommand1(x) can be rewritten as SomeClass::userCommand1 where SomeClass is the enclosing class of userCommand1. If userCommand1 is non static, it can be rewritten as this::userCommand1.
You don't need to build the map from two arrays. You can use ofEntries and entry to write the entries inline.
private final Map<String, Consumer<String>> someMap = Map.ofEntries(
Map.entry("foo", SomeClass::userCommand1),
Map.entry("bar", SomeClass::userCommand2),
Map.entry("baz", SomeClass::userCommand3),
// and so on
)
You are using Runnable interface that takes no argument on input:
#FunctionalInterface
public interface Runnable {
public abstract void run();
}
Instead, you can define your custom interface and consume it.
As a simple example:
#FunctionalInterface
public interface RunnableWithArg {
void apply(String t) throws RuntimeException;
}
And implementation may look like:
public class RunnableTest {
//also fine:
//public final RunnableWithArg[] userCommandMethods = { t -> this.userCommand1(t), t -> this.userCommand2(t) };
public final RunnableWithArg[] userCommandMethods = { this::userCommand1, this::userCommand2 };
public String commandKey1 = "commandKey1";
public String commandKey2 = "commandKey2";
public final String[] userCommandKeys = { commandKey1, commandKey2, };
public Map<String, RunnableWithArg> mapArrays(String[] array1, RunnableWithArg[] array2) {
Map<String, RunnableWithArg> mappedArrays = new HashMap<>();
for (int i = 0; i < array1.length; i++) {
mappedArrays.put(array1[i], array2[i]);
}
return mappedArrays;
}
public void userCommand1(String data) {
System.out.println("userCommand1 called with " + data);
}
public void userCommand2(String data) {
System.out.println("userCommand2 called with " + data);
}
public void test()
{
var fncMap = mapArrays(userCommandKeys, userCommandMethods);
for(String key: fncMap.keySet())
{
var fnc = fncMap.get(key);
fnc.apply(key);
}
}
}
And of course you can also define some generic types of "#FunctionalInterface" like this, so you can use it for both taking input and returning some output of generic types:
#FunctionalInterface
public interface AbcFunction<T, R> {
R apply(T t) throws AbcException;
static <T> Function<T, T> identity() {
return t -> t;
}
}
Is this something you are thinking of?
interface Command<T> {
public void run(T arg);
}
class SayHelloCommand implements Command<String>{
public void run(String name){
System.out.println("hello " + name);
}
}
class CountCommand implements Command<Integer>{
public void run(Integer limit){
for(int i=0; i<=limit; i++)
System.out.println(i);
}
}
public class Main{
public static void main(String[] args) {
Command[] commands = new Command[3];
commands[0] = new SayHelloCommand();
commands[1] = new CountCommand();
commands[0].run("Joe");
commands[1].run(5);
}
}
I am trying to wrap my head around generic and functions... what I am trying to achieve: Passing function name as a string to get it executed:
I want to do Wrapper.useFunction("eleven") or Wrapper.useFunction("ten")
public class Wrapper<T> {
public F useFunction(Function<F, F> function) {
return function.apply(F);
}
Function<F, String> ten = s -> "10";
Function<F, String> eleven = s -> "11";
}
But this code not even close to compiling. Maybe it doesn't make any sense. Any suggestions?
If you have a finite set of functions which you would like to be able to call I would recommend building a Map which maps Strings to instances of Runnable (or similar functional interfaces). Your useFunction method may then look up the function implementation in the Map and call it if it exists.
Example:
public class SomeClass {
private final Map<String, Runnable> methods = new HashMap<>();
{
methods.put("helloworld", () -> {
System.out.println("Hello World!");
});
methods.put("test", () -> {
System.out.println("test!");
});
methods.put("doStuff", () -> {
System.out.println("doStuff!");
});
}
public void perform(String code) {
methods.getOrDefault(code,
() -> {
System.err.println("No such Method: "+code);
})
.run();
}
}
If you want to call arbitrary methods you should probably use Reflection as stated by others.
This question already has answers here:
What is the equivalent for java interfaces or objective c protocols in swift?
(2 answers)
Closed 6 years ago.
EDIT: What is different between What is the equivalent for java interfaces or objective c protocols in swift? and this question?
After I read that topic, I thought It was an option to use a class to extend the protocol, and I tried to create the protocol itself with no success, but as Duncan C. said it is not possible to initialise a protocol type directly and I have to extend it with another class.
My Problem: I have a class in Java, I hold an array of interfaces, that way I can loop through the array and call the doWork() function until one of them returns true. I want to achieve the same functionality in Swift.
My java class:
class MyClass{
//create a variable that holds all of my engines
private MyEngine[] myEngines = new MyEngine[]{
new MyEngine(){
#Override
public boolean doWork(){
return doWork1();
}
},
new MyEngine(){
#Override
public boolean doWork(){
return doWork2();
}
},
new MyEngine(){
#Override
public boolean doWork(){
return doWork3();
}
}
}
//loop through all engines until one of them succeed
public boolean doWorkUntilSuccess(){
for(int i = 0; i < myEngines.length; i++){
if(myEngines[i].doWork())
return true;
}
return false;
}
private boolean doWork1(){
//code
return result;
}
private boolean doWork2(){
//code
return result;
}
private boolean doWork3(){
//code
return result;
}
interface MyEngine{
boolean doWork();
}
}
The Swift equivalent to an interface is a Protocol, as Connor says in his answer.
Again, borrowing from Connor's answer:
protocol MyEngine {
func doWork() -> Bool
}
You can't instantiate objects of type MyEngine directly. Instead you need to define one or more objects that conform to the protocol:
class Obj1: MyEngine {
func doWork() -> Bool {
print("in Obj1 doWork()")
return true
}
}
class Obj2: MyEngine {
func doWork() -> Bool {
print("in Obj2 doWork()")
return true
}
}
You can then define an array of objects that conform to the protocol:
var objArray = [MyEngine]()
Then populate the array:
objArray.append(Obj1())
objArray.append(Obj2())
objArray.append(Obj2())
objArray.append(Obj1())
You can then say
objArray.forEach{$0.doWork()}
What you're looking for is a protocol.
protocol MyEngine {
func doWork() -> Bool
}
Classes can then implement the protocol. However, there is no equivalent (to my knowledge) of saying new MyEngine(). You need to declare a class or struct that implements the protocol.
You can put needed functions into array like that:
var firstFunction = {
print("1")
}
var secondFunction = {
print("2")
}
let functions: [() -> ()] = [firstFunction, secondFunction]
for function in functions {
function()
}
Log output:
1
2
The
Java interface equivalent in Swift
is a protocol: The Swift Programming Language (Swift 3.0.1): Protocols.
Your MyEngine interface would look like this:
protocol MyEngine {
func doWork() -> Bool
}
Though for the use case shown, you would probably just use a closure. Like so:
class WorkToDo {
typealias WorkerFunc = () -> ()
let workStuff : [ WorkerFunc ] = [
{ ... do work 1 ... },
{ ... do work 2 ... },
{ ... do work 3 ... }
]
func doAllWork() {
for work in workStuff {
work()
}
}
}
Is there a way to determine whether a given Java lambda object is a method reference or a "CallSite-specific" lambda:
boolean isMethodReference(Object lambda)
Positive example:
assertTrue(isMethodReference(Object::toString));
Negative example with "CallSite-specific" lambda:
long valueFromCallSite = System.currentTimeMillis();
Consumer<Object> lambda = o -> {
if (valueFromCallSite % 2 == 0) {
o.toString();
} else {
o.hashCode();
}
};
assertFalse(isMethodReference(lambda));
A heuristic approach for isMethodReference(lambda) was proposed in "Determine if a lambda expression is stateless or stateful in Java":
boolean isMethodReference(Object lambda) {
return lambda.getClass().getDeclaredFields().length == 0;
}
It’s only a heuristic because it relies on unspecified behavior and thus is JDK implementation-specific and even might break in a future version.
It is possible to determine if a Java method reference is equivalent to another method reference. Assuming we have an interface User:
public interface User {
String firstName();
}
then we can do this:
public class Main {
public static void main(String[] args) {
print(User::firstName);
print(u -> u.firstName());
}
public interface SerializableFunction<T, R> extends Serializable, Function<T, R> {
}
private static void print(SerializableFunction<User, String> function) {
System.out.println("function = " + function);
if (Arrays.equals(serialize(function), serialize(User::firstName))) {
System.out.println("which is the method reference User::firstName");
}
}
private static byte[] serialize(SerializableFunction<User, String> function) {
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream)) {
objectOutputStream.writeObject(function);
return byteArrayOutputStream.toByteArray();
} catch (IOException e) {
return new byte[0];
}
}
}
This will print something like this:
function = software.chronicle.refactor.demo.serialization.Main$$Lambda$25/0x0000000800c02658#65ab7765
which is the method reference User::firstName
function = software.chronicle.refactor.demo.serialization.Main$$Lambda$33/0x0000000800c02b08#6659c656
So, it is actually possible to check if a lambda is a specific method reference.
Consider the following Scala code:
package scala_java
object MyScala {
def setFunc(func: Int => String) {
func(10)
}
}
Now in Java, I would have liked to use MyScala as:
package scala_java;
public class MyJava {
public static void main(String [] args) {
MyScala.setFunc(myFunc); // This line gives an error
}
public static String myFunc(int someInt) {
return String.valueOf(someInt);
}
}
However, the above does not work (as expected since Java does not allow functional programming). What is the easiest workaround to pass a function in Java? I would like a generic solution that works with functions having arbitrary number of parameters.
EDIT: Does Java 8 have any better syntax than the classic solutions discussed below?
In the scala.runtime package, there are abstract classes named AbstractFunction1 and so on for other arities. To use them from Java you only need to override apply, like this:
Function1<Integer, String> f = new AbstractFunction1<Integer, String>() {
public String apply(Integer someInt) {
return myFunc(someInt);
}
};
If you're on Java 8 and want to use Java 8 lambda syntax for this, check out https://github.com/scala/scala-java8-compat.
You have to manually instantiate a Function1 in Java. Something like:
final Function1<Integer, String> f = new Function1<Integer, String>() {
public int $tag() {
return Function1$class.$tag(this);
}
public <A> Function1<A, String> compose(Function1<A, Integer> f) {
return Function1$class.compose(this, f);
}
public String apply(Integer someInt) {
return myFunc(someInt);
}
};
MyScala.setFunc(f);
This is taken from Daniel Spiewak’s “Interop Between Java and Scala” article.
The easiest way for me is to defined a java interface like:
public interface JFunction<A,B> {
public B compute( A a );
}
Then modify your scala code, overloading setFunc to accept also JFunction objects such as:
object MyScala {
// API for scala
def setFunc(func: Int => String) {
func(10)
}
// API for java
def setFunc(jFunc: JFunction[Int,String]) {
setFunc( (i:Int) => jFunc.compute(i) )
}
}
You will naturally use the first definition from scala, but still be able to use the second one from java:
public class MyJava {
public static void main(String [] args) {
MyScala.setFunc(myFunc); // This line gives an error
}
public static final JFunction<Integer,String> myFunc =
new JFunction<Integer,String>() {
public String compute( Integer a ) {
return String.valueOf(a);
}
};
}
Here's my attempt at a solution, a little library: https://github.com/eirslett/sc8
You wrap your Java 8 lambda in F(...) and then it's converted to a Scala function.