如何在Java8中使用foreach循环中的变量?

时间:2014-06-28 11:21:59

标签: java java-8

这是我的实际for-each循环。我需要将其转换为java8 for循环。

for (PromotionEntity promotionEntity : pestudents) {
                List<ClassAttendanceChild> attendancelist = session.createQuery("from ClassAttendanceChild where attendanceadded='" + day + "' and pid.pId='" + promotionEntity.getpId() + "'").list();
                if (!attendancelist.isEmpty()) {
                    ClassAttendanceChild attendenceDetails = (ClassAttendanceChild) attendancelist.get(0);
                    if (attendenceDetails.getStatus().equalsIgnoreCase("yes")) {
                        present++;
                        System.out.println("present = " + present);
                    } else {
                        Absent++;
                        System.out.println("Absent = " + Absent);
                    }
                } else {
                    nottaken++;
                    System.out.println("nottaken = " + nottaken);
                }
            }

如何将其转换为java8 for循环,我在该变量增量中得到异常:

 pestudents.forEach(promotionEntity -> {
            List<ClassAttendanceChild> attendancelist = session.createQuery("from ClassAttendanceChild where attendanceadded='" + day + "' and pid.pId='" + promotionEntity.getpId() + "'").list();
            if (!attendancelist.isEmpty()) {
                 ClassAttendanceChild attendenceDetails = (ClassAttendanceChild) attendancelist.get(0);
                  if (attendenceDetails.getStatus().equalsIgnoreCase("yes")) {
//                    present++;
//                    System.out.println("present = " + present);
                } else {
//                    Absent++;
//                    System.out.println("Absent = " + Absent);
                }
            } else {
//                nottaken++;
//                System.out.println("nottaken = " + nottaken);
            }


        });

3 个答案:

答案 0 :(得分:4)

像往常一样,当您决定实现功能时,您必须回到更高级别的目标描述,然后以FP风格重写代码。

您想确定三类事件的总数:“现在”,“缺席”和“未记录”。以下是关于如何通过FP方式实现它的建议(感谢Stuart Marks指出如何构建库提供的频率计数收集器):

import static java.util.stream.Collectors.counting;
import static java.util.stream.Collectors.groupingBy;

...

System.out.println(pestudents.stream().collect(groupingBy(pe -> {
    final List<ClassAttendanceChild> attendancelist = session.createQuery(
        "from ClassAttendanceChild where attendanceadded='" + day 
        + "' and pid.pId='" + promotionEntity.getpId() + "'")
      .list();
    return attendancelist.isEmpty()? "nottaken"
        : attendancelist.get(0).getStatus().equalsIgnoreCase("yes")?
            "present" : "absent";
  }, counting())));

您可以注意到我们已将工作分为两个阶段:首先我们对每个PromotionEntity进行分类,然后对这些进行频率计数减少。结果是从类别到其计数的映射。

对我而言,意图的清晰度足以具有FP风格的优势,但这具有为并行化准备地形的额外优势。在这种特殊情况下,并行化可能不会得到回报,因为瓶颈是数据库,但一般来说,如果全程采用FP风格,则并行化将成为更接近目标。


(原始代码,带自定义收集器)

public static void main(String[] args) {
  final List<PromotionEntity> pestudents = ...your initialization...
  final Map<String, Integer> freqs = pestudents.stream().map(pe -> {
    final List<ClassAttendanceChild> attendancelist = session.createQuery(
           "from ClassAttendanceChild where attendanceadded='" + day + 
           "' and pid.pId='" + promotionEntity.getpId() + "'")
      .list();
    return attendancelist.isEmpty()? "nottaken" 
        : attendancelist.get(0).getStatus().equalsIgnoreCase("yes")?
            "present" : "absent";
  }).collect(toFrequencyMap());
  System.out.println(freqs);
}

static Integer zeroForNull(Integer i) { return i == null? 0 : i; }

static <K> Collector<K, Map<K, Integer>, Map<K, Integer>> toFrequencyMap() {
  return Collector.of(
      HashMap<K, Integer>::new,
      (acc, key) -> acc.compute(key, (x, count) -> zeroForNull(count) + 1),
      (acc, source) -> {
        source.forEach((key, sourceCount) ->
          acc.compute(key, (x,accCount) ->
            sourceCount + zeroForNull(accCount)));
        return acc;
      },
      Collector.Characteristics.UNORDERED);
}

答案 1 :(得分:1)

要并行化此代码,您可以使用AtomicInteger作为线程安全计数器。

AtomicInteger present = new AtomicInteger();
AtomicInteger absent = new AtomicInteger();
AtomicInteger nottaken = new AtomicInteger();

pestudents.parallelStream().forEach(promotionEntity -> {
        List<ClassAttendanceChild> attendancelist = session.createQuery("from ClassAttendanceChild where attendanceadded='" + day + "' and pid.pId='" + promotionEntity.getpId() + "'").list();
        if (!attendancelist.isEmpty()) {
             ClassAttendanceChild attendenceDetails = (ClassAttendanceChild) attendancelist.get(0);
              if (attendenceDetails.getStatus().equalsIgnoreCase("yes")) {
                  present.incrementAndGet();
                  System.out.println("present = " + present);
            } else {
                  absent.incrementAndGet();
                  System.out.println("Absent = " + Absent);
            }
        } else {
              nottaken.incrementAndGet();
              System.out.println("nottaken = " + nottaken);
        }
    });

答案 2 :(得分:0)

不允许修改传递给forEach的方法之外定义的局部变量。必须将它们声明为final或至少有效地最终,这意味着它们在初始化后永远不会更改。

您可以做的是将present和其他局部变量更改为实例变量或类变量,允许您修改它们。

那就是说,我建议你保留旧语法,它更适合你想要做的事情。