Dev*_*abc 10 java loops while-loop optional java-8
在我的一些项目中,我经常使用do-while-checkNextForNull-getNext循环模式(不知道它是否有正式名称).但是在Java8中,使用Optional比在客户端代码中检查空引用更清晰.但是当在这个循环模式中使用Optional时,代码有点冗长和丑陋,但是因为Optional有一些方便的方法,我希望必须存在比我下面提到的方法更清晰的方法.
例:
鉴于以下课程.
class Item {
int nr;
Item(nr) {
this.nr = nr;
// an expensive operation
}
Item next() {
return ...someCondition....
? new Item(nr + 1)
: null;
}
}
Run Code Online (Sandbox Code Playgroud)
其中第一个项目始终具有nr == 1并且每个项目确定下一个项目,并且您不希望创建不必要的新项目.
我可以在客户端代码中使用以下循环do-while-checkNextForNull-getNext模式:
Item item = new Item(1);
do {
// do something with the item ....
} while ((item = item.next()) != null);
Run Code Online (Sandbox Code Playgroud)
使用Java8-Optional,给定的类变为:
class Item {
....
Optional<Item> next() {
return ...someCondition....
? Optional.of(new Item(nr + 1))
: Optional.empty();
}
}
Run Code Online (Sandbox Code Playgroud)
然后do-while-checkNextForNull-getNext循环模式变得有点丑陋和冗长:
Item item = new Item(1);
do {
// do something with the item ....
} while ((item = item.next().orElse(null)) != null);
Run Code Online (Sandbox Code Playgroud)
这orElse(null)) != null部分感觉不舒服.
我寻找其他类型的循环,但没有找到更好的循环.有更清洁的解决方案吗?
可以使用for-each循环,同时避免空引用(使用null引用被认为是一种不好的做法).该解决方案由Xavier Delamotte提出,不需要Java8-Optional.
使用通用迭代器实现:
public class Item implements Iterable<Item>, Iterator<Item> {
int nr;
Item(int nr) {
this.nr = nr;
// an expensive operation
}
public Item next() {
return new Item(nr + 1);
}
public boolean hasNext() {
return ....someCondition.....;
}
@Override
public Iterator<Item> iterator() {
return new CustomIterator(this);
}
}
Run Code Online (Sandbox Code Playgroud)
和
class CustomIterator<T extends Iterator<T>> implements Iterator<T> {
T currentItem;
boolean nextCalled;
public CustomIterator(T firstItem) {
this.currentItem = firstItem;
}
@Override
public boolean hasNext() {
return currentItem.hasNext();
}
@Override
public T next() {
if (! nextCalled) {
nextCalled = true;
return currentItem;
} else {
currentItem = currentItem.next();
return currentItem;
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后客户端代码变得非常简单/干净:
for (Item item : new Item(1)) {
// do something with the item ....
}
Run Code Online (Sandbox Code Playgroud)
虽然这可能被视为违反Iterator合同,因为该new Item(1)对象包含在循环中,而通常,for循环会立即调用next()并因此跳过第一个对象.换句话说:对于第一个对象,违反了next(),因为它返回第一个对象本身.
Era*_*ran 10
你可以这样做:
Optional<Item> item = Optional.of(new Item(1));
do {
Item value = item.get();
// do something with the value ....
} while ((item = value.next()).isPresent());
Run Code Online (Sandbox Code Playgroud)
或(避免额外变量):
Optional<Item> item = Optional.of(new Item(1));
do {
// do something with item.get() ....
} while ((item = item.get().next()).isPresent());
Run Code Online (Sandbox Code Playgroud)
在Java8中,使用Optional比在客户端代码中检查空引用更清晰
不,它是另一种方式:可以在有助于编写更清晰代码的地方使用可选项.如果没有,只要坚持旧的习语.如果你现有的成语看起来很好的话,不要觉得有任何使用它的压力 - 在我看来它确实如此.作为一个例子,这将是可选的良好用法:
item.next().map(Object::toString).ifPresent(System.out::println);
Run Code Online (Sandbox Code Playgroud)
由于你需要在第一个不存在的Optional上跳出循环,这实际上没有用.
但是,我认为您的真正兴趣更为通用:为您的代码利用Java 8的功能.你应该选择的抽象是Stream:
itemStream(() -> new Item(1)).forEach(item -> { ... all you need ... });
Run Code Online (Sandbox Code Playgroud)
当然,您现在可以通过流处理来实现:
itemStream(() -> new Item(1)).filter(item.nr > 3).mapToInt(Item::nr).sum();
Run Code Online (Sandbox Code Playgroud)
这是你构建流的方法:
import java.util.Spliterators;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
public class ItemSpliterator extends Spliterators.AbstractSpliterator<Item>
{
private Supplier<Item> supplyFirst;
private Item lastItem;
public ItemSpliterator(Supplier<Item> supplyFirst) {
super(Long.MAX_VALUE, ORDERED | NONNULL);
this.supplyFirst = supplyFirst;
}
@Override public boolean tryAdvance(Consumer<? super Item> action) {
Item item;
if ((item = lastItem) != null)
item = lastItem = item.next();
else if (supplyFirst != null) {
item = lastItem = supplyFirst.get();
supplyFirst = null;
}
else return false;
if (item != null) {
action.accept(item);
return true;
}
return false;
}
public static Stream<Item> itemStream(Supplier<Item> supplyFirst) {
return StreamSupport.stream(new ItemSpliterator(supplyFirst), false);
}
}
Run Code Online (Sandbox Code Playgroud)
有了这个,您距离无缝并行化计算的能力只有一步之遥.由于您的项目流基本上是顺序的,我建议查看我关于此主题的博客文章.