What you want to do is go through two lists at the same name. The generic name for this operation is "zip" - when you go through two (or sometimes more) arrays/lists/streams/etc and do something with each element.
You can pick an implementation for streams from here: Zipping streams using JDK8 with lambda (java.util.stream.Streams.zip) there are many that are already implemented in existing libraries, as well. If you already have such a library in your project, you need but an import to use it.
For illustrative purposes, I'll assume there is an implementation available with this signature:
<A, B, C> Stream<C> zip(Stream<? extends A> a,
Stream<? extends B> b,
BiFunction<? super A, ? super B, ? extends C> zipper)
Also, a good simple generic utility would be a Pair
class that has two values. There are many existing implementations. I'll an implementation with this this signature is available:
class Pair<LEFT, RIGHT> {
Pair(LEFT left, RIGHT right);
LEFT getLeft();
RIGHT getRight();
}
This will hold the related state and address type. But you can also consider creating a specific object that encapsulates a given state and address type.
With these generic helpers, your code can look like this:
Stream<String> states = Arrays.stream(item.getState().split(","));
Stream<String> addressType = Arrays.stream(item.getAddressType().split(","));
Map<Boolean, List<String>> splitStates = zip(states, addressTypes,
(state, addressType) -> new Pair<String, String>(state, addressType))
.collect(
Collectors.partitioningBy(pair -> Constants.MAILING.equals(pair.getRight()),
collectors.mapping(pair -> pair.getLeft())
)
);
List<String> mailingStates = split.get(true);
List<String> physicalStates = split.get(false);
If lambdas are replaced with method references and some minor rearrangement when possible, then you get:
private static final Predicate<Pair<String, String> IS_Mailing =
pair -> Constants.MAILING.equals(pair.getRight());
/* ... */
Stream<String> states = Arrays.stream(item.getState().split(","));
Stream<String> addressType = Arrays.stream(item.getAddressType().split(","));
Map<Boolean, List<String>> splitStates = zip(states, addressTypes, Pair::new)
.collect(Collectors.partitioningBy(IS_MAILING),
collectors.mapping(Pair::getLeft()));
List<String> mailingStates = split.get(true);
List<String> physicalStates = split.get(false);
And if instead of generic Pair
class you implement a class like:
class StateData {
private String state;
private String addressType;
public StateData(String state, String addressType) {
this.state = state;
this.addressType = addressType;
}
public String getState() { return this.state; }
public String getAddressType() { return this.addressType; }
public boolean isMailing() {
return Constants.MAILING.equals(this.getAddressType());
}
}
The code becomes more semantic:
Stream<String> states = Arrays.stream(item.getState().split(","));
Stream<String> addressType = Arrays.stream(item.getAddressType().split(","));
Map<Boolean, List<String>> splitStates = zip(states, addressTypes, StateData::new)
.collect(Collectors.partitioningBy(StateData::isMailing),
collectors.mapping(StateData::getState()));
List<String> mailingStates = split.get(true);
List<String> physicalStates = split.get(false);
One final consideration would be to create an enum for addressType
instead of comparing to a constant.