什么是迭代两个流并将操作应用于一个流的更好方法

时间:2016-04-17 04:45:25

标签: java-8 java-stream

如果有人能想出更好的方式来表达它,我会很感激标题的编辑。

我有一个代表具有容量的集合的类。

我的代码是

public class PlayerParty implements Party {

    public PlayerParty() {
        this(Collections.emptyList());
    }

    public PlayerParty(Collection<Pokemon> pokemon) {
        Objects.requireNonNull(pokemon, "pokemon must not be null");
        if (pokemon.size() > PARTY_LIMIT) {
            throw new IllegalArgumentException(String.format(PARTY_LIMIT_EXCEEDED, PARTY_LIMIT));
        }

        createPartySlots();
        fillPartySlots(pokemon);
    }

    @Override
    public final Iterable<Pokemon> getPokemon() {
        return Collections.unmodifiableCollection(
               partySlots
                   .stream()
                   .filter(PartySlot::isFull)
                   .map(PartySlot::getPokemon)
                   .collect(Collectors.toList()));
    }

    public final Optional<PartySlot> getNextSlot() {
        return partySlots
                   .stream()
                   .filter(slot -> !slot.isFull())
                   .findFirst();
    }

    private void createPartySlots() {
        for (int i = 0; i < PARTY_LIMIT; i++) {
            partySlots.add(new PartySlot());
        }
    }

    private void fillPartySlots(Iterable<Pokemon> pokemon) {
        pokemon.forEach(p -> {
            // Since we just added all of the slots, they're
            // guaranteed to be present
            // noinspection OptionalGetWithoutIsPresent
            PartySlot slot = getNextSlot().get();
            slot.fill(p);
            partySlots.add(slot);
        });
    }

    private static final String PARTY_LIMIT_EXCEEDED = "party cannot have more than %s Pokemon";
    private static final int PARTY_LIMIT = 6;
    private final List<PartySlot> partySlots = new ArrayList<>();
}

有问题的方法围绕fillPartySlots

PartySlot slot = getNextSlot().get();行上,我收到一条警告,提示我在没有先致电get的情况下致电isPresent。这是可以理解的,因为通常我想在尝试从Optional中获取值之前这样做。

是否有更好的方法可以根据另一个流的状态对一个流执行操作?也就是说,我可以更改它以便它使用isPresent(在此方法中应始终为true,因为构造函数中的先前调用会创建它们)?我可以做点什么吗

partySlots
    .stream()
    .filter(slot -> !slot.isFull()) // should return true for all slots
    .forEach(slot -> {
        slot.fill(nextAvailableOneFromMethodParameter?);
    });

1 个答案:

答案 0 :(得分:2)

如果缺少值的情况表示错误,则可以在不检查.get()的情况下调用.isPresent()。如果该值不存在,.get()将以NoSuchElementException快速失败,这是您可能想要的。

您可能希望使用.orElseThrow(...)代替.get()在代码中更清楚地记录,但这是首选问题。

另一方面,您使用.filter(slot -> !slot.isFull())的建议代码将默默地忽略插槽已满的情况,并使此类错误更难找到。此外,替代实现在插槽上迭代而不是在提供的小精灵上进行迭代,但如果口袋妖怪少于插槽那么会怎样呢?

顺便说一句,你有充分的理由使用Iterable吗? CollectionList可能是更合适的选择。考虑将此帖子发布到code review