Java可选和orElse

时间:2019-08-27 12:36:50

标签: java optional

我是Java可选对象的新手,但我看到此代码是由另一个开发人员编写的,但我没有得到它:

String t = null;
Optional.ofNullable("notnull")
    .orElse(
        Optional.ofNullable(t).orElseThrow(() -> new Exception("MyException"))
    );

为什么此代码引发异常?为什么甚至转到“ orElse”分支?

这是因为执行顺序有些奇怪吗?那么在评估orElse分支之前是否未设置第一个可选值?

7 个答案:

答案 0 :(得分:8)

Optional.ofNullable(t).orElseThrow(() -> new Exception("MyException")) 流从不会被调用,但是方法本身会被执行。这意味着方法参数也将传递给它。因此,无论传递给第一个Optional.ofNullable("notnull").orElse(...) 调用的值如何,都将调用orElse部分。

如果您不希望发生这种情况,则需要通过Optional.ofNullable(t).orElseThrow(() -> new Exception("MyException")),如下所示:

Optional.ofNullable

仅在调用Supplier流时才调用供应商。 请注意,您需要一个String t = null; Optional.ofNullable("notnull") .orElseGet( () -> Optional.ofNullable(t).orElseThrow(() -> new RuntimeException("MyException")) ); 而不是已检查的异常,才能从供应商处中断。

答案 1 :(得分:5)

这是因为 orElse() 中的代码将始终被评估。换句话说,即使您指定了非空的Optional,它也会被执行,这就是抛出public static void main(String[] args) { try (Scanner in = new Scanner(System.in)) { Integer no; do { // this is some flaky code but it works for this purpose try { no = Integer.parseInt(in.nextLine()); break; } catch (Exception e) { System.out.println("please enter only a numeric value"); } } while (true); System.out.println("You entered string " + no); int z = 0, y = 0; char[][] arr = new char[no][]; for (z = 0; z < no; z++) { String s = in.nextLine(); String[] arrOfStr = s.split(""); arr[z] = new char[arrOfStr.length]; for (y = 0; y < arrOfStr.length; y++) { System.out.println(); arr[z][y] = arrOfStr[y].charAt(0); } } for (char[] charArr : arr) { for (char c : charArr) { System.out.println(c); } } } } 的原因。

如果您查看 Java Optional – orElse() vs orElseGet() 文章的Exception部分,则可以在他们的示例中看到以下内容:

  

即使具有非空的Optional,我们也可以轻松推断出orElse()的参数是经过评估的。

答案 2 :(得分:3)

您写的是这样的:

String t = null;
String myException = Optional.ofNullable(t).orElseThrow(() -> new Exception("MyException"));
Optional.ofNullable("notnull").orElse(myException);

orElse的{​​{1}}部分进行评估,然后才知道您的值是否为空。如果要进行Optional评估,请考虑"Lazy"方法。

答案 3 :(得分:2)

问题按执行顺序。 它正在尝试计算.orElse(...)的值,并在.orElseThrow上抛出MyException。

换句话说,如果t不为null,则执行流程如下:

1)计算

的值
<Dialog.Container visible={this.state.dialogVisible} contentStyle={{height: 300, width: 300, paddingBottom: 105}}>

    <Dialog.Title>Edit Your Note</Dialog.Title>

    <Dialog.Input paddingHorizontal = "0%" height = "100%" width="100%" multiline={true} onChangeText={(nm) => 
         this.setState({ newNote: nm })}
            value={this.state.newNote}></Dialog.Input>

    <Dialog.Button label="Cancel" onPress={() => this.handleCancel(e.ans)} />
    <Dialog.Button label="Save" onPress={() => this.handleSave(e.idx, e.ans)} />

</Dialog.Container>

2)使用

中(1)的值
.*(?:https?:\/\/)?(?:www\.)?[a-z-]+\.(?:com|org)(?:\.[a-z]{2,3})?.*

答案 4 :(得分:2)

之所以可以得到预期的结果,是因为在Java中,在调用带有参数的方法之前,JVM在评估参数值之前所做的事情。
这就是select top 100 ih.streetname, ih.district, s.value from vw_pn_intervalshouse ih inner join vw_pn_street s on s.id = ih.streetname CROSS APPLY STRING_SPLIT(ih.intervalhouse, ',') s; 调用的参数值:

.orElse()

由于Optional.ofNullable(t).orElseThrow(() -> new Exception("MyException")) 引用了t,因此会引发异常。

答案 5 :(得分:2)

我真的很想知道为什么以这种方式编写此代码。似乎需要触发一个异常,并在可选项中添加一个明确的NULL值。

如前所述,使用orElse()代替orElseGet()时,无论T的值如何(例如Optional<T>),都会评估该方法。

我会使用一种更好的时尚和色彩搭配:

String value = "notnull"; // could be null
Optional.ofNullable(value)
    .orElseThrow(MyException::new);

如果该值为NULL,则触发异常。

请注意,您可以使用方法引用来调用异常

答案 6 :(得分:2)

关于Optional,您应该注意以下几点:

  1. 如果知道要包装的值是否为空,请使用Optional.of()Optional.empty()。如果不确定(例如,值是您从其他地方获取的变量),请使用Optional.ofNullable()

  2. Optional.orElse()Optional.orElseGet()之间存在重要区别。

    1. orElse取一个已经计算出的值,如果提供了一个表达式,则立即执行该表达式并对其求值。 这正在有问题的代码中发生。因此,应将此else变量用于已经可用的值或基元。

    2. orElseGet采用的供应商功能仅在评估可选链并请求替代值时运行。如果替代值的产生或计算成本很高,则应使用此方法。

    // Fine
    Optional<String> name = Optional.of(someValue).orElse("defaultName");
    
    // But this:
    Optional<String> name = Optional.of(someValue).orElse(db.queryName());
    
    // Is better written as following, as it saves you from an expensive operation
    Optional<String> name = Optional.of(someValue).orElseGet(() -> db.queryName());