Java函数接口澄清-传递到lambda表达式的参数
我有下面的代码,我正在努力理解。我有一个接口声明如下:Java函数接口澄清-传递到lambda表达式的参数,java,lambda,functional-interface,Java,Lambda,Functional Interface,我有下面的代码,我正在努力理解。我有一个接口声明如下: public interface WeightedRelationshipConsumer { boolean accept(int sourceNodeId, int targetNodeId, long relationId, double weight); } public interface WeightedRelationshipIterator { void forEachRelationship(int no
public interface WeightedRelationshipConsumer {
boolean accept(int sourceNodeId, int targetNodeId, long relationId, double weight);
}
public interface WeightedRelationshipIterator {
void forEachRelationship(int nodeId, Direction direction, WeightedRelationshipConsumer consumer);
}
然后我有第二个接口,它接受WeightedRelationshipConsumer
声明如下:
public interface WeightedRelationshipConsumer {
boolean accept(int sourceNodeId, int targetNodeId, long relationId, double weight);
}
public interface WeightedRelationshipIterator {
void forEachRelationship(int nodeId, Direction direction, WeightedRelationshipConsumer consumer);
}
在Dijkstra算法的实现中,我有以下代码:
private void run(int goal, Direction direction) {
// `queue` is a Priority Queue that contains the vertices of the graph
while (!queue.isEmpty()) {
int node = queue.pop();
if (node == goal) {
return;
}
// `visited` is a BitSet.
visited.put(node);
// Gets the weight of the distance current node from a node-distance map.
double costs = this.costs.getOrDefault(node, Double.MAX_VALUE);
graph.forEachRelationship(
node,
direction, (source, target, relId, weight) -> {
updateCosts(source, target, weight + costs);
if (!visited.contains(target)) {
queue.add(target, 0);
}
return true;
});
}
}
这是最重要的
graph.forEachRelationship(node, direction, (source, target, relId, weight) -> {
updateCosts(source, target, weight + costs);
if (!visited.contains(target)) {
queue.add(target, 0);
}
return true;
});
这使我困惑。具体来说,什么是源
、目标
、relId
、权重
,它们是如何解决的?这4个变量没有在这个类中的任何其他地方定义<代码>更新成本()如下所示:
private void updateCosts(int source, int target, double newCosts) {
double oldCosts = costs.getOrDefault(target, Double.MAX_VALUE);
if (newCosts < oldCosts) {
costs.put(target, newCosts);
path.put(target, source);
}
}
private void updateCosts(int源、int目标、双倍新成本){
double oldCosts=costs.getOrDefault(目标,double.MAX_值);
如果(新成本<旧成本){
成本。卖出(目标,新成本);
path.put(目标、源);
}
}
此外,如果有可能有助于理解此类代码的资源,请提供。谢谢。您的界面似乎是一个功能界面:
interface WeightedRelationshipConsumer {
boolean accept(int sourceNodeId, int targetNodeId, long relationId, double weight);
}
这些类型也称为SAM类型(单一抽象方法类型),它们是使用lambda表达式或方法引用实现的候选类型
lambda表达式是实现接口唯一方法的一种方法
比如说
WeightedRelationshipConsumer wrc = (source, target, relId, weight) -> true;
这是一种为其accept
方法提供实现的方法,其中(源、目标、relId、权重)
对应于方法的声明参数,其中true
,lambda表达式的返回值,也对应于accept
方法的返回类型
它显示您的图形。forEachRelationship
方法接受WeightedRelationshipConsumer
的实例作为其第三个参数,因此,您可以将lambda表达式作为参数传递
正如你的问题所述:
graph.forEachRelationship(node, direction, (source, target, relId, weight) -> {
updateCosts(source, target, weight + costs);
if (!visited.contains(target)) {
queue.add(target, 0);
}
return true;
});
关于参数的明显缺乏定义,这只是您的一个困惑。Lambda表达式支持类型推断,因此,我们不需要再次提供参数的类型,毕竟它们已经在Lambda表达式实现的方法的签名中声明(即,accept
)
因此,我们之前的lambda可以声明为:
WeightedRelationshipConsumer wrc = (int sourceNodeId, int targetNodeId, long relationId, double weight) -> true
但为了使它们更具可读性,通常会省略这些类型。毕竟,编译器可以从accept
的方法签名推断参数的类型
因此,lambda括号中的标识符列表实际上是函数的参数声明
这里有大量的参考资料,在Stackoverflow的标签下谢谢。
源
、目标
、relId
和权重的实际定义如何updateCosts()
需要它们,但是,我看不到它们在任何地方被定义。@我只是扩展了我的答案以解决您的问题。谢谢,我有最后一个澄清。关于forEachRelationship()
这是一个抽象方法,当参数传递给它时,实际会发生什么?我在任何地方都看不到它的函数体。我想这就是我困惑的原因。请帮我澄清一下,我会接受你的回答。非常感谢。@swdon您没有提供forEachRelationship
方法声明的详细信息,它的类及其派生,那么我怎么知道您问题的答案呢?但是,我可以从中推断,即使引用图
来自某个抽象类型,它显然指向了该抽象的实现,其中确实定义了forEachRelationship
方法。如果您得到的是graph.getClass()
,那么您可能会找到这个派生类是什么。