我的目标是通过将方法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[] {});
}
我已经尝试过使用Function和BiFunction,但是他们已经失去了实力。 任何人都可以提供一个如何实现这种情况的片段吗?
答案 0 :(得分:2)
这还不是直接可行的。在Java 9中,Stream
类将具有iterate
方法,允许按如下方式实现:
Field[] allFields = Stream
.iterate((klass, Objects::nonNull, Class::getSuperclass)
.flatMap(c -> Stream.of(c.getDeclaredFields()))
.toArray(Field[]::new);
但是,您已经拥有的getAllFields
方法是所需功能的一个很好的,干净的实现,并且名称明确地清楚此方法的作用。功能实现将更难理解。
答案 1 :(得分:2)
这个getAllFields
实现非常低效,创建了多个ArrayList
实例和数组,反复地在它们之间来回复制整个数据。值得庆幸的是,类层次结构很少会成为一个瓶颈。
但是,您可以使用直接循环实现此功能,这样更简单,更高效:
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]);
}
这里使用递归没有丝毫的好处。
通过循环,您可以轻松创建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);
}
但是,当然,甚至没有理由将循环放入Function
。由于您希望使用低效的递归实现,您只想在此处使用函数,但lambda表达式根本不支持访问它们自己。他们只能访问实现功能接口的实例所存储的字段,如果它存储在您不想要的字段中。使用本地lambda表达式,递归是不可能的。
使用直接循环,您只需编写
即可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]);
}
实际上,将fields
的内容复制到数组中的确很少有真正的理由,您可以使用List<Field>
代替。
也就是说,将循环封装到描述其目的的命名方法中,如getAllFields
,实际上是一件好事。如果您不想公开它,请将其声明为private
而不是public
。