NullPointerException при добавлении узловых объектов в ArrayList

Я получаю NullPointerException когда я пытаюсь запустить этот код. Я назначил Nodes 2,3 и 4 как дочерние узлы для Node1, Я попытался создать метод, который будет проходить через все дочерние узлы в Node1 и возвращать список. Я не уверен, что я делаю неправильно.

public class TestingArrays2 {

    List<Node> myList1;
    List<Node> myList2;
    List<Node> myList3;
    List<Node> myList4;

    private Node Node1;
    private Node Node2;
    private Node Node3;
    private Node Node4;

    public TestingArrays2() {
        myList1 = new ArrayList<Node>();
        myList2 = new ArrayList<Node>();
        myList3 = new ArrayList<Node>();
        myList4 = new ArrayList<Node>();

        myList1.add(Node2);
        myList1.add(Node3);
        myList1.add(Node4);

        Node1 = new Node("One", myList1);
        Node2 = new Node("Two", myList2);
        Node3 = new Node("Three", myList3);
        Node4 = new Node("Four", myList4);

        List<Node> allNodesArray = nodeArray(Node1);

        for (int i = 0; i < allNodesArray.size(); i++){
            System.out.println(allNodesArray.get(i).label);
        }
    }

    public static void main(String arg[]) {
        TestingArrays2 testArray = new TestingArrays2();
    }

    public List<Node> nodeArray(Node n){
        List<Node> tempList = new ArrayList<Node>();

        for (int i = 0; i < n.children.size(); i++){
            tempList.add(n.children.get(i));
        }

    return tempList;
    }
}

3 ответа

Решение

Вы не создаете свой Nodes, Смотрите эти строки...

private Node Node1;
private Node Node2;
private Node Node3;
private Node Node4;

Они просто объявляют переменную как способную содержать объект типа Node, Тем не менее, они изначально начинаются с null значение - то есть они пусты.

Вы тогда звоните эти строки...

myList1.add(Node2);
myList1.add(Node3);
myList1.add(Node4);

Который вставил бы null ценности в ваш Listпотому что вы пытаетесь добавить объект, который еще не был создан.

Итак, вам нужно изменить свой код так, чтобы эти строки...

Node1 = new Node("One", myList1);
Node2 = new Node("Two", myList2);
Node3 = new Node("Three", myList3);
Node4 = new Node("Four", myList4);

появляются, прежде чем пытаться myList1.add() их в список. Это создаст Node объекты, которые затем могут быть добавлены к вашему List,

Как упомянуто в комментариях @BalusC, на вашем for Цикл позже в вашем коде, потому что он пытается вызвать .label на null объект. Исправление порядка, как предложено выше, исправит это, так как все объекты в вашем List теперь будет Nodes,

Это:

myList1.add(Node2);
myList1.add(Node3);
myList1.add(Node4);

Node1 = new Node("One", myList1);
Node2 = new Node("Two", myList2);
Node3 = new Node("Three", myList3);
Node4 = new Node("Four", myList4);

Вы пытаетесь добавить узлы в список до того, как они были созданы.

Хороший ответ на ваш вопрос уже дан.

Глядя на ваш код, у меня есть несколько предложенных модификаций.

Вы выполняете всю работу в (конструкторе) вашего тестового класса. Лучше по возможности делегировать это классу Node. Также постарайтесь не выполнять "работу" в конструкторе, только инициализацию.

Также ознакомьтесь с соглашениями о коде, которые я применил, например, использование имен существительных для имен классов и начало имен переменных со строчной буквы.

public class ArrayTest2 {

    public static void main(String arg[]) {

        Node node1 = new Node("One");

        node1.add(new Node("Two"));
        node1.add(new Node("Three"));
        node1.add(new Node("Four"));

        // this calls the toString method of node1
        System.out.println(node1);
    }

}

public class Node {

    private final String name;
    private final List<Node> children;

    public Node(String name) {
        this.name = name;
        this.children = new ArrayList<Node>();
    }

    public String getName() {
        return name;
    }

    public void add(Node children) {
        children.add(child);
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(name);
        if(children.size() > 0) {
            sb.append("(");
            String separator = "";
            for (Node child : children){
                sb.append(separator).append(String.valueOf(child));
                separator = ",";
            }
            sb.append(")");
        }
        return sb.toString();
    }
}

Обратите внимание, что дочернее поле является приватным, и для него нет получателя. Предоставлять прямой доступ к внутренним структурам данных, таким как 'children', считается плохой практикой, поэтому я добавил метод add для добавления узлов. Таким образом, класс сохраняет контроль над тем, что происходит с его данными, что является важным принципом проектирования ОО.

Метод toString создает строковое представление узла. Он добавляет имя узла, а затем, в случае наличия дочерних элементов, добавляет строковое представление каждого дочернего узла в список через запятую, заключенный в скобки, так что это должно вывести что-то вроде:

One(Two,Three,Four)

Более сложная структура, например:

Node node1 = new Node("One");
Node node2 = new Node("Two");
Node node3 = new Node("Three");
Node node4 = new Node("Four");
Node node5 = new Node("Five");
Node node6 = new Node("Six");
node1.add(node2);
node1.add(node3);
node2.add(node4);
node4.add(node5);
node4.add(node6);

Должен дать:

One(Two(Four(Five,Six)),Three)

Отказ от ответственности: мой код создан вручную, не скомпилирован и не проверен

Другие вопросы по тегам