【问题标题】:Spliting string, flatMapping it and creating objects using Java streams?拆分字符串,flatMapping 它并使用 Java 流创建对象?
【发布时间】:2020-04-22 23:49:12
【问题描述】:

我有 2 节课是这样的:

public class Seat extends Moviefiable {

        private int number;
        private Hall hall;

        public Seat(int id, boolean active, int number, Hall hall) {
            super(id, active);
            this.number = number;
            this.hall = hall;
        }

        public Seat() {this(-1, false, -1, null);}

        public static Seat getById(int idSeat) throws SQLException {
            Seat seat = SeatDAO.getById(idSeat);
            return seat;
        }
}

public class Ticket extends Moviefiable {

private Projection projection;
private Seat seat;
private LocalDateTime purchasingDate;
private User user;

public Ticket(int id, boolean active, Projection projection, Seat seat, LocalDateTime purchasingDate, User user) {
    super(id, active);
    this.projection = projection;
    this.seat = seat;
    this.purchasingDate = purchasingDate;
    this.user = user;
}

public Ticket() {this(-1, false, null, null, null, null);}

现在,我需要创建两个或更多 Tickets,这取决于 loggedInUser 选择的票数。从我的JSP 页面,我会得到这样的信息:

String uri = request.getQueryString(); //uri looks like this: seats=2&seats=3

我想为两个 Seat 对象创建两个 Ticket 对象。在uri 字符串中,字符 2 和 3 是席位的主键。

这个想法是使用 Java 流来执行拆分和创建对象。这是我目前为止的。

ArrayList<Ticket> newTicketsForSeats = Stream.of(uri.split("&"))
                   .map(s -> s.split("seats=")[1])
                   //.flatMap(Arrays::stream)
                   .mapToInt(Integer::valueOf)
                   .mapToObj(s -> {
                    try {
                        return new Ticket(-1, true, projection, SeatDAO.getById(s), 
                                 LocalDateTime.now(), loggedInUser);
                    } catch (SQLException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                        return null;
                    }
                })
                   .collect(Collectors.toCollection(ArrayList::new));

当我进行测试时,像这样查看我得到的输出:

Stream.of(uri.split("&"))
    .map(s -> s.split("seats=")[1])
    .mapToInt(Integer::valueOf)
    .forEach(System.out::println); //2 3

没关系。但是当我运行上面的代码时,我得到了:

java.lang.ArrayIndexOutOfBoundsException: 1
at servlets.ConfirmPurchaseServlet.lambda$0(ConfirmPurchaseServlet.java:62)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)

projection也是我得到的对象,这只是参考,它在servlet的其他地方。 loggedInUser我从会话中得到。我是关于 Java 流的新手,任何额外的解释都会很好。

我知道map() 需要IntUnaryOperator lambda 表达式,如下所示:

s -> s * 10

我不知道如何从 int(Seat 的主键)“映射”到 Seat 对象。

干杯。

【问题讨论】:

  • 我认为你需要mapToObj 而不是map...
  • 我将map 更改为mapToObj,第二个mapToObj 报告错误:方法 mapToObj(( s) -> {}) 未定义 Stream
  • 也在这里发布:coderanch.com/t/724831/java/…

标签: java java-stream flatmap


【解决方案1】:

您的主要问题是您试图将流输出分配给ArrayListCollectors.toList() 返回一个 List,不能指望它是一个特定的实现。

所以要么这样做:

List<SomeClass> list = ...collect(Collectors.toList());

或者这个

ArrayList<SomeClass> list = ... collect(Collectors.toCollection(ArrayList::new));

以下应该可以工作,但可能需要根据您的其他课程进行一些调整。

ArrayList<Ticket> newTicketsForSeats = Stream.of(uri.split("&"))
               .map(s -> s.split("seats="))
               .flatMap(Arrays::stream)
               .mapToInt(Integer::valueOf)
               .mapToObj(s -> new Ticket(-1, true, projection, SeatDAO.getById(s), 
                     LocalDateTime.now(), loggedInUser))
               .collect(Collectors.toCollection(ArrayList::new));

【讨论】:

  • 非常感谢您的重播。我编辑了我原来的问题。 SeatDAO.getById(int idSeat) 可能会抛出异常,所以 Eclipse 本身建议使用这个 try-catch 块,但是,我以某种方式得到了一些未经检查的异常......
【解决方案2】:

其中任何一个都可能有效:

List<Ticket> newTicketsForSeats = Stream.of(uri.split("&"))
        .map(s -> s.replace("seats=", ""))
        .mapToInt(Integer::valueOf)
        .mapToObj(s -> new Ticket(-1, true, projection, SeatDAO.getById(s), LocalDateTime.now(), loggedInUser))
        .collect(Collectors.toList());

List<Ticket> newTicketsForSeats = Stream.of(uri.split("&"))
        .map(s -> s.replace("seats=", ""))
        .map(s -> new Ticket(-1, true, projection, SeatDAO.getById(Integer.valueOf(s)), LocalDateTime.now(), loggedInUser))
        .collect(Collectors.toList());

顺便说一句:您似乎没有与签名匹配的 Ticket 构造函数:

Ticket(int, boolean, Projection, Seat, LocalDateTime, boolean)

【讨论】:

  • 感谢 Ron 在这里和 Ranch 论坛上的回复。互联网有时,看起来很奇怪,可能是一个小地方:)我编辑了我的答案。关于 Ticket 构造函数,我有它,我的类是这样的: Ticket(int id, boolean active, Projection projection, Seat seat, LocalDateTime date, User user) 希望你能帮助我。
  • 附带说明,您肯定需要.mapToInt(Integer::parseInt) 而不是.mapToInt(Integer::valueOf),否则,您将装箱到Integer 对象中,只是为了立即取消装箱到int。如果您不关心拳击开销,请使用.map(Integer::valueOf)...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-09-29
  • 2014-11-22
  • 1970-01-01
  • 1970-01-01
  • 2023-04-05
  • 2016-03-23
  • 1970-01-01
相关资源
最近更新 更多