Lambda 与流一起使用的功能接口实现之间的差异

Lambda 与流一起使用的功能接口实现之间的差异,lambda,java-8,functional-programming,java-stream,Lambda,Java 8,Functional Programming,Java Stream,我在这里试图了解过滤流的工作原理。 下面是从Strings的List中筛选重复项的两种方法。 (我不想使用distinct关键字进行说明) 这种方法似乎奏效了。不确定方法1和方法2之间的区别。我看到distincyByKey是一个静态方法,但是它有什么区别呢?每次执行lambda表达式体时,您的第一个代码片段都会创建一个新的集实例,这意味着流的每个元素都有一个实例。因此,每次在流的元素上应用过滤器时,它都会将该元素添加到不同的集合实例中,因此无法过滤出重复项 在第二个代码段中,执行distinc

我在这里试图了解过滤流的工作原理。 下面是从
String
s的
List
中筛选重复项的两种方法。 (我不想使用distinct关键字进行说明)


这种方法似乎奏效了。不确定方法1和方法2之间的区别。我看到
distincyByKey
是一个静态方法,但是它有什么区别呢?

每次执行lambda表达式体时,您的第一个代码片段都会创建一个新的
实例,这意味着
流的每个元素都有一个实例。因此,每次在
的元素上应用过滤器时,它都会将该元素添加到不同的
集合
实例中,因此无法过滤出重复项

在第二个代码段中,执行
distincyByKey()
时,将创建一次
Set
实例。当对
流的每个元素计算过滤器时,执行的lambda主体就是
seen.add(keydectractor.apply(t)
,并且它总是针对相同的
Set
实例执行

通过在流管道外部创建
Set
实例,或者使用方法引用,可以在没有
static
方法的情况下实现相同的行为:

Set<String> seen = ConcurrentHashMap.newKeySet();
List<String> list1 = 
    list.parallelStream().filter(e-> seen.add(e)).collect(Collectors.toList());
Set seen=ConcurrentHashMap.newKeySet();
列表1=
list.parallelStream().filter(e->seen.add(e)).collect(Collectors.toList());

列表列表1=
list.parallelStream().filter(ConcurrentHashMap.newKeySet()::add.collect(Collectors.toList());

编辑:我从代码中删除了
getLastName()
方法调用,因为您的
Stream
Stream
,而
String
s没有
getLastName()
方法。我猜您混淆了一些代码片段。

两者之间的区别恰恰在于您的
Set
对象

在第一个代码段中,
seen
是由谓词创建的。每个元素都会调用谓词。这意味着每次调用谓词时,都会创建一个集合实例。在第二个代码段中,集合是由
distincyByKey()
创建的,它在创建流时只运行一次

distincyByKey
返回的谓词包含对该集合的引用,每次运行时,它都使用相同的实例。如果要使第二个代码像第一个一样运行,则该方法如下所示:

public static <T> Predicate<T> distincyByKey(Function<? super T, ?> keyExtractor) {
    return t -> {
        Set<Object> seen =  ConcurrentHashMap.newKeySet();
        return seen.add(keyExtractor.apply(t));
    }
}
公共静态谓词distincyByKey(函数键提取器){
返回t->{
Set seen=ConcurrentHashMap.newKeySet();
返回seen.add(keydextractor.apply(t));
}
}

此版本将与您的第一个实现一样被破坏。

非常感谢。您能告诉我它是否在lambda或streams的功能中指定吗?@user2296988我不确定您希望看到指定的具体内容。需要了解的重要一点是代码的每个语句何时执行。参数传递给
当创建
流时,filter()
将被计算一次。传递给
filter()
谓词的
test()
方法将对
流的每个元素执行一次。一旦您确定了代码的哪一部分将成为该
测试()的实现
方法在每个代码段中,您将看到差异。哦,这是有意义的。因此,通常lambda应该只有参数和返回语句(或void)。如果它在主体实现中有任何实例变量,它也会被视为参数。谢谢。请解释是否有任何方法可以使用您的第二个apporach作为成员变量。例如,我正在将一个类的变量传递到谓词。@user2296988我必须查看实际的示例代码。从com中还不够清楚哦,哇,从来都不知道你能用这种方式写回执。好帖子!
Set<String> seen = ConcurrentHashMap.newKeySet();
List<String> list1 = 
    list.parallelStream().filter(e-> seen.add(e)).collect(Collectors.toList());
List<String> list1 = 
    list.parallelStream().filter(ConcurrentHashMap.newKeySet()::add).collect(Collectors.toList());
public static <T> Predicate<T> distincyByKey(Function<? super T, ?> keyExtractor) {
    return t -> {
        Set<Object> seen =  ConcurrentHashMap.newKeySet();
        return seen.add(keyExtractor.apply(t));
    }
}