如何在可选执行的逻辑,如果不存在?

问题描述 投票:55回答:9

我想用java8 Optional替换下面的代码:

public Obj getObjectFromDB() {
    Obj obj = dao.find();
    if (obj != null) {
        obj.setAvailable(true);
    } else {
        logger.fatal("Object not available");
    }

    return obj;
}

下面的伪代码不工作,因为没有orElseRun方法,但不管怎么说它说明我的目的:

public Optional<Obj> getObjectFromDB() {
    Optional<Obj> obj = dao.find();
    return obj.ifPresent(obj.setAvailable(true)).orElseRun(logger.fatal("Object not available"));
}
java java-8 optional
9个回答
93
投票

在Java 9或更高,ifPresentOrElse是最有可能你想要什么:

Optional<> opt = dao.find();

opt.ifPresentOrElse(obj -> obj.setAvailable(true),
                    () -> logger.error("…"));

柯里使用vavr或类似可能会甚至更整洁的代码,但我还没试过。


33
投票

我不认为你可以在一个声明中做到这一点。做的更好:

if (!obj.isPresent()) {
    logger.fatal(...);   
} else {
    obj.get().setAvailable(true);
}
return obj;

10
投票

你将不得不把它们分割多个语句。这里是做的一个方法:

if (!obj.isPresent()) {
  logger.fatal("Object not available");
}

obj.ifPresent(o -> o.setAvailable(true));
return obj;

另一种方法(可能是过度设计)是使用map

if (!obj.isPresent()) {
  logger.fatal("Object not available");
}

return obj.map(o -> {o.setAvailable(true); return o;});

如果obj.setAvailable方便地返回obj,那么你可以简单的第二个例子来:

if (!obj.isPresent()) {
  logger.fatal("Object not available");
}

return obj.map(o -> o.setAvailable(true));

9
投票

首先,你dao.find()要么返回一个Optional<Obj>否则你就必须创建一个。

EG

Optional<Obj> = dao.find();

或者你可以自己做,如:

Optional<Obj> = Optional.ofNullable(dao.find());

如果目前这一将返回Optional<Obj>或者如果不存在Optional.empty()

所以,现在让我们来解决,

public Obj getObjectFromDB() {
   return Optional.ofNullable(dao.find()).flatMap(ob -> {
            ob.setAvailable(true);
            return Optional.of(ob);    
        }).orElseGet(() -> {
            logger.fatal("Object not available");
            return null;
        });
    }

这就是你要找的人班轮:)


9
投票

对于Java 8 Spring提供ifPresentOrElse从“实用方法与选配工作”,实现你想要什么。例子:

import static org.springframework.data.util.Optionals.ifPresentOrElse;    

ifPresentOrElse(dao.find(), obj -> obj.setAvailable(true), () -> logger.fatal("Object not available"));

5
投票

有一个.orElseRun方法,但它被称为.orElseGet,问题是,不像.map.isPresent不返回Optional<Obj>

如果你真的想这样做在一个声明,这是可能的:

public Obj getObjectFromDB() {
    return dao.find()
        .map( obj -> { 
            obj.setAvailable(true);
            return Optional.of(obj); 
         })
        .orElseGet( () -> {
            logger.fatal("Object not available"); 
            return Optional.empty();
    });
}

但是,这是不是你有什么之前,甚至笨重。


1
投票

我能想出了一对夫妇的“一条线”的解决方案,例如:

    obj.map(o -> (Runnable) () -> o.setAvailable(true))
       .orElse(() -> logger.fatal("Object not available"))
       .run();

要么

    obj.map(o -> (Consumer<Object>) c -> o.setAvailable(true))
       .orElse(o -> logger.fatal("Object not available"))
       .accept(null);

要么

    obj.map(o -> (Supplier<Object>) () -> {
            o.setAvailable(true);
            return null;
    }).orElse(() () -> {
            logger.fatal("Object not available")
            return null;
    }).get();

它看起来并不很漂亮,像orElseRun会好很多,但我认为与Runnable的这种选择是可以接受的,如果你真的想要一个在线解决方案。


0
投票

你需要Optional.isPresent()orElse()。您的片段赢得;吨的工作,因为它不一样,如果不存在任何回报。

可选的点是从方法返回。


-2
投票

我想你不能改变dao.find()方法返回Optional<Obj>的一个实例,因此你必须自己创造一个合适的。

下面的代码应该帮助你。我已经创建类OptionalAction,它提供的if-else机制为您服务。

public class OptionalTest
{
  public static Optional<DbObject> getObjectFromDb()
  {
    // doa.find()
    DbObject v = find();

    // create appropriate Optional
    Optional<DbObject> object = Optional.ofNullable(v);

    // @formatter:off
    OptionalAction.
    ifPresent(object)
    .then(o -> o.setAvailable(true))
    .elseDo(o -> System.out.println("Fatal! Object not available!"));
    // @formatter:on
    return object;
  }

  public static void main(String[] args)
  {
    Optional<DbObject> object = getObjectFromDb();
    if (object.isPresent())
      System.out.println(object.get());
    else
      System.out.println("There is no object!");
  }

  // find may return null
  public static DbObject find()
  {
    return (Math.random() > 0.5) ? null : new DbObject();
  }

  static class DbObject
  {
    private boolean available = false;

    public boolean isAvailable()
    {
      return available;
    }

    public void setAvailable(boolean available)
    {
      this.available = available;
    }

    @Override
    public String toString()
    {
      return "DbObject [available=" + available + "]";
    }
  }

  static class OptionalAction
  {
    public static <T> IfAction<T> ifPresent(Optional<T> optional)
    {
      return new IfAction<>(optional);
    }

    private static class IfAction<T>
    {
      private final Optional<T> optional;

      public IfAction(Optional<T> optional)
      {
        this.optional = optional;
      }

      public ElseAction<T> then(Consumer<? super T> consumer)
      {
        if (optional.isPresent())
          consumer.accept(optional.get());
        return new ElseAction<>(optional);
      }
    }

    private static class ElseAction<T>
    {
      private final Optional<T> optional;

      public ElseAction(Optional<T> optional)
      {
        this.optional = optional;
      }

      public void elseDo(Consumer<? super T> consumer)
      {
        if (!optional.isPresent())
          consumer.accept(null);
      }
    }
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.