【问题标题】:Is this a redundant NullPointerException catch?这是一个多余的 NullPointerException 捕获吗?
【发布时间】:2020-07-21 05:36:57
【问题描述】:

下面的 Spring REST 代码返回给定ticketId 的列表。

可以在这段代码中抛出NullPointerException 吗?

NullPointerException 明确被TicketController 捕获:

    catch (NullPointerException nullPointerException) {
        throw new ResponseStatusException(
            HttpStatus.BAD_REQUEST, nullPointerException.getMessage(), nullPointerException);
    }

在检查票证 id 是否为 null 时的想法可能是:

        if (ticketId == null) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "ticket id cannot be null");
        }

期望NullPointerException 会被抛出,但ResponseStatusException 会被抛出?

如果变量ticketId 是一个路径参数,它永远不能为空,因为在没有ticketId 的情况下点击基本网址/ 我收到:

There was an unexpected error (type=Method Not Allowed, status=405).

全部来源:

@RestController
    public class TicketController {

        private final TicketServiceImpl ticketServiceImpl;

        public TicketController(TicketServiceImpl ticketServiceImpl) {
            this.ticketServiceImpl = ticketServiceImpl;
        }

        @GetMapping(path = "/{ticketId}")
        public ResponseEntity<List<TicketResponse>> getTicketsById(
            @PathVariable("ticketId") final Long ticketId) {
            try {
                final List<TicketResponse> ticketsById = ticketServiceImpl.getAll(ticketId);
                return new ResponseEntity<>(ticketsById, HttpStatus.OK);
            }
            catch (NullPointerException nullPointerException) {
                throw new ResponseStatusException(
                    HttpStatus.BAD_REQUEST, nullPointerException.getMessage(), nullPointerException);
            }
            catch (TicketNotFoundException ticketNotFoundException) {
                throw new ResponseStatusException(
                    HttpStatus.NOT_FOUND, "Ticket id not found",
                    ticketNotFoundException);
            }

        }

    }

@Service
public class TicketServiceImpl implements TicketService {

    private final TicketRepository ticketRepository;

    public TicketServiceImpl(TicketRepository ticketRepository) {

        this.ticketRepository = ticketRepository;

    }

    @Override
    public List<TicketResponse> getAll(Long ticketId) {

        final List<TicketResponse> ticketResponselist = ticketRepository.findData(ticketId);

            if (ticketId == null) {
                throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "ticket id cannot be null");
            }
            else if (ticketResponselist.size() == 0) {
                throw new TicketNotFoundException("ticket not found");
            }
            else {
                return ticketResponselist;
            }

    }
}

@Repository
public interface TicketRepository {

    public List<TicketResponse> findData(Long ticketId);

}

【问题讨论】:

  • 虽然抛出异常需要时间,但这通常不是性能问题。将异常放在 catch 子句中并没有那么慢。所以问题变成了:1.你为什么关心和2.你是怎么测试的?您确定没有框架/情况可以抛出 NullPointerException 吗?如果可以,那么生成更高级别/已检查的异常肯定是有意义的。

标签: java spring spring-boot rest model-view-controller


【解决方案1】:

if (ticketId == null) 检查应该在调用 ticketRepository.findData(ticketId); 之前进行。

否则,验证没有意义。

另外,作为旁注,捕捉NullPointerException 是一种不好的做法。原因是抛出空指针异常主要是编码气味的标志。通过使用例如,代码应该是空安全的。 Optional 或在方法级别进行适当的验证。在这种情况下,它将处于路由级别(即外部输入)。从那时起,如果设置了验证,您将处理不可为空的 id。

这也与从方法返回 null 有某种关系,这也是一种不好的做法,因为它需要检查每个方法,然后使用返回的值。这会污染代码,引入新的抽象级别,并且通常会导致严重的错误。

【讨论】:

  • @loan 谢谢,ticketId 可以为空吗?来自问题:“如果变量 ticketId 是一个路径参数,它永远不会为空,因为我收到了基本 url / 没有 ticketId:出现意外错误(类型 = 不允许方法,状态 = 405)。”
  • 我认为这更多的是关于 spring 如何处理这个问题的实现细节。如果例如,它也可以为空。 path 参数不是数字(一些随机字符串),Long 值肯定不是真的。
  • @loan 你的意思是路径参数值吗?如果将 String 传递给不是有效数字的 ticketId 路径参数,则将抛出 numberFormatException,而不是 nullPointerException。
  • 那么看起来NullPointerException是不能抛出的。
【解决方案2】:

在这种情况下不需要检查 NullPointerException。

旁注:最好在作为方法参数传递时使用超类型,除非您非常确定不会抛出异常而不是您的异常。

【讨论】:

    猜你喜欢
    • 2015-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-21
    • 1970-01-01
    • 1970-01-01
    • 2016-10-02
    • 2013-11-21
    相关资源
    最近更新 更多