Functions and development as such, has to be fun

In last post I was talking about how to break free from if statements using JavaScript. But is it possible to do something similar in other languages, like C# and Java? I did put on my hiking shoes and went into venture to find it out.

Java

I created simple command line application, which prints out message.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import java.util.function.Function;

public class Main {
    public static void main(String[] args) {
        //Function<T,R> where T input type and R output
        Function<String, String> funFunction= new Function<String, String>() {
            @Override
            public String apply(String name) {
                return name.concat(", is having fun!");
            }
        };

        String result = funFunction.apply("Kristaps");
        System.out.println(result);
    }
}
//Output: Kristaps, is having fun!

A lot of code for small task, but it can be fixed with lambda expresion

1
2
3
4
5
6
public static void main(String[] args) {
    Function<String, String> funFunction = s -> s.concat(", is having fun!");

    String result = funFunction.apply("Kristaps");
    System.out.println(result);
}

Final touch

1
2
3
4
public static void main(String[] args) {
    Function<String, String> funFunction = s -> s.concat(", is having fun!");
    System.out.println(funFunction.apply("Kristaps"));
}

Add IF statements in code base

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public static void main(String[] args) {
    Main mainApp = new Main();
    mainApp.thePerson(0, "Kristaps");
    mainApp.thePerson(42, "Kristaps");
    //Output
    //Kristaps, is having fun!
    //Kristaps, has left the building!
}

public void thePerson(int state, String name) {
    Function<String, String> funFunction = s -> s.concat(", is having fun!");
    Function<String, String> sadFunction = s -> s.concat(", is sad!");
    Function<String, String> elseFunction = s -> s.concat(", has left the building!");

    if (state == 0) {
        System.out.println(funFunction.apply(name));
    } else if (state == 1) {
        System.out.println(sadFunction.apply(name));
    } else {
        System.out.println(elseFunction.apply(name));
    }
}

Refactor the code and remove the IFs

1
2
3
4
5
6
7
8
9
10
11
12
public void thePerson(int state, String name) {
    Map<Integer, Function<String,String>> functions = new HashMap<>();
    functions.put(0,  s -> s.concat(", is having fun!"));
    functions.put(1,  s -> s.concat(", is sad!"));
    functions.put(-1,  s -> s.concat(", has left the building!"));

    if (functions.containsKey(state)) {
        System.out.println(functions.get(state).apply(name));
    } else {
        System.out.println(functions.get(-1).apply(name));
    }
}

As I have to check the key existence in function map, I have one more IF left. Remove it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static void main(String[] args) {
    Main mainApp = new Main();
    String messageOne = mainApp.thePerson(0, "Kristaps");
    String messageTwo = mainApp.thePerson(42, "Kristaps");

    System.out.println(messageOne);
    System.out.println(messageTwo);
}

public String thePerson(int state, String name) {
    Map<Integer, Function<String,String>> functions = new HashMap<>();
    functions.put(0,  s -> s.concat(", is having fun!"));
    functions.put(1,  s -> s.concat(", is sad!"));
    functions.put(-1,  s -> s.concat(", has left the building!"));

    return Optional.ofNullable(functions.get(state)).orElse(functions.get(-1)).apply(name);
}

No more IF statements, which means, less Unit testing for each IF leaf, I would like to add some last Enterprise touch 😉

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;

class MessageHandler {
    private final Map<Integer, Function<String, String>> handlers = new HashMap<>();

    public void register(int state, Function<String, String> handler) {
        if (handlers.containsKey(state)) {
            return;
        }
        handlers.put(state, handler);
    }

    public String raise(int state, String name) {
        return Optional.ofNullable(handlers.get(state)).orElse(handlers.get(-1)).apply(name);
    }
}

public class Main extends MessageHandler {

    public Main() {
        register(0, name -> havingFun(name));
        register(1, name -> isSad(name));
        register(-1, name -> orElse(name));
    }

    public static void main(String[] args) {
        Main mainApp = new Main();

        System.out.println(mainApp.raise(0, "Kristaps"));
        System.out.println(mainApp.raise(42, "Kristaps"));
    }

    String havingFun(String who) {
        return who.concat(", is having fun!");
    }

    String isSad(String who) {
        return who.concat(", is sad!");
    }

    String orElse(String who) {
        return who.concat(", has left the building!");
    }
}

I did create a class MessageHandler and extended the Main calss with it. MessageHandler contains two methods, register and raise. When application starts, it registers the handlers, when application executes, it raises handler which is needed by that time. I did define methods inside Main class and registered them as a handlers, so that I can actually test the methods.

As the method footprint is equal to

1
Function<String, String>

it can be registered as register(0, mainApp::havingFun) without using any lambda at all, but then handler registration has be brought down to the main() static method.

Now add new handlers, don’t add IFs.

C#

The same example, but with different syntax. And for some reason Microsoft trimmed the name Function to Func :).

1
2
3
4
5
6
7
8
9
10
11
12
13
class Program
{
    static void Main(string[] args)
    {
        Func<string, string> myFunction = new Func<string, string>(s =>
        {
            return s + ", is having fun";
        });

        var result = myFunction("Kristaps");
        Console.WriteLine(result);
    }
}

Removing the noise

1
2
3
4
5
static void Main(string[] args)
{
    Func<string, string> myFunction = s => s + ", is having fun";
    Console.WriteLine(myFunction("Kristaps"));
}

I will skip to the final result, with enterprise touch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
class MessageHandler
{
    private readonly Dictionary<int, Func<string, string>> handlers = new Dictionary<int, Func<string, string>>();

    public void Register(int state, Func<string, string> handler)
    {
        if (handlers.ContainsKey(state))
        {
            return;
        }
        handlers.Add(state, handler);
    }

    public string raise(int state, string name)
    {
        return handlers.ContainsKey(state) ? handlers[state](name) : handlers[-1](name);
    }
}

class Program: MessageHandler
{

    public Program()
    {
        Register(-1, OrElse);
        Register(0, HavingFun);
        Register(1, IsSad);
    }

    static void Main(string[] args)
    {
        var mainApp = new Program();
        Console.WriteLine(mainApp.raise(0, "Kristaps"));
        Console.WriteLine(mainApp.raise(42, "Kristaps"));
    }

    private string HavingFun(string who)
    {
        return who + ", is having fun";
    }

    private string IsSad(string who)
    {
        return who + ", is sad";
    }

    private string OrElse(string who)
    {
        return who + ", has left the building";
    }
}

And I got almost the same code as in Java 🙂 what a surprise. In my holy opinion, both languages are powerful and you are blessed if you have opportunity to work with one of them.

Java reference for Functions
Java reference for Optional
C# reference for Func

Leave a Reply

Your email address will not be published. Required fields are marked *