0

i have this algorithm that i want to change it with parallel streams so it makes less time for the calculation, but when i did it i got the error Local variable defined in an enclosing scope must be final for realiseValeur, nbValid and invalidite.So how can i work with parelle streams in this algorithm. This is my algorithm in which i want to work with parallelstreams :

 @Override
    public Map<String, Double> getMapRealise(Date date, String code, Long pc) {
        Map<String, Double> map = new HashMap<>();
        List<Period> periodList = this.getListPeriod(date, code);
        Double realiseValeur = 0.0;
        Double invalidite = 0.0;
        if (periodList != null) {


            for (Period period : periodList) {
                Double periode = this.getResolutionTraduiteEnHeures(period.getResolution().getV());
                // Date dateDebutPrevisionnel =
                // this.getDateDebutPrevisionnel(period.getTimeInterval().getV());
                Double nbValid = 0.0;
                for (Pt pt : period.getListPt()) {
                    realiseValeur += periode * pt.getQ().getV() / pcnTranche / NBR_HEURES_PAR_JOURS;
                    nbValid = nbValid + pt.getCq().getV();
                }

                if ((nbValid * periode) < NBR_HEURES_MINE_PAR_JOURS) {
                    invalidite++;
                }
            }
        }

        else {
            LOGGER.warn(  "n existe pas ");
        }
        map.put(REALISE_VALEUR, realiseValeur);
        map.put(REALISE_INVALIDITE, invalidite);

        return map;}

I tried this but i got the error Local variable defined in an enclosing scope must be final for realiseValeur, nbValid and invalidite:

@Override
    public Map<String, Double> getMapRealise(Date date, String code, Long pc) {
        Map<String, Double> map = new HashMap<>();
        List<Period> periodList = this.getListPeriod(date, code);
        Double realiseValeur = 0.0;
        Double invalidite = 0.0;
        if (periodList != null) {

            periodList.parallelStream().forEach(period -> {
                Double periode = this.getResolutionTraduiteEnHeures(period.getResolution().getV());
                // Date dateDebutPrevisionnel =
                // this.getDateDebutPrevisionnel(period.getTimeInterval().getV());
                Double nbValid = 0.0;
                period.getListPt().parallelStream().forEach(pt -> {
                    realiseValeur += periode * pt.getQ().getV() / pcnTranche / NBR_HEURES_PAR_JOURS;
                    nbValid = nbValid + pt.getCq().getV();
                });

                if ((nbValid * periode) < NBR_HEURES_MINE_PAR_JOURS) {
                    invalidite++;
                }
            });

        }

        else {
            LOGGER.warn("n existe pas ");
        }
        map.put(REALISE_VALEUR, realiseValeur);
        map.put(REALISE_INVALIDITE, invalidite);

        return map;
    }
fbm fatma
  • 430
  • 6
  • 22

2 Answers2

0

You need to return something from each iteration of the outer loop which has the incremental values for each of the iterations.

Stream<Map<String, Double>> fromParallel =
    periodList.parallelStream()
        .map(period -> {
            double realiseValeurInc = 0.0;
            double invaliditeInc = 0.0;

            // Increment these variables instead of realiseValeur and invalidite

            return Map.of(REALISE_VALEUR, realiseValeurInc, REALISE_INVALIDITE, invaliditeInc);
        });

Now just merge all of these maps together:

Map<String, Double> result =
    fromParallel.reduce(
        (a, b) -> Map.of(
            REALISE_VALEUR, a.get(REALISE_VALEUR) + b.get(REALISE_VALEUR),
            REALISE_INVALIDITE, a.get(REALISE_INVALIDITE) + b.get(REALISE_INVALIDITE)));

(You don't have to do this in two separate steps, that's merely to explain the process.)

And you can use this as the return value (or copy this to a HashMap, if that's what you really need).

Of course, this is wildly inefficient, because of all the allocation of both Double and Map. It will probably be slower than the existing loop-based code. But it will at least give you the correct answer (eventually).

Andy Turner
  • 137,514
  • 11
  • 162
  • 243
  • 1
    …and I thought, using `Double` for every intermediate result was an impressive boxing overhead. But putting everything into a `Map` is truly maxing it out. – Holger May 11 '20 at 10:11
  • @Holger how else am I going to convince OP that parallel stream isn't some magical speed panacea, hm? – Andy Turner May 11 '20 at 10:16
  • 1
    If that was the main goal, point taken. Though, when we mitigate the boxing costs by mapping to a `double[]` array holding two values or a dedicated object holding a `double` and an `int` and use `collect`, to merge the values without creating new objects, it likely would be more efficient, while still being slower than a loop, for a few thousand elements to process. – Holger May 11 '20 at 10:24
-2

You can use AtomicInteger for this operation. since you are using Double for your opeartions. create your own AtomicFloat and use it instead of Double and your problem will be solved :)

import java.util.concurrent.atomic.AtomicInteger;
import static java.lang.Float.*;

class AtomicFloat extends Number {

    private AtomicInteger bits;

    public AtomicFloat() {
        this(0f);
    }

    public AtomicFloat(float initialValue) {
        bits = new AtomicInteger(floatToIntBits(initialValue));
    }

    public final boolean compareAndSet(float expect, float update) {
        return bits.compareAndSet(floatToIntBits(expect),
                                  floatToIntBits(update));
    }

    public final void set(float newValue) {
        bits.set(floatToIntBits(newValue));
    }

    public final float get() {
        return intBitsToFloat(bits.get());
    }

    public float floatValue() {
        return get();
    }

    public final float getAndSet(float newValue) {
        return intBitsToFloat(bits.getAndSet(floatToIntBits(newValue)));
    }

    public final boolean weakCompareAndSet(float expect, float update) {
        return bits.weakCompareAndSet(floatToIntBits(expect),
                                      floatToIntBits(update));
    }

    public double doubleValue() { return (double) floatValue(); }
    public int intValue()       { return (int) get();           }
    public long longValue()     { return (long) get();          }

}