Счетчик приращений в лямбда-выражении - PullRequest
0 голосов
/ 14 июня 2019

Мне нужно написать лямбда-функцию, которая может автоматически увеличивать значение счетчика. например, мое значение счетчика равно 0. Затем я выполняю лямбда-выражение, которое увеличивает значение счетчика до 1, устанавливает значение 1 в счетчик и возвращает это значение счетчика (1) из лямбда-выражения. Затем в следующий раз, когда я вызываю лямбда-выражение, лямбда должна увеличить значение счетчика до 2 и вернуть значение (2) из ​​лямбда-выражения. как написать такую ​​лямбду. Я новичок в лямбда-программировании. пожалуйста, извините, если я задам довольно простой и прямой вопрос. Заранее спасибо. Пожалуйста, помогите.

Ответы [ 5 ]

2 голосов
/ 14 июня 2019
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);
}
}
0 голосов
/ 16 июня 2019

Это самая простая лямбда-форма, которая может автоматически увеличивать значение счетчика. Счетчик инициализируется с 0. Каждый вызов count.getAsInt() возвращает текущее значение счетчика и впоследствии увеличивает счетчик (после увеличения). Таким образом, счетчик в примере возвращает 0, 1, 2….
С ++counter[0] это будет 1, 2, 3….

int[] counter = new int[] { 0 };
IntSupplier count = () -> counter[0]++;

count.getAsInt();   // returns 0, 1, 2…
0 голосов
/ 14 июня 2019

Следует отметить, что использование lamda с Stream заманчиво, а когда мы работаем с Stream, легко добавить вызов .parallel для использования многопоточности. Это добавляет проблему с параллелизмом.

Одна хорошая вещь - это то, что можно решить с помощью класса, который также может помочь вам с вашей задачей: AtomicInteger предоставляет метод для увеличения AtomicInteger.incAndGet или для добавления AtomicInteger.addAndGet

Это можно использовать как ссылку на метод, например:

final int SIZE = 10_000;
AtomicInteger cnt = new AtomicInteger();
IntStream.range(0,  SIZE)
    .parallel().map(i -> 1)
    .forEach(cnt::addAndGet);

Это не самый интересный код, но он будет увеличиваться с использованием синхронизированного счетчика, предотвращая проблемы. Я использовал эквивалентный код, используя простой счетчик с int для сравнения, и почти при каждой попытке он не работает.

Вот быстрый код для подтверждения концепции. Это простой цикл, который будет пытаться 100 раз каждый тест и выводить в консоли, если есть проблема.

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);
        }
    }
}

Иногда INTEGER может работать довольно долго без каких-либо проблем, но вы заметите, что использование AtomicInteger и синхронизация более безопасны.

0 голосов
/ 14 июня 2019

Похоже, вы пытаетесь сделать 2 вещи, используя лямбду, а также создать решение для приращения.Я бы предложил разделить вопросы и спросить, зачем вам лямбда для решения инкрементатора.Ниже приведено решение с лямбдой, но мне трудно поверить, что я когда-нибудь напишу что-то подобное в реальном мире.

interface Thing{
    public int increment();
}

public class Lambda {

    private static Integer counter = 0;

    /**
     *
     */
    public static Integer testingLambda() {
        Thing thing = () -> ++counter;
        return thing.increment();
    }
}

Возможно, я бы вместо этого пошел на что-то подобное ...

public class Lambda {

private static int counter = 0;

private Lambda() {

}

public static void increment() {
    counter++;
}

public static int getCounter() {
    return counter;
}
0 голосов
/ 14 июня 2019

Я не думаю, что вы можете сделать это просто в лямбда-выражении, но вы можете использовать анонимную запись класса:

        Function<String,Integer> fct = new Function<String,Integer>() {
            int counter = 0;
            @Override
            public Integer apply(String t) {
                // ...
                return ++counter;
            }
        };
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...