Lambdas, multiple forEach with casting

后端 未结 4 966
抹茶落季
抹茶落季 2020-12-23 12:08

Need some help thinking in lambdas from my fellow StackOverflow luminaries.

Standard case of picking through a list of a list of a list to collect some children deep

4条回答
  •  臣服心动
    2020-12-23 12:25

    This would be my version of your code using JDK 8 streams, method references, and lambda expressions:

    server.findServices()
        .stream()
        .map(Service::getContainer)
        .filter(Engine.class::isInstance)
        .map(Engine.class::cast)
        .flatMap(engine -> Arrays.stream(engine.findChildren()))
        .filter(Host.class::isInstance)
        .map(Host.class::cast)
        .flatMap(host -> Arrays.stream(host.findChildren()))
        .filter(Context.class::isInstance)
        .map(Context.class::cast)
        .map(context -> {
            ContextInfo info = new ContextInfo(context.getPath());
            info.setThisPart(context.getThisPart());
            info.setNotImportant(context.getNotImportant());
            return info;
        })
        .collect(Collectors.toList());
    

    In this approach, I replace your if-statements for filter predicates. Take into account that an instanceof check can be replaced with a Predicate

    Predicate isEngine = someObject -> someObject instanceof Engine;
    
    
    

    which can also be expressed as

    Predicate isEngine = Engine.class::isInstance
    
    
    

    Similarly, your casts can be replaced by Function.

    Function castToEngine = someObject -> (Engine) someObject;
    

    Which is pretty much the same as

    Function castToEngine = Engine.class::cast;
    

    And adding items manually to a list in the for loop can be replaced with a collector. In production code, the lambda that transforms a Context into a ContextInfo can (and should) be extracted into a separate method, and used as a method reference.

    提交回复
    热议问题