0

我想指定特定节点是否与定义图中的节点集相邻?为此,我编写了这个方法:

private boolean isNeighbor(ArrayList<Customer> collection, Customer node,DirectedSparseGraph<Customer, Transaction> network) throws SQLException {
        for(Customer customer:collection){
            if(network.isSuccessor(customer, node)) return true;
        }
        return false;
    }

不幸的是,这个方法返回空指针异常。所以我决定将其更改为:

private boolean isNeighbor(ArrayList<Customer> collection, Customer node,DirectedSparseGraph<Customer, Transaction> network) throws SQLException {
        Collection<Customer> nodes=network.getVertices();
        ArrayList<Customer> acctualNodes = new ArrayList<Customer>();
        Customer acctualNode=new Customer();
        for(Customer customer: collection){
            for(Customer cust:nodes){
                if(cust.getName().equals(customer.getName())) acctualNodes.add(cust);
            }
        }
        for(Customer customer: nodes){
            if(node.getName().equals(customer.getName())) acctualNode=customer;
        }
        for(Customer customer: acctualNodes){
            if(network.isSuccessor(customer, acctualNode)) return true;
        }
        return false;
    }

新方法运行良好,但需要大量资源和时间,而且毫无用处。我的问题是如何以定义的方法执行时间更短的方式处理空指针异常?

我调试了我的方法。以下是有关三个使用对象的信息:

collection: ArrayList<E> id=17
elementData Object[6246]  (id=37)   

node: Customer id=23
customerArray   null    
customerName    "9379090484" (id=1345)  
type    null    

network: DirectedSparseGraph<V,E> id=27
edge_type   EdgeType  (id=39)   
edges   HashMap<K,V>  (id=42)   
vertices    HashMap<K,V>  (id=47)   
entrySet    HashMap$EntrySet  (id=1349) 
hashSeed    -949367244  
keySet  HashMap$KeySet  (id=48) 
loadFactor  0.75    
modCount    64780   
size    64780   
table   HashMap$Entry<K,V>[131072]  (id=52) 
threshold   98304   
useAltHashing   false   
values  null

如您所见,没有一个指定的对象是空的!那么是什么导致了NPE?!

4

4 回答 4

1

如我所见,您在不同的集合中有同一对象的两个不同实例。因此,您确实按名称搜索,这些行:

for(Customer customer: collection){
    for(Customer cust:nodes){
        if(cust.getName().equals(customer.getName())) acctualNodes.add(cust);
    }
}

然后对正确的实例使用 isSuccessor 方法

如果我的假设是正确的,那么你的方法是:

private boolean isNeighbor(ArrayList<Customer> collection, Customer node,DirectedSparseGraph<Customer, Transaction> network) throws SQLException {
        HashMap<String, Customer> realNodes = new HashMap<String, Customer>();
        Collection<Customer> nodes=network.getVertices();

        for (Customer n: nodes) {
            realNodes.put(n.getName(), n);
        }

        Customer acctualNode = realNodes.get(node.getName());
        for(Customer customer:collection){
            Customer actualCustomer = realNodes.get(customer.getName());
            if(network.isSuccessor(actualCustomer, acctualNode)) {
                return true;
            }
        }
        return false;
    }

编辑 - 添加注释:这将工作相对较快,但我相信网络对象的瓶颈,获取所有节点对我来说并不好。如果有一个通过名称返回 CustomerNode 的方法,那么您需要使用它而不是将所有对象放入 HashMap 中。

EDIT2 - 尝试让它更快。我不知道您使用的包,但如果是的话,可能是 DirectSparseGraph 的 jung 实现。我在 jung 的来源中找到了 getSuccessor 方法的实现:

public Collection<V>  getSuccessors(V vertex)
    {
        if (!containsVertex(vertex))
            return null;
        return Collections.unmodifiableCollection(getSuccs_internal(vertex));
    }

并且没有 isSuccessor。我假设您的 isSuccessor 方法会抛出 NPE,因为 getSuccessors 方法返回 null。它返回 null 因为找不到传递的顶点。集合中的顶点使用 equals 方法进行比较。这是我的目的:在 Customer 对象中定义 equals 方法并按名称进行比较(最好一起定义 equals 和 hashCode 方法并从 IDE - Eclipse、IDEA、NetBeans 生成它们):

public class Customer {
...
 private String name;

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Customer other = (Customer ) obj;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }
}

之后,您可以尝试使用您的第一种方法。如果它不起作用,那么我对 isSuccessor 方法和 NPE 的假设是不正确的,您可以尝试自己定义 isSuccessor 方法:

private boolean isNeighbor(ArrayList<Customer> collection, Customer node,DirectedSparseGraph<Customer, Transaction> network) throws SQLException {
        for(Customer customer:collection){
            //if(network.isSuccessor(customer, node)) { 
            if(isSuccessor(network, customer, node)) {
                return true;
            }
        }
        return false;
    }

    private boolean isSuccessor(DirectedSparseGraph<Customer, Transaction> network, Customer customer, Customer node) {
        Customer mockNode = node;
        Customer mockCustomer = customer;
        // If you can't redefine equals method for Customer object then you need to create a mock object mockNode.equals(node) == true && mockCustomer.equals(customer)
        Collection<Customer> successors = network.getSuccessors(mockNode);
        return successors != null && successors.indexOf(mockCustomer) != -1;
    }

如果您不能为 Customer 对象重新定义 equals 方法,那么您需要在将它们传递给网络对象之前创建模拟对象,因此以下条件应该为真:

mockNode.equals(node) && mockCustomer.equals(customer)

但是,如果您可以定义 equals 和 hasCode 方法会更好,我相信它会对您有很大帮助。

于 2013-08-13T12:42:43.397 回答
0

我不知道这是否是您正在寻找的,但如果它是您需要的“微优化”,也许这会有所帮助:

private boolean isNeighbor(ArrayList<Customer> collection, Customer node,DirectedSparseGraph<Customer, Transaction> network) throws SQLException {
    if (network == null) {
        throw new IllegalArgumentException("Network may not be null.");
    }

    if (collection == null) {
        return false;
    }

    for(Customer customer : collection){
        if(network.isSuccessor(customer, node)) {
            return true;
        }
    }

        return false;
}
于 2013-08-13T11:43:05.233 回答
0

在继续进行邻居分析之前检查是否为空。例如。

private boolean isNeighbor(ArrayList<Customer> collection, Customer node, DirectedSparseGraph<Customer, Transaction> network) throws SQLException {
    if (null == collection || collection.size() == 0) {
        return false;
    } else {
        for (Customer customer : collection) {
            if (network.isSuccessor(customer, node)) return true;
        }
    }
    return false;

}  

同样,您必须对函数中的所有参数进行空检查以避免 NPE。

于 2013-08-13T11:45:21.850 回答
0

您也可以使用以下内容。

private boolean isNeighbor(ArrayList<Customer> collection, Customer node,DirectedSparseGraph<Customer, Transaction> network) throws SQLException {
    boolean isNeighbor = false;
    try {
        for(Customer customer:collection) {
            if (network.isSuccessor(customer, node)) {
                isNeighbor = true;
                break;
            }
        }
    }
    catch (NullPointerException npe) {
        npe.printStackTrace();
        isNeighbor = false;
    }

    return isNeighbor

}
于 2013-08-13T11:54:30.953 回答