Bharat Bhagat
Bharat Bhagat

Reputation: 501

Is it possible to replace a simple java for loop (with index) with java 8 stream

I want to have failfast behavior for any unsuccessful response and if all go successful then I return the last successful response as shown in following code.

for(int i=0;i<input.size(); i++){
   Data data = service.getData(input.get(i));
   if(data.isSuccessful() && i==input.size()-1){
      return data;
   }else if(!data.isSuccessful()){
    return data;
    }else{
    return null;
  }
 }

I tried to replace above mention code with streams but not been able to do so far.Main issue is that I am not able to imitate i(index) variable behavior in java8 stream code.

resp = input.stream().map((input)->{service.getData()}).filter(
(resp)->{
     if(!resp.isSuccessful())
        return true; 
     else if(resp.isSuccessful() && last resp)//if somehow I figure out last element
        return true;
     else 
        return false;}).findFirst();

Upvotes: 3

Views: 4883

Answers (2)

slartidan
slartidan

Reputation: 21576

There is no need for external libraries.

return IntStream.range(0, input.size())
.mapToObj(i -> {
    Data data = service.getData(input.get(i));
    if (!data.isSuccessful() || i == input.size() - 1) {
        return Optional.of(data);
    }
    return Optional.<Data>empty();
})
.filter(Optional::isPresent)
.findFirst()
.orElse(null);

Complete example (compilable):

import java.util.Optional;
import java.util.stream.IntStream;

class Data {
    public boolean isSuccessful() {return false;}
}
class Input {
    public Object get(int i) {return null;}
    public int size() {return 0;}
}
class Service {
    public Data getData(Object object) {return null;}
}
public class T {
    public static void main(String[] args) {method();}

    protected static Optional<Data> method() {
        Input input = new Input();
        Service service = new Service();

        return IntStream.range(0, input.size())
                .mapToObj(i -> {
                    Data data = service.getData(input.get(i));
                    if (!data.isSuccessful() || i == input.size() - 1) {
                        return Optional.of(data);
                    }
                    return Optional.<Data>empty();
                })
                .filter(Optional::isPresent)
                .findFirst()
                .orElse(null);
    }
}

Upvotes: 9

Tagir Valeev
Tagir Valeev

Reputation: 100209

Seems that you actually want the following:

for (int i = 0; i < input.size(); i++) {
    Data data = service.getData(input.get(i));
    if (!data.isSuccessful() || i == input.size() - 1) {
        return data;
    }
}
return null;

The shortest lambda-based solution I can propose involves the jOOλ library:

return Seq.seq(input)
          .map(service::getData)
          .limitWhileClosed(Data::isSuccessful)
          .reduce((a, b) -> b)
          .orElse(null);

The essential part here is limitWhileClosed method which takes the input element while the condition holds, but also includes the first element which violates the condition. After that we use reduce((a, b) -> b) to get the last taken element.

The limitWhileClosed method is absent in Java-8 Stream API. Java-9 will add the takeWhile which is similar, but does not include the violating element. So the pure Stream API solution would be much uglier than plain for loop.

Upvotes: 4

Related Questions