简体   繁体   English

Java 8,匿名递归嵌套方法

[英]Java 8, anonymous recursive nested method

My goal is to migrate the method getAllFields into init by re writing it as an anonymous function, I know it's quite possible using functional programming. 我的目标是通过将getAllFields方法重写为一个匿名函数来将其迁移到init中,我知道使用函数式编程是很可能的。

public void init(){

}

public static Field[] getAllFields(Class klass) {
    List<Field> fields = new ArrayList<Field>();
    fields.addAll(Arrays.asList(klass.getDeclaredFields()));
    if (klass.getSuperclass() != null) {
        fields.addAll(Arrays.asList(getAllFields(klass.getSuperclass())));
    }
    return fields.toArray(new Field[] {});
}

I've tried using Function and also BiFunction but got lost abit. 我试过使用功能和BiFunction,但迷路了。 Can any one give a snippet for how to implement such case? 有人可以摘录如何实施这种情况吗?

This is not (yet) directly possible. (尚)无法直接实现。 In Java 9, the Stream class will have an iterate method, which allows to implement this as follows: 在Java 9中, Stream类将具有一个iterate方法,该方法可以按以下方式实现此方法:

Field[] allFields = Stream
    .iterate((klass, Objects::nonNull, Class::getSuperclass)
    .flatMap(c -> Stream.of(c.getDeclaredFields()))
    .toArray(Field[]::new);

However, the getAllFields method that you already have is a nice, clean implementation of the desired functionality, and the name makes unambiguously clear what this method does . 但是,您已经拥有的getAllFields方法是所需功能的不错的,干净的实现,并且该名称清楚地表明了此方法的作用 The functional implementation would be far more difficult to understand. 功能实现将很难理解。

This getAllFields implementation is horribly inefficient, creating multiple ArrayList instances and arrays, repeatedly copying the entire data between them back and forth. getAllFields实现效率极低,它创建多个ArrayList实例和数组,并在它们之间来回重复复制整个数据。 Thankfully, class hierarchies rarely are that deep that this becomes a bottleneck. 值得庆幸的是,类层次结构很少会成为瓶颈。

Still, you can implement this with a straight-forward loop, which is simpler and more efficient: 不过,您可以使用简单,高效的简单循环来实现此目的:

public static Field[] getAllFields(Class<?> klass) {
    List<Field> fields = new ArrayList<>();
    for(; klass!=null; klass=klass.getSuperclass())
        Collections.addAll(fields, klass.getDeclaredFields());
    return fields.toArray(new Field[0]);
}

There is not the slightest benefit from using recursion here. 在这里使用递归没有丝毫好处。

With a loop, you can easily create a Function if you really wish: 通过循环,如果您确实希望,可以轻松创建Function

public void init(){
    Function<Class<?>,Field[]> f = klass -> {
        List<Field> fields = new ArrayList<>();
        for(; klass!=null; klass=klass.getSuperclass())
            Collections.addAll(fields, klass.getDeclaredFields());
        return fields.toArray(new Field[0]);
    };
    Field[] someFields = f.apply(SomeClass.class);
}

Though, of course, there isn't even a reason to put the loop into a Function at all. 虽然,当然,甚至没有理由将循环放入Function中。 You only wanted to have a function here due to your wish to use that inefficient recursive implementation, but lambda expressions don't support accessing themself at all. 您只想在这里有一个函数,因为您希望使用那种效率低下的递归实现,但是lambda表达式根本不支持自己访问它们。 They only can access the field to which the instance implementing the functional interface got stored, if it was stored in a field, which you don't want. 他们只可以访问现场实施功能性接口的情况下得到了存储到的, 如果它被存储在一个领域,你不想要的。 With a local lambda expression, recursion is impossible. 使用本地lambda表达式,不可能进行递归。

With the straight-forward loop, you can just write 使用直接循环,您可以编写

public void init(){
    List<Field> fields = new ArrayList<>();
    for(Class<?> klass=SomeClass.class; klass!=null; klass=klass.getSuperclass())
        Collections.addAll(fields, klass.getDeclaredFields());
    Field[] someFields = fields.toArray(new Field[0]);
}

though, actually, there is rarely a real reason for copying the contents of fields into an array, you could just work with the List<Field> instead. 但是,实际上,几乎没有真正的理由将fields的内容复制到数组中,您可以直接使用List<Field>

That said, encapsulating the loop into a named method describing its purpose, like getAllFields , is actually a good thing. 就是说,将循环封装到描述其用途的命名方法中,例如getAllFields ,实际上是一件好事。 If you don't want to expose it, declare it private instead of public . 如果您不想公开它,则将其声明为private而不是public

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM