Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用Java8时执行可选操作_Java_Loops_While Loop_Java 8_Optional - Fatal编程技术网

使用Java8时执行可选操作

使用Java8时执行可选操作,java,loops,while-loop,java-8,optional,Java,Loops,While Loop,Java 8,Optional,在我的一些项目中,我经常使用DowhileCheckNextForFullGetNext循环模式(不知道是否有正式名称)。但是在Java8中,使用Optional被认为比检查客户机代码中的空引用更干净。但是当在这种循环模式中使用Optional时,代码会变得有点冗长和丑陋,但是因为Optional有一些方便的方法,我希望一定存在一种比我下面提出的更干净的方法 例如: 给定以下类 class Item { int nr; Item(nr) { this.nr =

在我的一些项目中,我经常使用DowhileCheckNextForFullGetNext循环模式(不知道是否有正式名称)。但是在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;
    }
}
其中第一个项目的nr==1,每个项目决定下一个项目,并且您不希望创建不必要的新项目

在客户端代码中选中NextForFull getNext模式时,我可以使用以下循环方式:

Item item = new Item(1);
do {
    // do something with the item ....
} while ((item = item.next()) != null);
使用Java8 Optional,给定的类变为:

class Item {
    ....

    Optional<Item> next() {
        return ...someCondition....
            ? Optional.of(new Item(nr + 1))
            : Optional.empty();
    }
}
orElse(null))!=空
零件感觉不舒服

我已经寻找了其他类型的循环,但没有找到更好的循环。有更清洁的解决方案吗

更新: 可以对每个循环使用一个for,同时避免空引用(使用空引用被认为是一种不好的做法)。此解决方案由Xavier Delamotte提出,不需要Java8可选

使用通用迭代器实现:

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);
    }
}

尽管这可能被视为违反迭代器约定,因为循环中包含
新项(1)
对象,但通常情况下,for循环会立即调用next(),从而跳过第一个对象。换句话说:对于第一个对象,next()被违反,因为它返回第一个对象本身。

您可以这样做:

Optional<Item> item = Optional.of(new Item(1));
do {
    Item value = item.get();
    // do something with the value ....
} while ((item = value.next()).isPresent());
Optional item=Optional.of(新项(1));
做{
Item value=Item.get();
//做一些有价值的事情。。。。
}while((item=value.next()).isPresent());
或者(为了避免额外的变量):

Optional item=Optional.of(新项(1));
做{
//对item.get()执行某些操作。。。。
}while((item=item.get().next()).isPresent());
在Java8中,使用Optional被认为比检查客户机代码中的空引用更干净

不,这是另一种方式:可选的可以用来帮助编写更干净的代码。如果没有的话,就坚持老习惯用语。在我看来,如果你现有的习语看起来不错,而且确实不错,那么不要觉得有压力去使用它。例如,这将是对可选选项的良好使用:

item.next().map(Object::toString).ifPresent(System.out::println);
因为您需要在第一个不存在的可选项上打破循环,所以这并没有真正的帮助

然而,我认为您真正感兴趣的是更普遍的:在代码中利用Java8的特性。您应该选择的抽象是流:

itemStream(() -> new Item(1)).forEach(item -> { ... all you need ... });
而且,很自然,您现在可以使用流处理:

itemStream(() -> new Item(1)).filter(item.nr > 3).mapToInt(Item::nr).sum();
以下是构建流的方式:

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);
  }
}
导入java.util.Spliterators;
导入java.util.function.Consumer;
导入java.util.function.Supplier;
导入java.util.stream.stream;
导入java.util.stream.StreamSupport;
公共类ItemSpliterator扩展了Spliterators.AbstractSpliterator
{
私人供应商优先供应;
私人物品;
公用项目拆分器(供应商供应优先){
super(Long.MAX_值,有序|非空);
this.supplyFirst=supplyFirst;
}

@覆盖公共布尔tryAdvance(使用者只需将循环支持添加到API中:

class Item {
    int nr;

    Item(int nr) {
        this.nr = nr;
        // an expensive operation
    }

    public void forEach(Consumer<Item> action) {
        for(Item i=this; ; i=new Item(i.nr + 1)) {
            action.accept(i);
            if(!someCondition) break;
        }
    }
    public Optional<Item> next() {
        return someCondition? Optional.of(new Item(nr+1)): Optional.empty();
    }
}
或方法引用

    i.forEach(System.out::println);

如果您想支持比forEach循环更复杂的操作,这是正确的方法。类似的是,您的实现封装了如何在
项上迭代。

,因为这与我在下面设计中提出的某种设计有关

创建支持提供可选下一步的接口

public interface NextProvidble<T> {

    Optional<T> next();
}
公共接口下一步提供{
可选的next();
}
项目实现NextProvidble接口

public class Item implements NextProvidble<Item> {
    int nr;

    Item(int nr) {
        this.nr = nr;
        // an expensive operation
    }

    @Override
    public Optional<Item> next() {
        return /*...someCondition....*/ nr < 10 ? Optional.of(new Item(nr + 1)) : Optional.empty();
    }

    @Override
    public String toString() {
        return "NR : " + nr;
    }
}
public类项实现NextProvidble{
国际天然气公司;
项目(国际编号){
这个。nr=nr;
//昂贵的手术
}
@凌驾
公共可选下一步(){
return/*…someCondition….*/nr<10?可选。of(新项(nr+1)):可选。空();
}
@凌驾
公共字符串toString(){
返回“NR:+NR;
}
}
这里我使用/…someCondition…../as nr<10

和自定义Do的新类,如下所示

public abstract class CustomDoWhile<T extends NextProvidble<T>> {

    public void operate(T t) {
        doOperation(t);
        Optional<T> next = t.next();
        next.ifPresent( nextT -> operate(nextT));
    }

    protected abstract void doOperation(T t);
}
公共抽象类CustomDoWhile{
公共无效操作(T){
操作(t);
可选的next=t.next();
next.ifPresent(nextT->operate(nextT));
}
受保护的抽象无效操作(T);
}
现在,您必须在客户端代码中执行哪些操作

 new CustomDoWhile<Item>() {
            @Override
            protected void doOperation(Item item) {
                System.out.println(item.toString());
            }
        }.operate(new Item(1));
newcustomdowhile(){
@凌驾
受保护的无效操作(项目){
System.out.println(item.toString());
}
}.操作(新项目(1));
这可能很清楚。
请添加您的想法。

在此处删除另一个自那时起可用的备选方案


其中,
doSomething(Item Item)
是对该项执行某些操作的方法。

您真的必须使用此模式吗?您是否可以将类实现为
Iterable
,并为您提供一个
迭代器
?您只需实现
hasNext()
(这是您当前的布尔条件)和
next
,而不是只实现
next()
@XavierDelamotte agree,这闻起来像(又一个)过度使用Java8功能集。不过,这是一个很好的问题,OP.@XavierDelamotte
迭代器
在基于IO的源代码上实现是出了名的笨拙。要想知道它是否
有下一个
,它实际上必须读取和缓存下一个元素。类似光标的习惯用法,只依赖于单个方法,实际上是首选的。例如e、
Spliterator
使用了这种方法,还有一个额外的扭曲。@MarkoTopolnik确实如此。然而,Guava提供了使用AbstractIterator来简化i
    i.forEach(System.out::println);
public interface NextProvidble<T> {

    Optional<T> next();
}
public class Item implements NextProvidble<Item> {
    int nr;

    Item(int nr) {
        this.nr = nr;
        // an expensive operation
    }

    @Override
    public Optional<Item> next() {
        return /*...someCondition....*/ nr < 10 ? Optional.of(new Item(nr + 1)) : Optional.empty();
    }

    @Override
    public String toString() {
        return "NR : " + nr;
    }
}
public abstract class CustomDoWhile<T extends NextProvidble<T>> {

    public void operate(T t) {
        doOperation(t);
        Optional<T> next = t.next();
        next.ifPresent( nextT -> operate(nextT));
    }

    protected abstract void doOperation(T t);
}
 new CustomDoWhile<Item>() {
            @Override
            protected void doOperation(Item item) {
                System.out.println(item.toString());
            }
        }.operate(new Item(1));
Stream.iterate(new Item(1), Item::hasNext, Item::next)
      .forEach(this::doSomething)