Как еще можно оптимизировать этот код для защитного программирования?
Для моего проекта структур данных цель состоит в том, чтобы прочитать в предоставленном файле, содержащем более 10000 песен, с четко обозначенным исполнителем, названием и текстом, и каждая песня отделена строкой с одной двойной кавычкой. Я написал этот код для разбора текстового файла, и он работает со временем выполнения чуть менее 3 секунд, чтобы
прочитайте 422K строк текста
создать объект Song
добавить сказанную песню в ArrayList
Код синтаксического анализа, который я написал:
if (songSource.canRead()) { //checks to see if file is valid to read
readIn= new Scanner(songSource);
while (readIn.hasNextLine()) {
do {
readToken= readIn.nextLine();
if (readToken.startsWith("ARTIST=\"")) {
artist= readToken.split("\"")[1];
}
if (readToken.startsWith("TITLE=\"")) {
title= readToken.split("\"")[1];
}
if (readToken.startsWith("LYRICS=\"")) {
lyrics= readToken.split("\"")[1];
} else {
lyrics+= "\n"+readToken;
}//end individual song if block
} while (!readToken.startsWith("\"")); //end inner while loop
songList.add(new Song(artist, title, lyrics));
}//end while not EOF
} //end if file can be read
Я говорил с моим профессором "Введение в алгоритмы" о коде для этого проекта, и он заявил, что я должен стараться быть более осторожным в своем коде, чтобы учесть несоответствия в данных, предоставленных другими людьми. Первоначально я использовал блоки if/else между полями Artist, Title и Lyrics, и по его предложению я изменил на последовательные выражения if. Хотя я могу понять его точку зрения, используя этот пример кода, как я могу быть более осторожным в отношении учета несоответствий ввода?
6 ответов
Вы предполагаете, что ввод идеален. Если вы посмотрите на то, как ваше приложение в настоящее время настроено, на основании быстрого чтения вашего алгоритма данные будут выглядеть так
ARTIST="John"
TITLE="HELLO WORLD"
LYRICS="Sing Song All night long"
"
Но рассмотрим случай
ARTIST="John"
TITLE="HELLO WORLD"
LYRICS="Sing Song All night long"
"
ARTIST="Peter"
LYRICS="Sing Song All night long"
"
Основываясь на вашем алгоритме, теперь у вас есть 2 песни, которые характеризуются как
songList = { Song("JOHN", "HELLO WORLD", "Sing Song All night long"),
Song("Peter", "HELLO WORLD", "Sing Song All night long") }
В текущем алгоритме, художник и название выставляются и будут отображаться во 2-й песне, даже если они не были определены. Вам нужно сбросить три переменные.
в другом вы просто добавляете полную строку в тексты песен. Что, если вы уже вытащили тексты песен, теперь вы переопределяете это. Прецедент
ARTIST="John"
LYRICS="Sing Song All night long"
TILET="HELLO WORLD"
"
Рассмотрите возможность отправки этой записи в состояние ошибки. Поэтому, когда пакетное чтение завершено, отчет об ошибке может быть сгенерирован и исправлен.
Также вы рассматриваете EOF только после того, как художник был прочитан. Что, если EOF происходит во время чтения Artist, а файл не заканчивается на ". Вы собираетесь получить исключение там. В вашем do/while добавьте еще одну проверку для hasNextLine()
Я бы заменил например:
artist= readToken.split("\"")[1];
с
String[] parts = readToken.split("\"");
if(parts.length >= 2) artist = parts[1];
else continue;
Другие модификации будут включать:
- сбросить локальные переменные (чтобы случайно не выбрать исполнителя для песни, если для первой песни не указан исполнитель)
- решить, что делать, если некоторые данные отсутствуют - вы все еще хотите добавить песню в список песен?
В реальном мире существуют некоторые гарантии в отношении целостности данных. В случае с пользовательским вводом (будь то из стандартного ввода или файла) существует определенная парадигма проекта для уведомления пользователя о проблеме, требующей внимания.
Например, когда компилятор кода компилятора или оболочка, выполняющая сценарий, обнаруживают несоответствие, он может остановить и распечатать строку, содержащую несоответствие, со второй строкой под ним, которая использует символ "^" для указания местоположения проблемы.
Итак, вот несколько основных вопросов, которые нужно задать себе:
1. Гарантируется ли каждая строка каждого поля?
2. Гарантирован ли порядок полей?
Если это условия входного контракта и они нарушены, вам следует игнорировать / сообщать о строке. Если они не являются условиями ввода, то вам нужно обработать это.. что вы в настоящее время не делаете.
Я вижу пару вещей, которые здесь отсутствуют, Джейсон.
Я думаю, что если / еще было хорошо, и это не изменит логику. Однако вы должны максимально ограничить область действия ваших переменных. Объявляя Artist, Title и т. Д. Внутри цикла while, они будут инициализированы нулем (или чем-то еще), поэтому, если в записи отсутствует исполнитель, она не получит значение последней записи.
Кроме того, что произойдет, если в названии, исполнителе и т. Д. Есть цитата? Как это обрабатывается? Как насчет Лирики, которая, кажется, состоит из нескольких строк правильно?
Что произойдет, если есть неизвестное поле - возможно, опечатка? Это будет добавлено в конец Лирики, которая кажется неправильной. Только после того, как поле LYRICS было найдено, вы можете добавить к нему. Если лирика нулевая, то она начнется с "нулевой".
Разобраться с исключениями (я полагаю, сканер может вызвать исключение InputMismatchException для недопустимого символа).
Похоже, do { } while (...)
может зацикливаться бесконечно, если файл плохо сформирован, и конец файла достигнут.
Ничто не мешает artist
или же title
от того, чтобы быть пустым.
Вот несколько вопросов, которые можно решить:
В вашем коде предполагается, что перед (например) "ARTIST" нет пробелов, нет знака "=" и т. Д.
В вашем коде предполагается, что ключевые слова указаны заглавными буквами. Кто-то может использовать строчные или смешанные буквы.
Ваш код предполагает, что строка, которая не начинается с
keyword=\"
является продолжением песни. Но что, если пользователь вошелARTOST="Sting"
? Или что, если пользователь попытался использовать две строки для имени исполнителя?
Наконец, я не уверен, что замена "else if" на "if" в этом случае повлияла на надежность кода.