Java中的函数对象
我想在java中实现类似javascript的方法,这可能吗?
说,我有一个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 pList = Arrays.asList(new Person[] {p1,p2});
我想实现这样的方法:
modList(pList,new Operation (Person p) { incrementAge(Person p) { p.setAge(p.getAge() + 1)}; });
modList接收两个参数,一个是列表,另一个是“函数对象”,它循环列表,并将此函数应用于列表中的每个元素。 在函数式编程语言中,这很容易,我不知道java怎么做到这一点? 也许可以通过动态代理完成,与原生for循环相比,它是否有性能折衷?
您可以使用接口和实现它的匿名内部类来完成它,例如
Person p1 = new Person("Jenny",20); Person p2 = new Person("Kate",22); List pList = Arrays.asList(p1, p2); interface Operation { abstract void execute(Person p); } public void modList(List list, Operation op) { for (Person p : list) op.execute(p); } modList(pList, new Operation { public void execute(Person p) { p.setAge(p.getAge() + 1)}; });
请注意,对于Java5中的varargs,可以简化对Arrays.asList
的调用,如上所示。
更新:上述的一般版本:
interface Operation { abstract void execute(E elem); } public void modList(List extends E> list, Operation op) { for (E elem : list) op.execute(elem); } modList(pList, new Operation() { public void execute(Person p) { p.setAge(p.getAge() + 1); } });
请注意,使用上面的modList
定义,您也可以在例如List
上执行Operation
(假设Student
是Person
的子类)。 普通的List
参数类型不允许这样做。
看看lambdaj项目。 以下是项目主页的示例:
List personInFamily = asList(new Person("Domenico"), new Person("Mario"), new Person("Irma")); forEach(personInFamily).setLastName("Fusco");
看看google集合库 。 查看Iterators和Iterables上的转换方法。 那应该能够得到你想要的东西。
是的,这在函数式编程语言中很容易..在Java中它有点复杂,但是你可以在可能的情况下使用generics类型来解决这个问题:
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 { void modify(Transformable object); } static class AgeIncrementer implements Modifier { 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 l = new ArrayList (); 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); } }
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 pList = Arrays.asList(new Person[]{p1, p2}); Function, List > theFunction = Function.>identity() .andThen(personList -> personList .stream() .map(person -> new Person(person.getName(), person.getAge() + 1)) .collect(Collectors.toList())); // You can use this directly List directly = theFunction.apply(pList); directly.forEach(person -> System.out.println(person)); // Or use it as an input parameter List toMethod = modList(pList, theFunction); toMethod.forEach(person -> System.out.println(person)); // Or you might prefer this way List 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 modList(List personList, Function, List > 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 + '}'; } }