3

I have some data stored in a JPA Repository that I am trying to process. I would like to be able to use Java 8 Streams to do so, but can not figure out how to get the required information. This particular 'Entity' is actually only for recovery, so it holds items that would need to be processed after something like a power-fail/restart.

Using pre-Java 8 for-loops the code would look like:

    List<MyEntity> deletes = myEntityJpaRepository.findByDeletes();
    for (MyEntity item : deletes) {
        String itemJson = item.getData();
        // use a Jackson 'objectMapper' already setup to de-serialize
        MyEventClass deleteEvent = objectMapper.readValue(itemJson, MyEventClass.class);
        processDelete(deleteEvent, item.getId());                   
    }

The problem arises from the two parameter method called at the very end. Using Streams, I believe I would do:

//      deletes.stream()
//             .map(i -> i.getData())
//             .map(event -> objectMapper.readValue(event, MyEventClass.class))
//             .forEach(??? can't get 'id' here to invoke 2 parameter method);

I have a solution (without Streams) that I can live with. However I would think this problem comes up a lot, thus my question is: IN GENERAL, is there a way using Streams to accomplish what I am trying to do?

JoeG
  • 7,191
  • 10
  • 60
  • 105

3 Answers3

3

Why not a Pair return on your map operation:

.map(i -> new Pair<>(i.getData(), i.getId()))
.map(pair -> new Pair<>(objectMapper.readValue(pair.getLeft(), MyEventClass.class), pair.getRight())
.forEach(p -> processDelete(pair.getLeft(), pair.getRight()))

I did not compile this, so there might be minor things to fix. But in general, you would need a Holder to pass your objects to the next stage in such a case. Either a Pair or some type or even a array.

Eugene
  • 117,005
  • 15
  • 201
  • 306
  • Sorry, I missed the note about `Holder`. I think that is the best answer. Initially, I didn't like "Pair" because it doesn't scale (yes, I know about `Triple`), and also conveys a relationship that might not be there. `Holder` seems the best general solution IMO. – JoeG May 15 '17 at 18:34
  • @JoeG as a side note, have a look http://stackoverflow.com/questions/43973776/what-is-equivalent-to-c-sharp-select-clause-in-java-streams/43983558#43983558 also for a absolutely nontrivial way... – Eugene May 15 '17 at 19:08
3

Why not doing it simply this way?

deletes.forEach(item -> 
    processDelete(objectMapper.readValue(item.getData(), MyEventClass.class),
                  item.getId()));
Harmlezz
  • 7,972
  • 27
  • 35
  • This is the "best" solution for my particular problem. However, I don't think it is a "general" solution. – JoeG May 15 '17 at 18:30
1

This is a start at least, I guess it is dependent on why you want to use stream and how much you want to make it more functional

List<MyEntity> deletes = myEntityJpaRepository.findByDeletes();
deletes.stream().foreach(item -> { 
    String itemJson = item.getData();
    // use a Jackson 'objectMapper' already setup to de-serialize
    MyEventClass deleteEvent = objectMapper.readValue(itemJson, MyEventClass.class);
    processDelete(deleteEvent, item.getId());                   
});
Viktor Mellgren
  • 4,318
  • 3
  • 42
  • 75