【问题标题】:Java 8 shows this error. Local variable itemList defined in an enclosing scope must be final or effectively finalJava 8 显示此错误。在封闭范围内定义的局部变量 itemList 必须是 final 或有效 final
【发布时间】:2017-03-16 10:44:46
【问题描述】:

我正在使用 java 8 编写代码,但我迭代 List,然后使用类别类型找到 RestaurantOrderBook。并将List 放入Map。它显示此错误:

在封闭范围内定义的局部变量 itemList 必须是 final 或有效 final

Query query = new Query();
String categ = category;
query.addCriteria(Criteria.where("restaurantId").is(restaurantId));

List<RestaurantOrderBook> itemList = new ArrayList<RestaurantOrderBook>();
itemList = mongoTemplate.find(query, RestaurantOrderBook.class);
System.out.println("size : " + itemList.size());
Map<String , List<RestaurantOrderBook>> map = new HashMap<String , List<RestaurantOrderBook>>();
        Arrays.asList("TakeAway", "Dining").forEach(e ->{

//Following line throws error:              
List<RestaurantOrderBook> list  = itemList.stream().filter(a -> !a.getOrderType().isEmpty() && a.getOrderType().equals(e)).collect(Collectors.toList());
                map.put(e, list);
        });

我还有另一种情况:

@Override
    public EventReportRewardsPoints eventReportRewardsPoints(String organizerId) {
        try{
            List<Event> listOfEvents = eventRepo.findByOrganizerId(organizerId);
            EventReportRewardsPoints eventTransReport = new EventReportRewardsPoints();
            Integer soldTics = 0;
            Double totalRevenue = 0d;
            Integer soldToday  = 0;

            Integer findTotalAvailableTics = 0;
            Integer findTotalQtytics = 0;

            for (Event event : listOfEvents) {
                List<EventTicket> eventTicket = eventTicketRepo.findByEventId(event.getId());

                Integer sumOfAvailabletics = eventTicket.stream()
                        .mapToInt(EventTicket::getRemainingTickets).sum();
                findTotalAvailableTics = findTotalAvailableTics + sumOfAvailabletics;

                Integer sumOfQtytics = eventTicket.stream().mapToInt(EventTicket::getQty).sum();
                findTotalQtytics  = findTotalQtytics + sumOfQtytics;

                List<EventTicketBook> listOfEventsTic = eventTicketBookRepository.findByEventId(event.getId());
                for (EventTicketBook eventTicketBook : listOfEventsTic) {
                    Double sumOfSales = eventTicketBook.getTickets().stream().mapToDouble(EventTicket::getPrice).sum();
                    totalRevenue = totalRevenue + sumOfSales;
                    Date now = new Date();
                    System.out.println("create date : " + eventTicketBook.getCreateOn());
                    /*if(now.compareTo(eventTicketBook.getCreateOn()) == 0){
                        Integer sumOfSoldToday = eventTicketBook.getTickets().stream().mapToInt(EventTicket::getQty).sum();
                        soldToday = soldToday + sumOfSoldToday;
                    }*/
                }
            }
            System.out.println("findTotalQtytics : " + findTotalQtytics);
            System.out.println("findTotalAvailableTics : " + findTotalAvailableTics);
            soldTics = findTotalQtytics - findTotalAvailableTics;
            eventTransReport.setTotalRevenue(totalRevenue);
            eventTransReport.setSoldToday(soldToday);
            eventTransReport.setTicketsSold(soldTics);
            return eventTransReport;
        }catch(Exception e ){
            e.printStackTrace();
        }
        return null;
    }

如何使用 lamda 表达式实现这一点??

【问题讨论】:

  • 我已阅读 stackover flow 中的帖子,但我无法理解。请用简单的方式解释我。
  • 我很好奇,为什么这被否决了,因为它是 Java 8 lambda/streams 领域的一个常见问题。还是因为重复?
  • @Navaneethan Arun 请提出一个新问题,而不是用第二个问题来强化原来的问题
  • @Stefan Zobel 我想将我的第二种情况转换为 lamda。请转换代码或给我您自己的想法。感谢您为我度过的黄金时光。

标签: java java-8 java-stream


【解决方案1】:

您在 lambda 表达式中使用 itemList。因此它必须是最终的。

Java 8 引入了有效最终的新概念,这意味着编译器会检查使用的变量是否在使用中是最终的,并且不会强制开发人员将其显式声明为最终的。 p>

因此,如果您将代码更改为

final List<RestaurantOrderBook> itemList = new ArrayList<RestaurantOrderBook>();

你会看到,编译器在以下位置给你一个错误:

itemList = mongoTemplate.find(query, RestaurantOrderBook.class);

因为您正在重新签署 itemList。这就是为什么 itemList 也不是有效的最终状态。如果你把这两行压缩成

List<RestaurantOrderBook> itemList = mongoTemplate.find(query, RestaurantOrderBook.class);

它应该可以工作。

【讨论】:

  • 我以后可以添加更多记录吗?因为它是最终的。
  • 是的。 final 仅表示,您不能将 itemList 设置为另一个 List 实例,但并不意味着您的 List 实例本身是只读的。
  • 你好@wumpz 我已经提出了另一种情况。我如何将代码编写为 lamda.?当我写它时,它给出了同样的错误。 “在封闭范围内定义的局部变量 itemList 必须是最终的或有效的最终”
  • 在第二个例子中你在哪里使用你的 lambda 表达式?我只能看到方法引用。
  • 我不确定您打算做什么。你想用 forEach 替换你的 for 循环吗?
【解决方案2】:

声明你的变量 itemList final:

final List<RestaurantOrderBook> itemList = mongoTemplate.find(query, RestaurantOrderBook.class);

【讨论】:

  • 这是声明为 final 的好方法吗?也许我将来会在列表中添加一些记录。我该怎么办?
  • 没必要。有效地最终意味着,编译器检查使用情况。因此,此答案仅在正确的位置提供错误消息。
  • 使用 final 关键字您仍然可以将项目添加到列表中,但您不能将不同的列表分配给变量 itemList。
  • 这是正确的,但在 lambda 表达式中使用它不是必需的,因为编译器会为您检查它(实际上是最终的)。
【解决方案3】:

正如 wumpz 接受的答案中所述,原因是所使用的变量必须是最终的或有效的最终变量。

我想补充一下原因来说明为什么会这样

当我们编写一个 Lambda 表达式时,我们实际上是在创建一个匿名内部类。例如:

@FunctionalInterface
interface MyInterface{
    public void print();
}

在我们的代码中用作:

public static void main(String[] args) {
        int i = 6;  

        new MyInterface() {             
            @Override
            public void print() {                
                System.out.println(++i); // Remove ++ to resolve error
            }
        }.print();
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-09-24
    • 2021-01-12
    • 2017-08-28
    • 2018-09-27
    • 2019-03-04
    • 2019-10-28
    • 1970-01-01
    相关资源
    最近更新 更多