Lambdas, multiple forEach with casting

后端 未结 4 964
抹茶落季
抹茶落季 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条回答
  •  Happy的楠姐
    2020-12-23 12:40

    First attempt beyond ugly. It will be years before I find this readable. Has to be a better way.

    Note the findChildren methods return arrays which of course work with for (N n: array) syntax, but not with the new Iterable.forEach method. Had to wrap them with Arrays.asList

    public List list() {
        final List list = new ArrayList();
        final StandardServer server = getServer();
    
        asList(server.findServices()).forEach(service -> {
    
            if (!(service.getContainer() instanceof Engine)) return;
    
            final Engine engine = (Engine) service.getContainer();
    
            instanceOf(Host.class, asList(engine.findChildren())).forEach(host -> {
    
                instanceOf(Context.class, asList(host.findChildren())).forEach(context -> {
    
                    // copy to another object -- not the important part
                    final ContextInfo info = new ContextInfo(context.getPath());
                    info.setThisPart(context.getThisPart());
                    info.setNotImportant(context.getNotImportant());
                    list.add(info);
                });
            });
        });
    
        return list;
    }
    

    The utility methods

    public static  Iterable instanceOf(final Class type, final Collection collection) {
        final Iterator iterator = collection.iterator();
        return () -> new SlambdaIterator<>(() -> {
            while (iterator.hasNext()) {
                final Object object = iterator.next();
                if (object != null && type.isAssignableFrom(object.getClass())) {
                    return (T) object;
                }
            }
            throw new NoSuchElementException();
        });
    }
    

    And finally a Lambda-powerable implementation of Iterable

    public static class SlambdaIterator implements Iterator {
        // Ya put your Lambdas in there
        public static interface Advancer {
            T advance() throws NoSuchElementException;
        }
        private final Advancer advancer;
        private T next;
    
        protected SlambdaIterator(final Advancer advancer) {
            this.advancer = advancer;
        }
    
        @Override
        public boolean hasNext() {
            if (next != null) return true;
    
            try {
                next = advancer.advance();
    
                return next != null;
            } catch (final NoSuchElementException e) {
                return false;
            }
        }
    
        @Override
        public T next() {
            if (!hasNext()) throw new NoSuchElementException();
    
            final T v = next;
            next = null;
            return v;
        }
    
        @Override
        public void remove() {
            throw new UnsupportedOperationException();
        }
    }
    

    Lots of plumbing and no doubt 5x the byte code. Must be a better way.

提交回复
热议问题