Java 流是否仅用于数组?单个元素怎么样?



我一直在研究Java流和函数式编程。
想出了一种重写小"用户登录"代码的方法。

这是我的登录方法;
如果来自查询的用户为 null,则会在筛选器上处理 null 指针异常。

public ResponseEntity login(User request) {
User dbUser = userRepo.findByEmail(request.getEmail());
if (!aes.matches(request.getPassword(), dbUser.getPassword()))
return ResponseEntity.status(403).build();
return logUserIn(dbUser);
}
private ResponseEntity logUserIn(User dbUser) {
dbUser.setPassword(null);
jwtHandler.setJwtCookie(dbUser);
return ResponseEntity.ok(dbUser);
}

并通过使用流;

public ResponseEntity login(User request) {
return Stream.of(userRepo.findByEmail(request.getEmail()))
.filter(dbUser -> aes.matches(request.getPassword(), dbUser.getPassword()))
.map(this::logUserIn)
.findFirst()
.orElse(ResponseEntity.status(403).build());
}
private ResponseEntity logUserIn(User dbUser) {
dbUser.setPassword(null);
jwtHandler.setJwtCookie(dbUser);
return ResponseEntity.ok(dbUser);
}

我不知道流是否应该以这种方式使用。是吗?
如果我在项目中更重要的部分使用类似的逻辑,以后会不会遇到麻烦?

如果你以更实用的风格使用它而不是短路,你可能会对if-else感觉更好:

if (!aes.matches(request.getPassword(), dbUser.getPassword())) {
return ResponseEntity.status(403).build();
}
else {
return logUserIn(dbUser);
}

使用流/可选在一个语句中执行等效操作更难阅读且性能较差。

您可以考虑将返回findByEmailOptional<User>的可能性,这对于任何"查找"方法来说都是更惯用的。然后你可以结合这两种方法,如

return userRepo.findByEmail(request.getEmail()).map(dbUser -> {
if (!aes.matches(request.getPassword(), dbUser.getPassword())) {
return ResponseEntity.status(403).build();
}
else {
return logUserIn(dbUser);
}
})... // .orElse(null) / .orElseThrow(...)

大多数情况下,您会遇到麻烦。"根本"的问题是,两种编写方式都可以作为"最佳选择"进行辩护,而Java社区总的来说非常喜欢第二种形式。出于同样的原因,name_variables_like_this是一个坏主意(社区决定公约是nameThemLikeThis(。打破常规将意味着你的代码更难被其他人阅读,而其他人编写的代码更难被你阅读。此外,当您尝试与其他代码交互时,可能会遇到摩擦。

例如,现在(以及在可预见的未来(,"lambdas"(那些带有::->的东西(不是异常透明的,不是控制流透明的,也不是可变的局部变量透明的。

这里只有 3 个可行的选项:

  1. 以某种方式编写所有代码,以便无论您在编写什么,这 3 个透明胶片都永远不会相关。这对我来说听起来是不可能的。即使您以某种方式管理,那里还有其他库。从java.*开始,它不是为这种代码样式设计的。

  2. 混合代码样式,当您没有立即预见到透明度相关时,请使用 lambda 样式,否则,如果是或您认为可能是,则使用更命令式样式。这对我来说听起来很愚蠢;当一种风格可以涵盖所有用例时,为什么要混合 2 种样式?

  3. 坚持使用 lambda 样式,向后弯腰以解决这 3 个透明度的不足,这困扰着您,将变量"降级"为AtomicX变体,使用此类结构来传输异常和布尔标志来携带中断并继续控制流在外面,etectera。这只是在写丑陋的代码,只是因为你特别喜欢你花哨的新闪亮的锤子,只是坚持把所有问题都当作钉子,不是吗?

那是试图猜测当你与其他代码和其他程序员交互时会发生什么。这个片段,在真空中,只有你一个人?呃,两者都很好用。无论你喜欢什么,如果社区,与其他代码的摩擦,以及拥有一致的风格都无关紧要。

我在实时代码中使用了 Java 8 流,对我来说最大的缺点是当异常在管道中未处理时会得到堆栈跟踪。

当然,它们很好写,让你有一种以函数式风格编写代码的感觉,但事实是流只是一个门面,因为在花哨的 API 下面,你正在处理一个普通、丑陋的 Java 迭代器上的巨大抽象层,当出现问题时,这一点变得非常明显,例如未处理异常。

所以你的问题的答案是肯定的,你可能会遇到麻烦,但这取决于你在阅读堆栈跟踪方面的水平,其中 70% 的跟踪与你编写的代码无关,而是与用于将迭代器转换为流的神奇东西有关。

尽可能多地首选使用if-elsefor-loops等,除非您确信流会更有效或更易于阅读。在这一点上,可读性非常重要,StreamAPI 存在的部分原因是为了提高可读性,但在充分利用 Streams API 的潜力时,适度和良好的判断力是值得锻炼的优点。

最新更新