9

Using the Java 8 Stream package I want to transform a List of arrays of type object into a List of a specific class object. The arrays on the first list contain field of the class loaded from the database.

This is the List of arrays of type object loaded from the DB:

List<Object[]> results = loadFromDB();

Every element Object[] present in the list contains fields that I want to map to the following class:

class DeviationRisk {
    Timestamp plannedStart;
    Timestamp plannedEnd;
    String rcsName;
    BigDecimal riskValue;
    BigDecimal mediumThreshold;
    BigDecimal highThreshold;
    Interval interval;

    String getRcsName() {
        return rcsName;
    }

    DeviationRisk(Object[] res) {
        this((Timestamp) res[0], (Timestamp) res[1], (String) res[2], (BigDecimal) res[3], (BigDecimal) res[4], (BigDecimal) res[5]);

    }

    DeviationRisk(Timestamp start, Timestamp end, String rcs, BigDecimal risk, BigDecimal medium, BigDecimal high) {
        plannedStart = start;
        plannedEnd = end;
        rcsName = rcs;
        riskValue = risk;
        mediumThreshold = medium;
        highThreshold = high;
        interval = new Interval(plannedStart.getTime(), plannedEnd.getTime());
    }

    DeviationRisk create(Object[] res) {
              return new DeviationRisk(res);
          }

    List<DateTime> getRange() {
        return DateUtil.datesBetween(new DateTime(plannedStart), new DateTime(plannedEnd));
    }
}

As you can see every element Object[] present in the original list results it's just the array representation of the object DeviationRisk

Now, I know how to do this using loops it's just 3 lines of code as you can see below:

  List<DeviationRisk> deviations = new ArrayList<>();
        for (Object[] res : results) {
            deviations.add(new DeviationRisk(res));
        }

How to achieve the same result using Java 8 Streams?

2 Answers 2

19

You can try with:

List<DeviationRisk> result = results.stream()
                                    .map(DeviationRisk::new)
                                    .collect(Collectors.toList())
Sign up to request clarification or add additional context in comments.

4 Comments

short and smart answer +1.
Cheers :) I was missing the call to new.
@kocko can you explain the map part of it. What happens when you say DeviationRisk::new. I know this is a constructor reference but I can't wrap my head around what happens inside the map method when it is passed a constructor reference.
Can I get your advice on a transformation question here please?
7

This will do it:

final List<DeviationRisk> l = results.stream()
    .map(DeviationRisk::new).collect(Collectors.toList());

This work because DeviationRisk::new is viewed as a Function<Object[], DeviationRisk> by the compiler.

4 Comments

same answer as above so you deserve a +1 as well :)
@fge can you explain the map part of it. What happens when you say DeviationRisk::new. I know this is a constructor reference but I can't wrap my head around what happens inside the map method when it is passed the constructor reference.
@bot as I explained, this is due to the fact that DeviationRisk::new is viewed, at the compiler level, as a Function<Object[], DeviationRisk>. What matters is the argument type (Object[]) and the return type DeviationRisk. Just forget that this is a constructor at all in this case; the compiler is able to infer the fact that ultimately, if you pass something that is an Object[] to the lambda, the result will be a DeviationRisk. That this particular lambda is in fact a method reference to a constructor is of no importance whatsoever -- it could be anything else
Thanks for the explanation. What I want to specifically know is how does the map method use this lambda. Consider for example . list.stream.map(Apple:new) is assigned to a List of Strings and Apple class contains a constructor that initializes the name instance variable. How does the map method know that it must use the name of the Apple as the input to the lambda and not any other instance variable of type String in Apple. In the current example, what if DeviationRisk has two instance variables of type Object[]? How does the lambda know which one to use as input?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.