I need to write a Lambda function which can auto increment counter value. for example- my counter value is 0. Then, i execute lambda expression which shall increment counter value to 1 , set value 1 to counter and return this counter value (1) from lambda expression. Then, next time, when I call lambda expression , lambda should increment counter value to 2, and return value (2) from lambda. how to write such kind of lambda. I am new to lambda programming. please excuse me if I have ask pretty simple and straight forward question. Thanks in advance. Please help.
5 Answers
public static void main(String args[]) {
//with type declaration
MathOperation incrementCounter = (int a) -> a++;
//with out type declaration
MathOperation incrementCounter = a -> a++;
//with return statement along with curly braces
MathOperation incrementCounter = (int a) -> { return a++; };
//without return statement and without curly braces
MathOperation division = (int a) -> a++;
System.out.println("Increment" + tester.operate(10, incrementCounter));
interface MathOperation {
int operation(int a);
}
private int operate(int a, MathOperation mathOperation) {
return mathOperation.operation(a);
}
}
Comments
One thing to note, it is tempting to use lamda with Stream and when we work with Stream, it is easy to add a .parallel call to use multithreading. This adds some concurrencies problem.
One good thing is that could be solved using a class that could also help you with your task, AtomicInteger provide a method to increment AtomicInteger.incAndGet or to add AtomicInteger.addAndGet
This could be used as a method reference like this :
final int SIZE = 10_000;
AtomicInteger cnt = new AtomicInteger();
IntStream.range(0, SIZE)
.parallel().map(i -> 1)
.forEach(cnt::addAndGet);
This is not the most interesting code, but this will increment using a synchronized counter, preventing the problems. I have use an equivalent code using a simple counter with an int for the comparison and on almost each tries, it fails.
Here is a quick code to prove the concept. It is a simple loop that will try 100 times each test and output in the console if there is a problem.
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class Main {
int cntInt;
AtomicInteger cntAtom;
final int SIZE = 10_000;
final int TRIES = 1_000;
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Main().testInt();
}
for (int i = 0; i < 100; i++) {
new Main().testAtomic();
}
}
public void testInt(){
int testCount = 0;
do{
cntInt = 0;
testCount++;
IntStream.range(0, SIZE)
.parallel().map(i -> 1)
.forEach(i -> cntInt += i);
}while(cntInt == SIZE && testCount < TRIES);
if(cntInt != SIZE ){
System.out.format("INTEGER Run: %d, Value: %d, Expected: %d%n", testCount, cntInt, SIZE);
}
}
public void testAtomic(){
int testCount = 0;
do{
cntAtom = new AtomicInteger();
testCount++;
IntStream.range(0, SIZE)
.parallel().map(i -> 1)
.forEach(cntAtom::addAndGet);
}while(cntAtom.get() == SIZE&& testCount < TRIES);
if(cntAtom.get() != SIZE ){
System.out.format("ATOMIC Run: %d. Value: %dm Expected: %d%n", testCount, cntAtom.get(), SIZE);
}
}
}
Some times, the INTEGER can run quite some time without any issues but you will notice that using an the AtomicInteger and the synchronize approach is safer.
Comments
It sounds like you are trying to do 2 things use a lambda and also create an increment solution. I would suggest separating the issues and ask why you need a lambda for the incrementer solution. The below is a solution with a lambda but it is hard for me to believe that I would ever write something like this in the real world.
interface Thing{
public int increment();
}
public class Lambda {
private static Integer counter = 0;
/**
*
*/
public static Integer testingLambda() {
Thing thing = () -> ++counter;
return thing.increment();
}
}
I would probably go for something like this instead...
public class Lambda {
private static int counter = 0;
private Lambda() {
}
public static void increment() {
counter++;
}
public static int getCounter() {
return counter;
}
Comments
This is the simplest lambda form which can auto-increment the value of a counter. The counter is initialized with 0. Each call of count.getAsInt() returns the current counter value and increments the counter afterwards (post-incremented). So the counter in the example returns 0, 1, 2….
With ++counter[0] it would be 1, 2, 3….
int[] counter = new int[] { 0 };
IntSupplier count = () -> counter[0]++;
count.getAsInt(); // returns 0, 1, 2…