简体   繁体   English

如何使用Java 8 Stream API转换代码?

[英]How can i transform my code using java 8 stream API?

I am writing a simple method to print out statistics of a series of outcomes of games. 我正在编写一种简单的方法来打印一系列游戏结果的统计数据。 Every Game has a list of Outcomes in it, which contain enums according to the outcome of a game. 每个游戏都有一个结果列表,其中包含根据游戏结果列出的枚举。 My instructor has commented a TODO in my code: 我的老师在我的代码中注释了一个TODO:

public static void printStatistics(List<Game> games) {
    float win = 0;
    float lose = 0;
    float draw = 0;
    float all = 0;

    //TODO: should be implemented /w stream API
    for (Game g : games) {
        for (Outcome o : g.getOutcomes()) {
            if (o.equals(Outcome.WIN)) {
                win++;
                all++;
            } else if (o.equals(Outcome.LOSE)) {
                lose++;
                all++;
            } else {
                draw++;
                all++;
            }
        }
    }
    DecimalFormat statFormat = new DecimalFormat("##.##");

    System.out.println("Statistics: The team won: " + statFormat.format(win * 100 / all) + " %, lost " + statFormat.format(lose * 100 / all)
            + " %, draw: " + statFormat.format(draw * 100 / all) + " %");

}

I am familiar with lambda expressions. 我熟悉lambda表达式。 I tried looking online for solutions, but could not find examples of a stream accessing fields of a field of a class. 我尝试在网上寻找解决方案,但找不到流访问类的字段的示例。 I would be happy if you could give me a solution, or provide me with a relevant tutorial. 如果您可以给我解决方案,或者提供相关的教程,我将非常高兴。 Thanks. 谢谢。

You can stream games, flatMap to outcomes, then collect them to a map of counts: 您可以将游戏,flatMap流化为结果,然后将它们收集到计数图中:

Map<Outcome, Long> counts = games.stream()
        .map(Game::getOutcomes)
        .flatMap(Collection::stream)
        .collecting(Collectors.groupingBy(o -> o, Collectors.counting()));

long win = counts.getOrDefault(Outcome.WIN, 0L);
long lose = counts.getOrDefault(Outcome.LOSE, 0L);
long draw = counts.getOrDefault(Outcome.DRAW, 0L);
long all = games.stream()
        .mapToInt(g -> g.getOutcomes().size())
        .sum();

groupingBy fits this case: groupingBy适合这种情况:

Map<Outcome, Long> map = games.stream()
        .flatMap(game -> game.getOutcomes().stream())
        .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

And get win , lose count: 获得winlose计数:

long win = map.get(Outcomes.WIN);
long lose = map.get(Outcomes.LOSE);
...

To get all count you need to sum all values from map 要获得all计数,您需要对地图中的所有值求和

long all = map.values().stream()
    .mapToLong(Long::valueOf)
    .sum();

To access the fields of the class in a Stream , use map : 要访问Stream中的类的字段,请使用map

games.stream().map(game -> 
  game.getOutcomes().stream().map(outcome -> {
    // do something with each `outcome`
  })
)

The above code assumes that getOutcomes() returns a List , which is not specified in the current version of OP's question. 上面的代码假定getOutcomes()返回一个List ,该List未在OP的当前版本中指定。

Note that you cannot simply increment counters within a Stream , as you might hope to, because all variables used within Stream s must be final or effectively final. 请注意,您不能像您希望的那样简单地在Stream增加计数器,因为Stream内使用的所有变量必须是final或有效的final。 You'll have to dig a bit more into the Stream API to figure out how to increment the way you did in your original solution. 您将不得不对Stream API进行更多的研究,以找出如何增加您在原始解决方案中的方法。

Hint: you want to do something like this , which utilises Collectors.groupingBy() . 提示:你想要做像这样 ,它利用Collectors.groupingBy() 。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM