1

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.

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. Can any one give a snippet for how to implement such case?

6
  • 4
    What's the goal? Obfuscate your code? There are plenty of cases where using lambdas is useful, but this is really not one of them. Commented Feb 19, 2017 at 9:29
  • Please show what you've tried and explain what problems you're facing. Commented Feb 19, 2017 at 9:31
  • I disagree, I think that once your whole code logic is encapsulated inside 1 method, it's much more maintainable Commented Feb 19, 2017 at 9:33
  • 2
    Err, that's what you have now: everything is encapsulated inside getAllFields. This method does one thing, correctly. It obeys the single responsibility principle, and has a name indicating what it does. What's the problem? Commented Feb 19, 2017 at 9:40
  • 1
    You can create a method reference pointing to the above method: Function<Class<?>, Field[]> f = MyClass::getAllFields; Commented Feb 19, 2017 at 10:01

2 Answers 2

2

This getAllFields implementation is horribly inefficient, creating multiple ArrayList instances and arrays, repeatedly copying the entire data between them back and forth. 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:

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. 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. 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.

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.

That said, encapsulating the loop into a named method describing its purpose, like getAllFields, is actually a good thing. If you don’t want to expose it, declare it private instead of public.

Sign up to request clarification or add additional context in comments.

2 Comments

The inductive or recursive approach for this matter wasn't the topic even though of course you're extremely right about gaining nothing with going with the recursive approach & I completely accept the fact that the inductive way is far more justified than the rec 1, I was more concerned about the functional programming methodology just like in javaScript, which allows to create an anonymous method that will not create a reference nor will create a method reference, will just retrieve a value to a local method reference, was hoping to see this in java 8.
A lambda expression is like an anonymous method (in fact, they are compiled to a method), but it can’t call itself recursively. Well, the method invocation syntax requires a method name…
2

This is not (yet) directly possible. In Java 9, the Stream class will have an iterate method, which allows to implement this as follows:

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. The functional implementation would be far more difficult to understand.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.