我有以下两个实现的界面:
public interface Parser { void parse(); boolean canParse(String message);}class StackParser implements Parser { public void parse(){ System.out.println("Parsing stackoverflow"); } public boolean canParse(String message){ return message.equals("stackoverflow"); }}class YoutubeParser implements Parser { public void parse() { System.out.println("Parsing youtube"); } public boolean canParse(String message) { return message.equals("youtube"); }}
我去检查传入的消息并解析"stackoverflow"
或"youtube"
:
public class Main { private List<Parser> parsers; public static void main(String[] args) { new Main().doSomething("youtube"); } void doSomething(String message){ parsers.stream() .filter(p -> p.canParse(message)) .forEach(p -> p.parse()); }}
好,很好 但是,如果消息不是"stackoverflow"
或"youtube"
怎么办?应用程序将保持静音,但如果未找到匹配项,我想发送另一条默认消息,例如"I can't parse this web!"
。
我知道这是行不通的(即使是编译),但也应该"I can't parse this web"
只打印一次,而不是针对每种false
条件。
parsers.stream() .filter(p -> { if (p.canParse(message) == false) { System.out.println("I can't parse it!"); } }) .forEach(p -> p.parse());
我该怎么做?
这是何时使用Optional#orElse
或Optional#orElseThrow
方法的完美示例。您想检查是否满足某些条件,以便进行过滤,尝试返回单个结果。如果不存在,则其他条件为真,应返回。
try { Parser parser = parsers.stream() .filter(p -> p.canParse(message)) .findAny() .orElseThrow(NoParserFoundException::new); // parser found, never null parser.parse();} catch (NoParserFoundException exception) { // cannot find parser, tell end-user}
如果一次只有一个解析器可以解析消息,则可以添加默认解析器:
class DefaultParser implements Parser { public void parse() { System.out.println("Could not parse"); } public boolean canParse(String message) { return true; }}
然后通过
// make sure the `DefaultParser` is the last parser in the `parsers`parsers.stream().filter(p -> p.canParse(message)).findFirst().get().parse();
或者删除DefaultParser并执行
Optional<Parser> parser = parsers.stream().filter(p -> p.canParse(message)).findFirst();if (parser.isPresent()) { parser.get().parse();} else { // handle it }
您可以在内部仅使用forEach if-else
parsers.forEach(p -> { if (!p.canParse(message)) { System.out.println("I can't parse it!"); } else { p.parse(); } });
这是一个非常有趣的问题,幸运的是我不得不在一段时间前面对。Mi方法包括声明Supplier<T>
仅在抛出异常时才会迭代的列表(此方法的目的是根据给定的参数从数据库检索数据,因此我可以按id或实例进行搜索) 。
import java.util.function.Supplier;public class AbstractFacadeUtil { public <R> R tryOr(Supplier<R>...fns) { R result = null; boolean success = false; int i = 0; while (!success && i < fns.length) { Supplier<R> fn = fns[i++]; try { result = fn.get(); success = true; } catch (Exception e) { } } if (!success) { throw new RuntimeException(new Exception(String.format("[%s] Couldn't find a successful method to apply\"", this.getClass()))); } return result; }}
一些注意事项:
我Supplier<T>
之所以使用它是因为它的主体不包含任何会引发未声明异常的东西,否则将需要使用它Callable<T>
。
是的,可以给它起一个更好的名字。
也许Iterator<T>
可以使这段代码更易于理解和清晰。
在您的特定情况下,我会使用Jason的方法Supplier<T>
,在列表的末尾添加一个会抛出NoParserFoundException
[编辑],你应该迭代List<Supplier<T>>
或List<Callable<T>>
wheter的Parser
无法解析,它抛出一个CantParseException
。因此,正如您所看到的,即使我不确定这是否是最有效或专家的方法,异常也会有所帮助。希望对您有帮助。
[EDIT2] 这是我如何实现上述解决方案的示例。
好吧,我要说。查看发布的每个解决方案-您如何看待?它们是否是功能性方法所期望的简洁,干净的代码?
不,为什么?由于设计错误,因此不适合功能方法。
修复设计:
摆脱void
返回类型(BRR)
不要过度使用类似的方法canDoSomething
(像对待isPresent
的Optional
-它的存在是有极端的情况下,大多是技术,而不是业务代码)
查看VAVR(或类似的库)-类Try
,Either
等等。
那么,在每种情况下,解决方案都会自然而然地-不仅是您在此处发布的特定解决方案。