Is it possible to LOG different messages based on which step null is encountered while doing nested null check with Optional and map

huangapple go评论94阅读模式
英文:

Is it possible to LOG different messages based on which step null is encountered while doing nested null check with Optional and map

问题

I have a nested object which can return a null at any point of time.

Thanks to Optional and map we can now do nested calls without having to put null checks after every get.

I have a very unique requirement where I need to know at which step exactly did I encounter a null object, for example (Copied from StackOverflow):

  1. Optional.of(new Outer())
  2. .map(Outer::getNested)
  3. .map(Nested::getInner)
  4. .map(Inner::getFoo)
  5. .ifPresent(System.out::println);

How can I LOG a different kind of log message depending on when and where I encounter a null value?

The code below is not valid but I am just trying to explain how it might look like programmatically:

  1. Optional.of(outerObject).else(LOG.error("Outer was null"))
  2. .map(Outer::getNested).else(LOG.error("Nested was null"))
  3. .map(Nested::getInner).else(LOG.error("Inner was null"))
  4. .map(Inner::getFoo).else(LOG.error("Foo was null"))
  5. .ifPresent(System.out::println);
英文:

I have a nested object which can return a null at any point of time.

Thanks to Optional and map we can now do nested calls without having to put null checks after every get.

I have a very unique requirement where I need to know at which step exactly did I encounter a null object for e.g. (Copied from StackOverflow)

  1. Optional.of(new Outer())
  2. .map(Outer::getNested)
  3. .map(Nested::getInner)
  4. .map(Inner::getFoo)
  5. .ifPresent(System.out::println);

How can I LOG a different kind of log message depending on when and where I encounter a null value?

The code below is not valid but I am just trying to explain how it might look like programmatically:

  1. Optional.of(outerObject).else(LOG.error("Outer was null"))
  2. .map(Outer::getNested).else(LOG.error("Nested was null"))
  3. .map(Nested::getInner).else(LOG.error("Inner was null"))
  4. .map(Inner::getFoo).else(LOG.error("Foo was null"))
  5. .ifPresent(System.out::println);

答案1

得分: 1

你可以使用异常处理来实现所需的行为,代码如下:

  1. public class Test {
  2. public static void main(String[] args) {
  3. Outer outer = new Outer(new Nested(new Inner("value")));
  4. // Outer outer = new Outer(new Nested(new Inner(null)));
  5. // Outer outer = new Outer(new Nested(null));
  6. // Outer outer = new Outer(null);
  7. // Outer outer = null;
  8. try {
  9. Optional.ofNullable(outer).or(() -> throwEx("Outer was null"))
  10. .map(Outer::nested).or(() -> throwEx("Nested was null"))
  11. .map(Nested::inner).or(() -> throwEx("Inner was null"))
  12. .map(Inner::foo).or(() -> throwEx("Foo was null"))
  13. .ifPresent(System.out::println);
  14. } catch (NullValueException e) {
  15. System.out.println(e.getMessage());
  16. }
  17. }
  18. private static <T> T throwEx(String msg) {
  19. throw new NullValueException(msg);
  20. }
  21. }
  22. class NullValueException extends RuntimeException {
  23. public NullValueException(String msg) {
  24. super(msg);
  25. }
  26. }
  27. record Outer(Nested nested) {
  28. }
  29. record Nested(Inner inner) {
  30. }
  31. record Inner(String foo) {
  32. }

注意:这只是代码的翻译部分,不包括问题或其他内容。

英文:

You can achieve the required behaviour with some exception handling like this:

  1. public class Test {
  2. public static void main(String[] args) {
  3. Outer outer = new Outer(new Nested(new Inner(&quot;value&quot;)));
  4. // Outer outer = new Outer(new Nested(new Inner(null)));
  5. // Outer outer = new Outer(new Nested(null));
  6. // Outer outer = new Outer(null);
  7. // Outer outer = null;
  8. try {
  9. Optional.ofNullable(outer).or(() -&gt; throwEx(&quot;Outer was null&quot;))
  10. .map(Outer::nested).or(() -&gt; throwEx(&quot;Nested was null&quot;))
  11. .map(Nested::inner).or(() -&gt; throwEx(&quot;Inner was null&quot;))
  12. .map(Inner::foo).or(() -&gt; throwEx(&quot;Foo was null&quot;))
  13. .ifPresent(System.out::println);
  14. } catch (NullValueException e) {
  15. System.out.println(e.getMessage());
  16. }
  17. }
  18. private static &lt;T&gt; T throwEx(String msg) {
  19. throw new NullValueException(msg);
  20. }
  21. }
  22. class NullValueException extends RuntimeException {
  23. public NullValueException(String msg) {
  24. super(msg);
  25. }
  26. }
  27. record Outer(Nested nested) {
  28. }
  29. record Nested(Inner inner) {
  30. }
  31. record Inner(String foo) {
  32. }

答案2

得分: 1

  1. 如果这只是一次性的事情,我会编写一个帮助方法来“包装”方法引用。包装器将返回包装的函数返回的内容,但如果包装的方法返回null,它还会记录一条消息。
  2. ```java
  3. private static <T, R> Function<T, R> withNullMessage(Function<? super T, ? extends R> function, String message) {
  4. return t -> {
  5. R r = function.apply(t);
  6. if (r == null) {
  7. Log.error(message);
  8. }
  9. return r;
  10. };
  11. }
  1. Optional.of(foo)
  2. .map(withNullMessage(Foo::getBar, "Bar is null!"))
  3. .map(withNullMessage(Bar::getBaz, "Baz is null!"))
  4. ...

请注意,这不处理foo为null的情况。如果foo为null,这将引发异常。要处理这种情况,您可以从一个肯定不为null的对象开始,

  1. Optional.of("")
  2. .map(withNullMessage(x -> foo, "Foo is null!"))
  3. .map(withNullMessage(Foo::getBar, "Bar is null!"))
  4. .map(withNullMessage(Bar::getBaz, "Baz is null!"))

或者您可以编写自己的of方法来记录null。

这种方法的另一个缺点是它不适用于flatMap。例如,这不会按您期望的那样工作:

  1. .flatMap(withNullMessage(Foo::thisReturnsAnotherOptional, "...")

您需要另一个包装方法来处理这种情况。

如果您经常需要这种类型的功能,可能值得编写自己的类似Optional的类型,其map方法接受额外的参数。

  1. <details>
  2. <summary>英文:</summary>
  3. If this is a one-off thing, I would write a helper method that &quot;wraps&quot; the method references. The wrapper would return what the wrapped function returns, but if the wrapped method returns null, it also logs a message.

private static <T, R> Function<T, R> withNullMessage(Function<? super T, ? extends R> function, String message) {
return t -> {
R r = function.apply(t);
if (r == null) {
Log.error(message);
}
return r;
};
}

Optional.of(foo)
.map(withNullMessage(Foo::getBar, "Bar is null!"))
.map(withNullMessage(Bar::getBaz, "Baz is null!"))
...

  1. Note that this does not handle the case where `foo` is null. If `foo` is null, this will throw an exception. To handle this, you can start with a definitely-not-null thing,

Optional.of("")
.map(withNullMessage(x -> foo, "Foo is null!"))
.map(withNullMessage(Foo::getBar, "Bar is null!"))
.map(withNullMessage(Bar::getBaz, "Baz is null!"))

  1. Or you can write your own `of` that logs nulls.
  2. Another drawback of this is that it doesn&#39;t work with `flatMap`s. e.g. this does not work as you&#39;d expect:
  3. .flatMap(withNullMessage(Foo::thisReturnsAnotherOptional, &quot;...&quot;))
  4. You would need another wrapper method to handle that case.
  5. If you need this sort of thing a lot, it&#39;s probably worth it to write your own `Optional`-like type, whose `map` methods take an extra argument.
  6. </details>
  7. # 答案3
  8. **得分**: 1
  9. 根据前面清扫工的答案中提到的一次性错误算法,我们可以实现如下。这将处理角落的空值情况以及其他情况:
  10. ```java
  11. public static void clientMethod() {
  12. Outer validOuter = new Outer(new Nested(new Inner("s")));
  13. Outer nullNested = new Outer(new Nested(null));
  14. Optional.ofNullable(nullNested)
  15. .map(outer -> eam(outer, Function.identity(), "提取的值:Outer 为 null"))
  16. .map(outer -> eam(outer, Outer::getNested, "提取的值:Nested 为 null"))
  17. .map(nested -> eam(nested, Nested::getInner, "提取的值:Inner 为 null"))
  18. .map(inner -> eam(inner, Inner::getFoo, "提取的值:Foo 为 null"))
  19. .ifPresent(System.out::println);
  20. }
  21. public static <T, R> R eam(T object, Function<T, R> extractor, String extractedValueNullMessage) {
  22. if (object != null) {
  23. R extractedValue = extractor.apply(object);
  24. if (extractedValue == null) {
  25. LOG.error(extractedValueNullMessage);
  26. }
  27. return extractedValue;
  28. }
  29. return null;
  30. }

请注意,代码中的注释和变量名已经被翻译。

英文:

Following the algorithm of one-off error mentioned in previous Sweeper's answer we could implement as below.This will take care of corner null cases as well

  1. public static void clientMethod() {
  2. Outer validOuter = new Outer(new Nested(new Inner(&quot;s&quot;)));
  3. Outer nullNested = new Outer(new Nested(null));
  4. Optional.ofNullable(nullNested)
  5. .map(outer-&gt;eam(outer, Function.identity(),&quot;Extracted value: Outer was null&quot;))
  6. .map(outer -&gt;eam(outer, Outer::getNested,&quot;Extracted value:Nested was null&quot;))
  7. .map(nested-&gt;eam(nested, Nested::getInner,&quot;Extracted value:Inner was null&quot;))
  8. .map(inner-&gt;eam(inner, Inner::getFoo,&quot;Extracted value:Foo was null&quot;))
  9. .ifPresent(System.out::println);
  10. }
  11. public static &lt;T,R&gt; R eam (T object,Function&lt;T,R&gt; extracter,String extractedValueNullMessage){
  12. if(object != null){
  13. R extractedValue = extracter.apply(object);
  14. if (extractedValue == null){
  15. LOG.error(extractedValueNullMessage);
  16. }
  17. return extractedValue;
  18. }
  19. return null;
  20. }

huangapple
  • 本文由 发表于 2023年7月20日 14:23:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/76727184.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定