简体   繁体   English

传入两个lambda函数

[英]passing in two lambda functions

I want to pass two lambda expressions (or something similar, I'm still getting familiar with all the terminology) into a method; 我想将两个lambda表达式(或类似的东西,我仍然熟悉所有术语)传递给方法; the first one will get a list of items, and the second one will retrieve one Integer object from (each one of) those items. 第一个将获得项目列表,第二个将从这些项目(每个项目)中检索一个Integer对象。

So I want to have a method something like this: 所以我想有一个像这样的方法:

private List<Integer> getRecentList(List<Integer> searchParams, 
                                    Function<List<Integer>, List<Integer>> listGetter,
                                    Supplier<Integer> idGetter)
{
  List<Object> objectList = listGetter.apply(searchParams);
  List<Integer> idList = new ArrayList<>();
  for (Object o: objectList)
  {
    idList.add(idGetter.get());
  }
  return idList;
}

and call it something like this: 并这样称呼它:

List<Integer> idList = setRecentList(searchParams, 
                                     (a) -> serviceOne.getItemList(a), 
                                     Item::getItemId);

So the first function is one called on an instance variable that the called method will have access to, and the second function is an instance method on any one of the objects returned as a list by the first function. 因此,第一个函数是调用被调用方法将访问的实例变量的函数,第二个函数是第一个函数作为列表返回的任何对象的实例方法。

But the (eclipse) compiler doesn't like Item::getItemId , with or without parentheses at the end. 但是(eclipse)编译器不喜欢Item::getItemId (在结尾处带或不带括号)。

Do I just have a syntax thing wrong, or is there something else wrong with this idea? 我只是语法有问题,还是这个想法有其他问题?


Edit after many helpful comments -- thanks to you all! 在发表许多有用的评论后进行编辑-谢谢大家!

I have one problem left. 我还有一个问题。 I've now got a method that I think does what I want, but I'm not sure how to pass the second expression to call it. 我现在有一个方法可以满足我的要求,但是我不确定如何传递第二个表达式来调用它。 Here is the method: 方法如下:

private List<Integer> getRecentList(List<Integer> salesCodeIdList,
                                    Function<List<Integer>, List> listGetter, 
                                    Function<Object, Integer> idGetter                                 
                                    ) {
    List<Object> objectList = listGetter.apply(salesCodeIdList);
    List<Integer> idList = new ArrayList<>();
    for (Object o : objectList) {
        idList.add(idGetter.apply((o)));
    }
    return idList;
}

AFAIK, I have to leave the second List raw in the getter spec, since different getters will return different types of objects in their lists. AFAIK,我必须将第二个List保留在getter规范中,因为不同的getter将在其列表中返回不同类型的对象。

But I still don't know how to invoke it -- I want to pass a method that gets an id from a particular instance of object, ie, I want to pass a getter on the ID of one of the objects returned by the listGetter. 但我仍然不知道如何调用它-我想传递一个从特定对象实例获取ID的方法,即我想传递一个由listGetter返回的对象之一的ID的吸气剂。 That will be different types of objects on different calls. 那将是不同调用上的不同类型的对象。 How would I invoke that? 我将如何调用呢?

To go back to examples, if I had a Supplier class with getSupplierId(), and a Vendor class with getVendorId(), and I cannot change those classes, can I pass in the correct method to invoke on the objects in the list depending on which getter retrieved the list? 回到示例,如果我有一个带有getSupplierId()的Supplier类和一个带有getVendorId()的Vendor类,并且我不能更改这些类,我可以传递正确的方法来调用列表中的对象,具体取决于哪个getter检索了列表?

A likely reason why you get the error is hidden inside the implementation of your method: 发生错误的可能原因隐藏在方法的实现中:

private List<Integer> getRecentList(List<Integer> searchParams, 
                                Function<List<Integer>, List<Object>> listGetter,
                                Supplier<Integer> idGetter)
{
    List<Object> objectList = listGetter.apply(searchParams);
    List<Integer> idList = new ArrayList<>();
    for (Object o: objectList)
    {
        idList.add(idGetter.get()); // <<<<<==== Here
    }
    return idList;
}

Note how o from the for loop is not used in the call, indicating that idGetter would get you an ID out of thin air. 请注意,在调用中未使用for循环中的o ,这表明idGetter会让您idGetter获得ID。 That's of course is not true: you need to pass an item to idGetter , which means that the call should be 那当然是不正确的:您需要将一个项目传递给idGetter ,这意味着调用应该

idList.add(idGetter.apply(o));

(from the comment) I can't cast within the method, I don't know what type of object to cast to there. (根据评论)我无法在方法中强制转换,也不知道要强制转换为哪种类型的对象。

which in turn means that idGetter should be Function<Object,Integer> : 这又意味着idGetter应该是Function<Object,Integer>

for (Object o: objectList)
{
    idList.add(idGetter.apply(o));
}

Since you would like to reuse the same function for lists of different types, the call would have to use a lambda that performs the cast at the caller, ie at the point where you know the type: 由于您想对不同类型的列表重用相同的函数,因此该调用将必须使用在调用方(即您知道类型的位置)执行转换的lambda:

List<Integer> idList = setRecentList(searchParams, 
                                 (a) -> serviceOne.getItemList(a), 
                                 (o) -> ((Item)o).getItemId());

Item::getItemId is not a Supplier<Integer> . Item::getItemId不是Supplier<Integer> A Supplier<Integer> is a lambda function that takes no arguments and returns an Integer . Supplier<Integer>是不带任何参数并返回Integer的lambda函数。 But Item::getItemId would require an Item to get the ID from. 但是Item::getItemId将需要一个Item才能从中获取ID。

Here is probably what you want. 这可能是您想要的。 Note I've changed your method signature to match the idea that you're getting IDs from items. 请注意,我已经更改了方法签名,以符合您从项目中获取ID的想法。

class Item {
    int id;
    Item (int i) {
        id = i;
    }
    int getItemId() {
        return id;
    }
}

private static List<Integer> getRecentList(List<Integer> searchParams, 
        Function<List<Integer>, List<Item>> listGetter,
        Function<Item, Integer> idGetter)
{
    List<Item> itemList = listGetter.apply(searchParams);
    List<Integer> idList = new ArrayList<>();
    for (Item item: itemList)
    {
        idList.add(idGetter.apply(item));
    }
    return idList;
}

Edit: If you want this to handle multiple kinds of Item s, and they all have IDs, you can do something like the following. 编辑:如果您希望它处理多种Item ,并且它们都具有ID,则可以执行以下操作。 First, define an interface to represent the fact that your different kinds of Items all have IDs: 首先,定义一个接口来表示您不同种类的Items都具有ID的事实:

interface ItemWithId {
    abstract int getItemId();
}
class ItemA implements ItemWithId {
    int id;
    ItemA(int i) {
        id = i;
    }
    public int getItemId() {
        return id;
    }
}
class ItemB implements ItemWithId {
    int id;
    ItemB(int i) {
        id = i;
    }
    public int getItemId() {
        return id;
    }
}

Then, your method should use ItemWithId instead of Item : 然后,您的方法应使用ItemWithId而不是Item

private List<Integer> getRecentList(List<Integer> searchParams,
        Function<List<Integer>, List<ItemWithId>> listGetter,
        Function<ItemWithId, Integer> idGetter)
{
    List<ItemWithId> itemList = listGetter.apply(searchParams);
    List<Integer> idList = new ArrayList<>();
    for (ItemWithId item: itemList)
    {
        idList.add(idGetter.apply(item));
    }
    return idList;
}

Finally, you can call this by casting an ItemA or ItemB to an ItemWithId : 最后,您可以通过将ItemAItemB强制转换为ItemA来调用此ItemWithId

List<Integer> idList = getRecentList(searchParams,
        (a) -> getItemList(a),
        (item) -> ((ItemWithId) item).getItemId());

Another edit: Ok, so you can't change ItemA or ItemB . 另一个编辑:好的,因此您不能更改ItemAItemB You can still make it work: 您仍然可以使其工作:

class ItemA {
    int id;
    ItemA(int i) {
        id = i;
    }
    public int getItemIdA() {
        return id;
    }
}
class ItemB {
    int id;
    ItemB(int i) {
        id = i;
    }
    public int getItemIdB() {
        return id;
    }
}

private List<Integer> getRecentList(List<Integer> searchParams,
        Function<List<Integer>, List<Object>> listGetter,
        Function<Object, Integer> idGetter)
{
    List<Object> itemList = listGetter.apply(searchParams);
    List<Integer> idList = new ArrayList<>();
    for (Object item: itemList)
    {
        idList.add(idGetter.apply(item));
    }
    return idList;
}

List<Integer> idList = getRecentList(searchParams,
        (a) -> getItemList(a),
        (item) -> ((ItemA) item).getItemIdA());
// or
List<Integer> idList = getRecentList(searchParams,
        (a) -> getItemList(a),
        (item) -> ((ItemB) item).getItemIdB());

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM