4

Originally, I have this code:

String[] A;
String[] B;
//...
List<String> myList= new ArrayList<>(A.length + B.length);
for (int i= 0; i< B.length; i++){
   myList.add(A[i]);
   myList.add("*".equals(B[i]) ? B[i] : doSomethingWith(B[i]));
}

How to refactor if using, preferably, Java 8?

If for instance I have these arrays

A = {"one", "two", "three", "four"}

B = {"five", "six", "seven", "eight"}

At the end of the code, myList will be:

myList = {"one", "five", "two", "six", "three", "seven", "four", "eight"}

raullalves
  • 836
  • 8
  • 20

2 Answers2

5

I personally don't think this needs refactoring as any "streamed" code will be less readable and less intuitive than your existing code, but as a pure proof-of-concept:

String[] A;
String[] B;
List<String> myList;

myList = IntStream.range(0, B.length)
                  .mapToObj(i -> new String[]
                      {
                          A[i],
                          "*".equals(B[i]) ? B[i] : doSomethingWith(B[i])
                      })
                  .flatMap(Arrays::stream)
                  .collect(Collectors.toList());

Working demo.


  • We use IntStream.range to provide the indices into our arrays.

  • mapToObj maps each index to an array containing the elements we want (this stage is also needed as IntStream::flatMap can only convert to another IntStream, we want to convert it to a Stream of Strings).

  • flatMap maps each array to a stream, then "flattens" the resulting stream of streams.

  • Finally, we just collect the results.

hnefatl
  • 5,860
  • 2
  • 27
  • 49
  • 2
    Indeed, personally I cannot see the obsession with needing a streams / Java 8 solution for everything when it just makes the code less readable (in my opinion). – d.j.brown Jan 12 '18 at 11:39
  • That's exactly what I wanted. Thank you very much! – raullalves Jan 12 '18 at 11:49
  • you could improve readability - I had a little go, but it got rejected; benefits of streaming are however beyond readability. OPs solution has to do 'full array scan' while streamed solution can be lazily evaluated, elements can be skipped (and computation e.g. `doSomethingWith` will not happen on skipped ones), finally it all can be parallelised, which would be much harder in OPs case and would result in shared, possibly contested memory access – diginoise Jan 12 '18 at 12:37
  • @diginoise I tried to deliberately mimic parts of the OP's structure - I appreciate the edit with `Arrays::stream`, though. – hnefatl Jan 12 '18 at 12:39
  • 1
    There is no sense in initializing `myList` with `new ArrayList<>(A.length + B.length)`; it will be overwritten with the unrelated result of the stream operation anyway. Further you can simplify this to `.mapToObj(i -> Stream.of(A[i], "*".equals(B[i])? B[i]: doSomethingWith(B[i])) .flatMap(Function.identity())` – Holger Jan 16 '18 at 16:01
-2

Try something like this:

 String[] A;
 String[] B;
 //...
 List<String> myList= Arrays.asList (A);
 List<String> myList2 = Arrays.stream(B).map(
    (x)->"*".equals(x) ? x : doSomethingWith(x))
    .collect(Collectors.toList());
 myList.addAll(myList2);