Как сохранить вывод консольного приложения

Что такое NullPointerException?

Хорошим местом для начала является JavaDocs . Они охватывают это:

Брошено, когда приложение пытается использовать null в случае, когда требуется объект. К ним относятся:

  • Вызов метода экземпляра нулевого объекта.
  • Доступ или изменение поля нулевого объекта.
  • Выполнение длины null, как если бы это был массив.
  • Доступ или изменение слотов с нулевым значением, как если бы это был массив.
  • Бросать нуль, как если бы это было значение Throwable.

Приложения должны бросать экземпляры этого класса для указания других незаконных видов использования нулевого объекта.

blockquote>

Также, если вы попытаетесь использовать нулевую ссылку с synchronized, который также выдаст это исключение, за JLS :

SynchronizedStatement:
    synchronized ( Expression ) Block
  • В противном случае, если значение выражения равно null, NullPointerException.
blockquote>

Как это исправить?

Итак, у вас есть NullPointerException. Как вы это исправите? Возьмем простой пример, который выдает NullPointerException:

public class Printer {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer();
        printer.print();
    }
}

Идентифицирует нулевые значения

. Первый шаг - точно определить , значения которого вызывают исключение . Для этого нам нужно выполнить некоторую отладку. Важно научиться читать stacktrace . Это покажет вам, где было выбрано исключение:

Exception in thread "main" java.lang.NullPointerException
    at Printer.printString(Printer.java:13)
    at Printer.print(Printer.java:9)
    at Printer.main(Printer.java:19)

Здесь мы видим, что исключение выбрано в строке 13 (в методе printString). Посмотрите на строку и проверьте, какие значения равны нулю, добавив протоколирующие операторы или используя отладчик . Мы обнаруживаем, что s имеет значение null, а вызов метода length на него вызывает исключение. Мы видим, что программа перестает бросать исключение, когда s.length() удаляется из метода.

Трассировка, где эти значения взяты из

Затем проверьте, откуда это значение. Следуя вызовам метода, мы видим, что s передается с printString(name) в методе print(), а this.name - null.

Трассировка, где эти значения должны быть установлены

Где установлен this.name? В методе setName(String). С некоторой дополнительной отладкой мы видим, что этот метод вообще не вызывается. Если этот метод был вызван, обязательно проверьте порядок , что эти методы вызывают, а метод set не будет называться после методом печати. ​​

Этого достаточно, чтобы дать нам решение: добавить вызов printer.setName() перед вызовом printer.print().

Другие исправления

Переменная может иметь значение по умолчанию setName может помешать ему установить значение null):

private String name = "";

Либо метод print, либо printString может проверить значение null например:

printString((name == null) ? "" : name);

Или вы можете создать класс, чтобы name всегда имел ненулевое значение :

public class Printer {
    private final String name;

    public Printer(String name) {
        this.name = Objects.requireNonNull(name);
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer("123");
        printer.print();
    }
}

См. также:

Я все еще не могу найти проблему

Если вы попытались отладить проблему и до сих пор не имеете решения, вы можете отправить вопрос для получения дополнительной справки, но не забудьте включить то, что вы пробовали до сих пор. Как минимум, включите stacktrace в вопрос и отметьте важные номера строк в коде. Также попробуйте сначала упростить код (см. SSCCE ).

10
задан André Chalella 14 September 2008 в 03:50
поделиться

6 ответов

Идеальное решение для этого состоит в том, чтобы использовать log4net с консолью appender и файлом appender. Существуют многие другое appenders доступное также. Это также позволяет Вам выключать и включать другой appenders во времени выполнения.

5
ответ дан 4 December 2019 в 01:03
поделиться

Я не думаю, что существует что-то не так с Вашим подходом.

Если Вы хотели повторно используемый код, считайте реализацию класса названной MultiWriter или somesuch, который берет в качестве входа два (или N?) TextWriter потоки и распределяют все предписания, сбросы, и т.д. к тем потокам. Затем можно сделать эту вещь файла/консоли, но столь же легко можно разделить любой поток вывода. Полезный!

4
ответ дан 4 December 2019 в 01:03
поделиться

Вероятно, не, что Вы хотите, но на всякий случай... По-видимому, PowerShell реализует версию почтенного tee команда. Который в значительной степени предназначается для точно этой цели. Так... курите их, если Вы получили их.

1
ответ дан 4 December 2019 в 01:03
поделиться

Полагайте, что рефакторинг Вашего приложения разделяет части взаимодействия с пользователем от бизнес-логики. По моему опыту, такое разделение довольно выгодно для структуры Вашей программы.

Для конкретной проблемы Вы пытаетесь решить здесь, это становится простым для части взаимодействия с пользователем для изменения ее поведения от Console.WriteLine к файловому вводу-выводу.

0
ответ дан 4 December 2019 в 01:03
поделиться

Я сказал бы, что подражают диагностика, что сама.NET использует (Трассировка и Отладка).

Создайте "выходной" класс, который может иметь различные классы, которые придерживаются текстового выходного интерфейса. Вы сообщаете выходному классу, он автоматически отправляет вывод, данный классам, которые Вы добавили (ConsoleOutput, TextFileOutput, WhateverOutput).. И так далее.. Это также оставляет Вас открытыми для добавления других "выходных" типов (таких как xml/xslt для получения приятно отформатированного отчета?).

Проверьте Набор Приемников трассировки для наблюдения то, что я имею в виду.

1
ответ дан 4 December 2019 в 01:03
поделиться

Я работаю над реализованием подобной опции, чтобы получить вывод, отправленный в Консоль и сохранить его к журналу, все еще передавая вывод в режиме реального времени нормальной Консоли, таким образом, это не повреждает приложение (например, если это - консольное приложение!).

Если Вы все еще пытаетесь сделать это в своем собственном коде путем сохранения консольного вывода (в противоположность использованию системы регистрации для сохранения просто информации, Вы действительно заботитесь о), я думаю, что можно избежать сброса после каждой записи, пока Вы также переопределяете Сброс () и удостоверяетесь, что это сбрасывает оригинал stdoutWriter Вы сохранили, а также Ваш fileWriter. Вы хотите сделать это в случае, если приложение пытается сбросить частичную строку к консоли для непосредственного дисплея (такого как входная подсказка, индикатор хода выполнения, и т.д.), для переопределения буферизации нормали.

Если тот подход имеет проблемы с Вашим консольным выводом, буферизуемым слишком долго, Вы, возможно, должны были бы удостовериться, что WriteLine () сбрасывает stdoutWriter (но вероятно не должен сбрасывать fileWriter кроме тех случаев, когда Ваш Сброс () переопределение называют). Но я думал бы что оригинал Console.Out (на самом деле идущий в консоль), автоматически сбросил бы ее буфер на новую строку, таким образом, Вам не придется вызвать ее.

Вы могли бы также хотеть переопределить Близко () к (сброс, и) закрывают Ваш fileWriter (и вероятно stdoutWriter также), но я не уверен, необходимо ли это действительно или если бы Завершение () в основном TextWriter выпустило бы Сброс () (который Вы уже переопределили бы), и Вы могли бы полагаться на выход приложения для закрытия файла. Необходимо, вероятно, протестировать это, это сбрасывается на выходе, чтобы быть уверенным. И знайте, что аварийный выход (катастрофический отказ), вероятно, не сбросит буферизованный вывод. Если это - проблема, сбрасывая fileWriter на новой строке может быть желательным, но это - другая хитрая куча проблем для разработки.

0
ответ дан 4 December 2019 в 01:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: