1

I've a list of items. I want to process a set of items which are in the middle of the list. Ex: Assume a list of employees who have id, first name, last name and middle name as attributes. I want to consider all rows between lastName "xxx" and "yyy" and process them further. How can this be optimized in Java8? Optimization is my first concern. Tried using Java8 streams and parallel streams. But termination(break) is not allowed in foreach loop in Java8 streams. Also we cannot use the outside("start" variable below) variables inside foreach. Below is the code which I need to optimize:

boolean start = false;
for(Employee employee: employees) {
    if(employee.getLastname().equals("yyy")) {
        break;
    } 
    if(start) {
    // My code to process
    }
    if(employee.getLastname().equals("xxx")) {
        start = true;
    }
}

What is the best way to handle the above problem in Java8?

Holger
  • 285,553
  • 42
  • 434
  • 765
User1230321
  • 1,435
  • 4
  • 23
  • 39

1 Answers1

1

That is possible in java-9 via (I've simplified your example):

Stream.of(1, 2, 3, 4, 5, 6)
            .dropWhile(x -> x != 2)
            .takeWhile(x -> x != 6)
            .skip(1)
            .forEach(System.out::println);

This will get the values in the range 2 - 6, that is it will print 3,4,5.

Or for your example:

employees.stream()
         .dropWhile(e -> e.getLastname().equals("xxx"))
         .takeWhile(e -> e.getLastname().equals("yyy"))
         .skip(1)
         .forEach(....)

There are back-ports for dropWhile and takeWhile, see here and here

EDIT

Or you can get the indexes of those delimiters first and than do a subList (but this assumes that xxx and yyy are unique in the list of employees):

int[] indexes = IntStream.range(0, employees.size())
            .filter(x -> list.get(x).getLastname().equals("xxx") || list.get(x).getLastname().equals("yyy"))
            .toArray();

employees.subList(indexes[0] + 1, indexes[1])
            .forEach(System.out::println);
Eugene
  • 117,005
  • 15
  • 201
  • 306
  • Do you mean to say that optimization of the above code is not possible in Java8? Whatever the primitive code I've written is the only solution here because I cannot go with Java9 at all. – User1230321 Sep 24 '18 at 09:30
  • @User1230321 see edit, there are back-ports of those in java-8 – Eugene Sep 24 '18 at 09:31
  • Your second variant only works, if the `"yyy"` last name is unique. – Holger Sep 24 '18 at 10:56
  • @Holger agreed... or `xxx` is unique too. I'll add that to the answer – Eugene Sep 24 '18 at 11:04
  • Well, if `xxx` is not unique, your code still does the same as the original code (only skip the first occurrence), though, it should be `.dropWhile(e -> !e.getLastname().equals("xxx"))`. But it’s behavioral different for multiple `yyy`s. – Holger Sep 24 '18 at 11:05
  • Oh, my last comment assumed you used `indexes[indexes.length -2]` rather than `indexes[1]`. I should read with more care. – Holger Sep 24 '18 at 11:26
  • 2
    So, to reproduce the OP’s code behavior, you could use `int size = employees.size(), start = IntStream.range(0, size) .filter(x -> employees.get(x).getLastname().equals("xxx")) .findFirst().orElse(size - 1) + 1, end = IntStream.range(start, size) .filter(x -> employees.get(x).getLastname().equals("yyy")) .findFirst().orElse(size);`, followed by `employees.subList(start, end).forEach(System.out::println);` – Holger Sep 24 '18 at 11:31
  • For this, you've to walk through the array twice which is not optimized solution I assume. What do you say? – User1230321 Sep 24 '18 at 14:41
  • @User1230321 this is really doubtful; I mean you have some branching inside your code via `if/else` too... so this has to be measured first, before it's judged. Usually traversing an list/array is not as slow as people tend to think – Eugene Sep 24 '18 at 14:45
  • @User1230321 did my answer help you here btw? – Eugene Sep 27 '18 at 10:18
  • @Eugene: It's almost similar. Around 10ms of difference is there. That's all. – User1230321 Sep 29 '18 at 12:20