Функциональный объект в Java - PullRequest
10 голосов
/ 08 апреля 2010

Я хочу реализовать javascript-подобный метод в java, возможно ли это?

Скажем, у меня есть класс Person:

public class Person {
 private String name ;
 private int age ;
 // constructor ,accessors are omitted
}

И список объектов Person:

Person p1 = new Person("Jenny",20);
Person p2 = new Person("Kate",22);
List<Person> pList = Arrays.asList(new Person[] {p1,p2});

Я хочу реализовать метод, подобный этому:

modList(pList,new Operation (Person p) {
  incrementAge(Person p) { p.setAge(p.getAge() + 1)};
});

modList получает два параметра, один - список, другой - «объект функции», он зацикливает список и применяет этот метод.функция для каждого элемента в списке.В функциональном языке программирования это легко, я не знаю, как Java это делает?Может быть, это можно сделать с помощью динамического прокси, имеет ли это компромисс производительности по сравнению с нативным циклом for?

Ответы [ 5 ]

14 голосов
/ 08 апреля 2010

Вы можете сделать это с помощью интерфейса и анонимного внутреннего класса, реализующего его, например

Person p1 = new Person("Jenny",20);
Person p2 = new Person("Kate",22);
List<Person> pList = Arrays.asList(p1, p2);

interface Operation {
  abstract void execute(Person p);
}

public void modList(List<Person> list, Operation op) {
  for (Person p : list)
    op.execute(p);
}

modList(pList, new Operation {
  public void execute(Person p) { p.setAge(p.getAge() + 1)};
});

Обратите внимание, что при использовании varargs в Java5 вызов Arrays.asList может быть упрощен, как показано выше.

Обновление: Обобщенная версия выше:

interface Operation<E> {
  abstract void execute(E elem);
}

public <E> void modList(List<? extends E> list, Operation<E> op) {
  for (E elem : list)
    op.execute(elem);
}

modList(pList, new Operation<Person>() {
    public void execute(Person p) { p.setAge(p.getAge() + 1); }
});

Обратите внимание, что с приведенным выше определением modList вы можете выполнить Operation<Person>, например, List<Student> тоже (при условии, что Student является подклассом Person). Простой тип параметра List<E> не позволил бы это.

3 голосов
/ 08 апреля 2010

Взгляните на проект lambdaj .Вот пример с домашней страницы проекта:

List<Person> personInFamily = asList(new Person("Domenico"), new Person("Mario"), new Person("Irma"));
forEach(personInFamily).setLastName("Fusco");
2 голосов
/ 08 апреля 2010

Посмотрите на библиотеку Google коллекции .Посмотрите на методы преобразования в Iterators и Iterables.Это должно быть в состоянии получить то, что вы хотите.

1 голос
/ 08 апреля 2010

Да, это легко в функциональном языке программирования ... в Java это немного сложнее, но вы можете поработать примерно так, используя, по возможности, также обобщенные типы:

public class TestCase {
    static interface Transformable {};

    static class Person implements Transformable {
        Person(String name, int age) {
            this.name = name;
            this.age = age;
        }

        public String name;
        public int age;
    }

    static interface Modifier<T extends Transformable> {
        void modify(Transformable object);
    }

    static class AgeIncrementer implements Modifier<Person> {
        public void modify(Transformable p) {
            ++((Person)p).age;
        }
    }

    static void applyOnList(List<? extends Transformable> objects, Modifier<? extends Transformable> modifier) {    
        for (Transformable o : objects) {
            modifier.modify(o);
        }
    }

    public static void main(String[] args) {
        ArrayList<Person> l = new ArrayList<Person>();
        l.add(new Person("John", 10));
        l.add(new Person("Paul", 22));
        l.add(new Person("Frank", 35));

        applyOnList(l, new AgeIncrementer());

        for (Person p : l)
            System.out.println(p.age);
    }
}
0 голосов
/ 25 сентября 2018
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

public class FuntionAsParameter {


    public static void main(final String[] args) {

        Person p1 = new Person("Jenny", 20);
        Person p2 = new Person("Kate", 22);

        List<Person> pList = Arrays.asList(new Person[]{p1, p2});

        Function<List<Person>, List<Person>> theFunction = Function.<List<Person>>identity()
            .andThen(personList -> personList
                .stream()
                .map(person -> new Person(person.getName(), person.getAge() + 1))
                .collect(Collectors.toList()));

        // You can use this directly
        List<Person> directly = theFunction.apply(pList);
        directly.forEach(person -> System.out.println(person));

        // Or use it as an input parameter
        List<Person> toMethod = modList(pList, theFunction);
        toMethod.forEach(person -> System.out.println(person));

        // Or you might prefer this way
        List<Person> thirdWay = modList(pList,
                (list) -> list.stream()
                        .map(person -> new Person(person.getName(), person.getAge() + 1))
                        .collect(Collectors.toList())
        );
        thirdWay.forEach(person -> System.out.println(person));
    }

    private static List<Person> modList(List<Person> personList, Function<List<Person>, List<Person>> theFunction) {
        return theFunction.apply(personList);
    }


}

class Person {

    private String name;
    private int age;

    public Person(final String name, final int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    @Override
    public String toString() {
        return "Person{" +
            "name='" + name + '\'' +
            ", age=" + age +
            '}';
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...