2

So I've searched through several websites and others questions on this, and none seem to have the answer that works for me. I have code that works, and my programming mentor suggested I change the chained if/else if to using a lambda table instead. I asked about using something of a hash table, and he said using a hash for only 9 items (the real program has 9 if/else statements) would be a waste.

I will post the working code using both the if/else if and the hash table, keeping it limited to 3 items to keep the code short and sweet.

Here is the code for if/else if...

public class testLambda {
    String[] numArray = {"One", "Two", "Three"};

    testLambda(String num){
        if (num.equals(numArray[0])){
            printStringOne();
        } else if (num.equals(numArray[1])){
            printStringTwo();
        } else if (num.equals(numArray[2])){
            printStringThree();
        }
    }

    private void printStringOne(){
        System.out.println("1");
    }

    private void printStringTwo(){
        System.out.println("2");
    }

    private void printStringThree(){
        System.out.println("3");
    }

    public static void main(String[] args) {
        new testLambda("One");
        new testLambda("Three");
        new testLambda("Two");
    }
}

results in system printing...

1
3
2

Here is the code for a hash table

import java.util.HashMap;
import java.util.Map;

public class testLambda {
    String[] numArray = {"One", "Two", "Three"};

    testLambda(String num){
        Map<String, Runnable> printNumber = new HashMap<>();

        printNumber.put(numArray[0], () -> printStringOne());
        printNumber.put(numArray[1], () -> printStringTwo());
        printNumber.put(numArray[2], () -> printStringThree());

        printNumber.get(num).run();
    }

    private void printStringOne(){
        System.out.println("1");
    }

    private void printStringTwo(){
        System.out.println("2");
    }

    private void printStringThree(){
        System.out.println("3");
    }

    public static void main(String[] args) {
        new testLambda("Three");
        new testLambda("One");
        new testLambda("Two");
    }
}

results in system printing...

3
1
2

and now... the lambda. From what I have read, an interface is required. Keep in mind, I can't use extends, because my application is already extending a different class(java doesn't support multiple inheritance) Here is what I have conjured so far (not working):

public class testLambda {
    String[] numArray = {"One", "Two", "Three"};

    public interface PrintNumber{
        void printNumber();
    }

    testLambda(String num){
        PrintNumber[] printNumbers = new PrintNumber[]{
                new PrintNumber() {public void printNumber(){printStringOne();}},
                new PrintNumber() {public void printNumber(){printStringTwo();}},
                new PrintNumber() {public void printNumber(){printStringThree();}}
        };

        for (int n = 0; n < numArray.length; n++){
            if (num.equals(numArray[n])){
                printNumbers[n];
            }
        }
    }

    private void printStringOne(){
        System.out.println("1");
    }

    private void printStringTwo(){
        System.out.println("2");
    }

    private void printStringThree(){
        System.out.println("3");
    }

    public static void main(String[] args) {
        new testLambda("Three");
        new testLambda("Two");
        new testLambda("One");
    }
}

This results in a compile error. Can anyone tell me what I'm doing wrong? I'm really new to the lambda algorithm.

Fiddle Freak
  • 1,923
  • 5
  • 43
  • 83
  • 2
    Note that, you can just write `new PrintNumber[] { () -> printStringOne(), () -> printStringTwo(), () -> printStringThree()}` (same as you did with your `Map<.., Runnable>`). You do not necessarily need a new interface. Now I don't know why it should get simpler with lambdas (or a lambda table?) and I do not know why it should be a waste to use a `Map` in this case. I wouldn't place a `Runnable` in there, but that's another thing. I would rather ask your mentor, what's the point of using a lambda table or why he/she suggested it. – Roland May 15 '17 at 10:47
  • You're right! This is much cleaner. Thanks a bunch :) Also, when I meet with him tomorrow, i'll ask him your question and get his response. Also, it looks like the interface is still required for creating the object array `CreateCharacter[] createCharacters = new CreateCharacter[]{...};`. – Fiddle Freak May 15 '17 at 11:02
  • Not necessarily. You could also just use `Runnable[]`. However using your own interface makes sense to make the purpose (and code) clearer. – Roland May 15 '17 at 11:06
  • Oh yeah, thanks :) but how would I then call the index of the Runnable array? `printNumbers[n].printNumber();` as `printNumber()` is red out. – Fiddle Freak May 15 '17 at 11:10
  • nevermind, I found it `printNumbers[n].run();` Thanks again :) – Fiddle Freak May 15 '17 at 11:13
  • I asked my mentor about your question, he said a hash map has a space set aside where the value of using a hash really doesn't come into play until you see a lot of items being used. But he said it's fine and likes the hash idea better, however `Runnable` has an issue here where it creates a separate thread causing a race condition. This causes a problem in the constructor because you don't know which thread is going to win first. Which brings me to my next question > http://stackoverflow.com/questions/43992323/how-to-handle-race-condition-with-runnable-using-separate-thread-for-lambda – Fiddle Freak May 16 '17 at 04:08
  • This is a very strange usage of `Runnable` and lambdas. I cannot think of any useful reason to do anything of this sort. Anyone who reads to learn about functional programming in Java, please take this into account! It does show some of the things to remember when using HashMaps though. – RudolphEst May 18 '17 at 18:44

1 Answers1

3

The compilation error is due to this statement:

numArray[n];

which is not a valid statement. What you wanted was this:

    for (int n = 0; n < numArray.length; n++){
        if (num.equals(numArray[n])){
            createCharacters[n].printNumber();
        }
    }

However, this relies on keeping two separate arrays in sync, and is therefore error prone. I suggest using a single HashMap for everything, and getting rid of your original numArray in favour of the HashMap:

public class testLambda {
    Map<String, Runnable> printNumber = new HashMap<>();
    static {
        printNumber.put("One", () -> printStringOne());
        printNumber.put("Two", () -> printStringTwo());
        printNumber.put("Three", () -> printStringThree());
    }

    testLambda(String num){
        printNumber.get(num).run();  // Add some checking here for robustness
    }

By the way, what you call a "lambda table" doesn't necessarily mean it can't be a HashMap. In fact, the above can be called a lambda table. The () -> printStringXXX(); are lambda expressions, and the map is a table of strings to lambdas.

Klitos Kyriacou
  • 10,634
  • 2
  • 38
  • 70
  • Sorry, I edited the question and re-wrote the constructor. It's still the statement error, but the intent of use is different. This is my fault. – Fiddle Freak May 15 '17 at 10:44
  • omg I was so close. I was just missing the `.printNumber()` in `printNumbers[n]`, making it `printNumbers[n].printNumber();` as the correct answer. Thanks :) – Fiddle Freak May 15 '17 at 10:45