Reputation: 1
I am working on a program that is supposed to describe a takeout system. I have a specific method that is supposed to simulate whether a customer has enough money to buy something using an interface. The problem I encountered was that while I was trying to implement an interface, UserInputRetriever, using lambda..I could only use final variables within the lambda expression. When it got to making a return statement for the method itself, shouldSimulate(), I realized I couldnt because what I returned is only visible in the lambda. Now IntelliJ, suggested using a final array which worked, because I was able to use it within the lambda expression and outside of it. I just need understanding as to why using array worked as compared to using a variable. Can you please explain?
The method is as follows:
public boolean shouldSimulate() {
boolean[] hasMoney = new boolean[1];
String userPrompt = """
Please choose an option from the following:
0. To end simulation process
1. To proceed with simulation process""";
UserInputRetriever<?> intUserInputRetriever = selection -> {
if(selection == 1 && customer.money >= menu.getLowestFoodCost()){
System.out.println("You have enough money.\nProceeding with " +
"simulation");
hasMoney[0] = true;
}
else if (selection == 1 && customer.money < menu.getLowestFoodCost()){
System.out.println("You do not have enough money.\nEnding the" +
" simulation");
hasMoney[0] = false;
}
else if(selection == 0){
System.out.println("Terminating simulation");
hasMoney[0] = false;
}
else
throw new IllegalArgumentException("Please choose a valid " +
"option");
return hasMoney[0];// if hasMoney was a variable, this would not throw a compile time error
};
getOutputOnInput(userPrompt, intUserInputRetriever);// you can ignore this line
return hasMoney[0];// if hasMoney was a variable, this would throw a compile time error
}
I tried using a variable first locally and tried to also use that in my interface implementation (which used lambda), but it threw errors. But upon using suggestion from IntelliJ which suggested using an array, it worked. I would like to know why
Upvotes: 0
Views: 286
Reputation: 86
The Java Lang. Spec. states that the "restriction to effectively final variables prohibits access to dynamically-changing local variables, whose capture would likely introduce concurrency problems".
In order to address this problem you can use atomic references or atomic types, e.g., AtomicBoolean.
BTW: It would have been helpful for others to provide an executable example of the problem and the solution. Something like this makes it easier to help:
import org.junit.jupiter.api.Test;
import java.util.concurrent.atomic.AtomicBoolean;
import static org.junit.jupiter.api.Assertions.*;
public class FunctionalInterfaceProblem {
public static String EXCEPTION_MESSAGE = "Value not 0 or 1";
@java.lang.FunctionalInterface
interface SomeInterfaceWithBoolean<T> {
boolean calculate(T i) throws IllegalArgumentException;
}
@Test
public void testWihArray() {
boolean[] outcome = new boolean[1];
SomeInterfaceWithBoolean<Integer> result = i -> {
if(i == 1){
outcome[0] = true;
} else if (i == 0){
outcome[0] = false;
} else {
throw new IllegalArgumentException(EXCEPTION_MESSAGE);
}
return outcome[0];
};
assertFalse(result.calculate(0));
assertTrue(result.calculate(1));
Throwable exception = assertThrows(IllegalArgumentException.class, ()->{result.calculate(2);} );
assertEquals(EXCEPTION_MESSAGE, exception.getMessage());
}
@java.lang.FunctionalInterface
interface SomeInterfaceWithAtomicBoolean<T> {
AtomicBoolean calculate(T i) throws IllegalArgumentException;
}
@Test
public void testWihAtomicBoolean() {
AtomicBoolean outcome = new AtomicBoolean(false);
SomeInterfaceWithAtomicBoolean<Integer> result = i -> {
if(i == 1){
outcome.set(true);
} else if (i == 0){
outcome.set(false);
} else {
throw new IllegalArgumentException(EXCEPTION_MESSAGE);
}
return outcome;
};
assertFalse(result.calculate(0).get());
assertTrue(result.calculate(1).get());
Throwable exception = assertThrows(IllegalArgumentException.class, ()->{result.calculate(2);} );
assertEquals(EXCEPTION_MESSAGE, exception.getMessage());
}
}
Upvotes: 2