java 检查“get”调用链是否为空

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3458451/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 01:56:53  来源:igfitidea点击:

Check chains of "get" calls for null

javanullnullpointerexception

提问by Johnny

Let's say I'd like to perform the following command:

假设我想执行以下命令:

house.getFloor(0).getWall(WEST).getDoor().getDoorknob();

To avoid a NullPointerException, I'd have to do the following if:

为了避免 NullPointerException,如果出现以下情况,我必须执行以下操作:

if (house != null && house.getFloor(0) && house.getFloor(0).getWall(WEST) != null
  && house.getFloor(0).getWall(WEST).getDoor() != null) ...

Is there a way or an already existing Utils class that does this more elegantly, let's say something like the following?

有没有一种方法或者一个已经存在的 Utils 类可以更优雅地做到这一点,让我们说如下?

checkForNull(house.getFloor(0).getWall(WEST).getDoor().getDoorknob());

采纳答案by Jerod Houghtelling

The best way would be to avoidthe chain. If you aren't familiar with the Law of Demeter (LoD), in my opinion you should. You've given a perfect example of a message chain that is overly intimate with classes that it has no business knowing anything about.

最好的方法是避免链条。如果您不熟悉迪米特法则 (LoD),我认为您应该这样做。您已经给出了一个完美的消息链示例,该消息链与它不了解的类过于密切。

Law of Demeter: http://en.wikipedia.org/wiki/Law_of_Demeter

得墨忒耳定律:http: //en.wikipedia.org/wiki/Law_of_Demeter

回答by Johnny

In case you can'tavoid breaking Law of Demeter (LoD) as stated in the chosen answer, and with Java 8introducing Optional, it would be probably the best practice to handle nulls in chains of gets such as yours.

如果您无法避免违反所选答案中所述的德米特法则 (LoD),并且Java 8引入了Optional,那么处理像您这样的获取链中的空值可能是最佳实践。

The Optionaltype will enable you to pipe multiple map operations (which contain get calls) in a row. Null checks are automatically handled under the hood.

Optional类型将使您能够连续管道多个映射操作(包含获取调用)。空检查在引擎盖下自动处理。

For example, when the objects aren't initialized, no print() will be made and no Exceptions will be thrown. It all we be handled gently under the hood. When objects are initialized, a print will be made.

例如,当对象未初始化时,不会进行 print() 并且不会抛出异常。这一切我们都在引擎盖下轻轻处理。当对象被初始化时,将进行打印。

System.out.println("----- Not Initialized! -----");

Optional.ofNullable(new Outer())
        .map(out -> out.getNested())
        .map(nest -> nest.getInner())
        .map(in -> in.getFoo())
        .ifPresent(foo -> System.out.println("foo: " + foo)); //no print

System.out.println("----- Let's Initialize! -----");

Optional.ofNullable(new OuterInit())
        .map(out -> out.getNestedInit())
        .map(nest -> nest.getInnerInit())
        .map(in -> in.getFoo())
        .ifPresent(foo -> System.out.println("foo: " + foo)); //will print!

class Outer {
    Nested nested;
    Nested getNested() {
        return nested;
    }
}
class Nested {
    Inner inner;
    Inner getInner() {
        return inner;
    }
}
class Inner {
    String foo = "yeah!";
    String getFoo() {
        return foo;
    }
}

class OuterInit {
    NestedInit nested = new NestedInit();
    NestedInit getNestedInit() {
        return nested;
    }
}
class NestedInit {
    InnerInit inner = new InnerInit();
    InnerInit getInnerInit() {
        return inner;
    }
}
class InnerInit {
    String foo = "yeah!";
    String getFoo() {
        return foo;
    }
}

So, with your getters chainit will look like this:

因此,使用您的 getters 链,它将如下所示:

Optional.ofNullable(house)
        .map(house -> house.getFloor(0))
        .map(floorZero -> floorZero.getWall(WEST))
        .map(wallWest -> wallWest.getDoor())
        .map(door -> wallWest.getDoor())

The return of it will be something like Optional<Door>which will allow you much safer work without worrying of null exceptions.

它的返回将类似于Optional<Door>它可以让您更安全地工作,而不必担心空异常。

回答by Roman Seleznov

In order to check a chain of gets for nullyou may need to call your code from a closure. The closure call code will look like this:

为了检查 get 链是否为null,您可能需要从闭包中调用您的代码。闭包调用代码如下所示:

public static <T> T opt(Supplier<T> statement) {       
    try {
        return statement.get();
    } catch (NullPointerException exc) {
        return null;
    }   
}

And you call it using the following syntax:

您可以使用以下语法调用它:

Doorknob knob = opt(() -> house.getFloor(0).getWall(WEST).getDoor().getDoorknob());

This code is also type safe and in general works as intended:

此代码也是类型安全的,并且通常按预期工作:

  1. Returns an actual value of the specified type if all the objects in the chain are not null.
  2. Returns nullif any of the objects in the chain are null.
  1. 如果链中的所有对象都不为null,则返回指定类型的实际值。
  2. 如果链中的任何对象为null ,则返回null

You may place optmethod into shared util class and use it everywhere in your application.

您可以将opt方法放入共享的 util 类中,并在您的应用程序中的任何地方使用它。

回答by Bozho

Make sure things that can't logically be nullare not. For example - a house always has a West wall. In order to avoid such exceptions in state, you can have methods to check whether the state you expect is present:

确保逻辑上不可能的事情null不是。例如 - 房子总是有一面西墙。为了避免状态中的此类异常,您可以使用方法来检查您期望的状态是否存在:

if (wall.hasDoor()) {
   wall.getDoor().etc();
}

This is essentially a null-check, but might not always be.

这本质上是一个空检查,但可能并不总是如此。

The point is that you should do something in case you have a null. For example - returnor throw an IllegalStateException

关键是你应该做一些事情,以防你有一个null. 例如 -return或抛出IllegalStateException

And what you shouldn't do - don't catch NullPointerException. Runtime exceptions are not for catching - it is not expected that you can recover from them, nor it is a good practice to rely on exceptions for the logic flow. Imagine that you actually don't expect something to be null, and you catch (and log) a NullPointerException. This will not be very useful information, since many things can be nullat that point.

而你不应该做的——不要抓住NullPointerException。运行时异常不是用于捕获的 - 不希望您可以从它们中恢复,依赖逻辑流的异常也不是一个好习惯。想象一下,您实际上并不期望某事是null,并且您捕获(并记录)了 a NullPointerException。这不会是非常有用的信息,因为null此时可能会有很多事情。

回答by Carl Manaster

You could of course simply wrap the whole expression up in a try-catch block, but that's a bad idea. Something cleaner is the Null object pattern. With that, if your house doesn't have floor 0, it just returns a Floor that acts like a regular Floor, but has no real content; Floors, when asked for Walls they don't have, return similar "Null" Walls, etc, down the line.

您当然可以简单地将整个表达式包装在一个 try-catch 块中,但这是一个坏主意。更简洁的是Null 对象模式。有了这个,如果你的房子没有 0 层,它只会返回一个像普通楼层一样的楼层,但没有真正的内容;楼层,当被要求提供他们没有的墙时,会返回类似的“空”墙等。

回答by Omar Ruiz

implementing nullPointer try/catch with a Supplier you can send it all chain of get

使用供应商实现 nullPointer try/catch 你可以将它发送到所有的 get 链

public static <T> T getValue(Supplier<T> getFunction, T defaultValue) {
    try {
        return getFunction.get();
    } catch (NullPointerException ex) {
        return defaultValue;
    }
}

and then call it in this way.

然后以这种方式调用它。

ObjectHelper.getValue(() -> object1.getObject2().getObject3().getObject4()));

回答by Adriaan Koster

Very old question, but still adding my suggestion:

很老的问题,但仍然添加我的建议:

I would suggest instead of getting the DoorKnob from the House you should try to let the DoorKnob be provided to this class from the calling code, or by creating a central lookup facility specifically for this purpose (e.g. a DoorKnob service)

我建议不要从 House 获取 DoorKnob,您应该尝试从调用代码中将 DoorKnob 提供给此类,或者为此专门创建一个中央查找工具(例如 DoorKnob 服务)

回答by polygenelubricants

There is no checkForNullmethod that you can write that will facilitate this (that's simply not how method invokation and argument evaluation works in Java).

没有checkForNull您可以编写的方法可以促进这一点(这不是 Java 中方法调用和参数评估的工作方式)。

You can break down the chained statements into multiple statements, checking at every step. However, perhaps a better solution is to not have these methods return nullin the first place. There is something called the Null Object Patternthat you may want to use instead.

您可以将链式语句分解为多个语句,并在每一步进行检查。然而,也许更好的解决方案是首先不要让这些方法返回null。有一种叫做空对象模式的东西,你可能想用它来代替。

Related questions

相关问题