Java 功能和消费者限制

Java 功能和消费者限制,java,lambda,java-8,Java,Lambda,Java 8,我决定在我的方法中使用函数作为参数,并发现了一些不愉快的事情。以下是一个例子: final Random random = new Random(); public interface Animal { public void sleep(); } public class Cat implements Animal { public boolean isAffectionate() { return random.nextBoolean(); }

我决定在我的方法中使用函数作为参数,并发现了一些不愉快的事情。以下是一个例子:

final Random random = new Random();

public interface Animal {
    public void sleep();
}

public class Cat implements Animal {

    public boolean isAffectionate() {
        return random.nextBoolean();
    }

    public void meow() {
        System.out.println("meow");
    }

    @Override
    public void sleep() {
        System.out.println("my sofa");
    }
}

public class Dog implements Animal {

    public boolean isAngry() {
        return random.nextBoolean();
    }

    public void bark() {
        System.out.println("woof-woof");
    }

    @Override
    public void sleep() {
        System.out.println("my carpet");
    }
}

public boolean isOwnerAtHome() {
    return random.nextBoolean();
}

public <T, A extends Animal> T anyAction(Class<A> clazz, Function<A, T> action)
        throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    A animal;
    animal = (A) clazz.getConstructors()[0].newInstance();
    T t;
    if (isOwnerAtHome()) {
        t = action.apply(animal);
    } else {
        animal.sleep();
        t = action.apply(animal);
    }
    return t;
}
要查看
void
活动,我必须使用以下方法:

public <A extends Animal> void voidAction(Class<A> clazz, Consumer<A> action)
        throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    Function<A, Boolean> function = animal -> {
        action.accept(animal);
        return true;
    };
    anyAction(clazz, function);
}
很乱。即使是方法(
anyAction
voidAction
)也应该有不同的名称


使用lambdas和不完全重写是否可以减少混乱?

通常我们使用一些语义来区分返回结果的函数和不返回结果的函数,例如:

static void <A extends Animal> void action(
    Class<A> type,
    Consumer<? super A> theAction) {...}

static void <A extends Animal, T> query(
    Class<A> type,
    Function<? super A, ? extends T> theQuery) {...}

Animal.action(Cat.class, Cat::meow);
boolean result =
    Animal.query(Cat.class, Cat::isAffectionate);

或可能考虑用不同的方式来解释:

private static <A extends Animal> Optional<A> create(
        Class<A> type) throws NoSuchMethodException, InstantiationException, IllegalAccessException {
    A a = type.getConstructor().newInstance();

    if (!a.isOwnerHome()) {
        a.sleep();
    }

    return a;
}

// "action"
theAction.accept(create(type));
// "query"
return theQuery.apply(create(type));
私有静态可选创建(
类类型)抛出NoSuchMethodException、InstanceionException、IllegalAccessException{
A=type.getConstructor().newInstance();
如果(!a.isOwnerHome()){
a、 睡眠();
}
返回a;
}
//“行动”
接受(创建(类型));
//“查询”
返回query.apply(创建(类型));
一般来说,请记住,API的内部可能并不漂亮或完美,而目标是从外部使用它

假设lambda的设计方式是
消费者
以某种方式隐式转换为
函数
。这对于希望重用一点代码的API设计人员来说是很方便的,但这将为这些API的用户以无意义/不正确的方式使用它们打开一条通道:

<T> void send(List<T> elements) {
    elements.stream()
        // using 'map' to log
        // when 'peek' is designed for this purpose
        .map(e -> Debug.log("sending " + e))
        .forEach(this::send);
}
void发送(列表元素){
元素流()
//使用“映射”进行日志记录
//当“peek”设计用于此目的时
.map(e->Debug.log(“发送”+e))
.forEach(this::send);
}

也许你认为它很复杂,因为你让它变得复杂:

public <T, A extends Animal> T anyAction(Supplier<A> s, Function<A, T> action) {
    A animal=s.get();
    if (!isOwnerAtHome()) animal.sleep();
    return action.apply(animal);
}
public <A extends Animal> void anyAction(Supplier<A> s, Consumer<A> action) {
    anyAction(s, a -> { action.accept(a); return null; }); 
}
public boolean booleanCatActionToday() {
    return anyAction(Cat::new, Cat::isAffectionate);
}
public void voidCatActionToday() {
    anyAction(Cat::new, Cat::meow);
}
您可以
静态导入
,并且您永远不需要重载方法,因为您可以调用接受
函数的方法

public void voidCatActionToday() {
    anyAction(Cat::new, noResult(Cat::meow));
}
<T> void send(List<T> elements) {
    elements.stream()
        // using 'map' to log
        // when 'peek' is designed for this purpose
        .map(e -> Debug.log("sending " + e))
        .forEach(this::send);
}
public <T, A extends Animal> T anyAction(Supplier<A> s, Function<A, T> action) {
    A animal=s.get();
    if (!isOwnerAtHome()) animal.sleep();
    return action.apply(animal);
}
public <A extends Animal> void anyAction(Supplier<A> s, Consumer<A> action) {
    anyAction(s, a -> { action.accept(a); return null; }); 
}
public boolean booleanCatActionToday() {
    return anyAction(Cat::new, Cat::isAffectionate);
}
public void voidCatActionToday() {
    anyAction(Cat::new, Cat::meow);
}
public static <T> Function<T,Void> noResult(Consumer<T> c) {
    return t -> { c.accept(t); return null; };
}
public void voidCatActionToday() {
    anyAction(Cat::new, noResult(Cat::meow));
}