Как правильно вернуть значение из блока try-catch? - PullRequest
0 голосов
/ 30 апреля 2019

Пример, который не работает из-за отсутствия возвращаемого значения:

public Path writeToFile() {
    try {
        Path tempFilePath = Files.createTempFile(Paths.get(""), "sorting_test_", ".txt");
        BufferedWriter bw = new BufferedWriter(new FileWriter(tempFilePath.toFile()));

        for (List<Integer> arr : arrays) {
            // Convert array ints to strings, join it to single string and write
            bw.write(arr.stream()
                    .map(String::valueOf)
                    .collect(Collectors.joining(" ")));
            bw.newLine();
        }
        bw.close();

        return tempFilePath;
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Я знаю, что могу сделать так:

public Path writeToFile() {
    Path tempFilePath = null;
    //try-catch{...}
    return tempFilePath;
}

Но выглядит ужасно. Есть ли более естественный способ решить эту задачу?

Ответы [ 5 ]

2 голосов
/ 30 апреля 2019

Вот несколько возможных решений:

  • Измените сигнатуру метода на public void writeToFile(). Не возвращайте Path. (Но это, вероятно, не сработает для вас: вам, вероятно, нужно Path.)

  • Добавьте return null; в конце метода. Это имеет недостаток, заключающийся в том, что вызывающий должен иметь дело со случаем, когда null возвращается ... иначе он получит NPE, когда они попытаются использовать несуществующий Path.

    Это эквивалентно вашему "уродливому" решению. Это спорно, что лучше с точки зрения стилистической. (Догматичный человек "структурированного программирования" сказал бы, что ваш путь лучше!)

  • Измените подпись, чтобы она возвращалась как Optional<Path>. Это лучшая альтернатива, чем возвращение явного null. Если вы реализуете это правильно, вызывающая сторона фактически вынуждена иметь дело с «отсутствующим» случаем.

  • Удалите try catch и измените сигнатуру метода на public Path writeToFile() throws IOException. Вызывающий должен иметь дело с проверенным исключением, но это может быть хорошо!


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

1 голос
/ 30 апреля 2019

Наиболее подходящий способ - сохранить оператор return в блоке try.

Если мы сохраним инструкцию return в finally или после catch, мы можем проглотить исключение.

Это старая ссылка, которая кажется связанной. Посмотрите, поможет ли это.

1 голос
/ 30 апреля 2019

Другое решение, вместо того, чтобы есть IOException (антипаттерн), преобразовать его в соответствующий подкласс RuntimeException и выбросить из блока catch.

Кроме того, в вашем примере вы пропускаете файлобработчик, не закрывая FileWriter в исключительной ситуации.

public Path writeToFile() {

    final Path tempFilePath;
    try {
        tempFilePath = Files.createTempFile(Paths.get(""), "sorting_test_", ".txt");
    } catch (IOException e ) {
        throw new MyRuntimeException(
                "Cannot create sorting_test temp file",
                e
            );
    }

    try (final FileWriter fw = new FileWriter(tempFilePath.toFile())) {
        try(final BufferedWriter bw = new BufferedWriter(fw)) {
            for (List<Integer> arr : arrays) {
                // Convert array ints to strings, join it to single string and write
                bw.write(arr.stream()
                    .map(String::valueOf)
                    .collect(Collectors.joining(" ")));
                bw.newLine();
            }
        }

        return tempFilePath;
    } catch (IOException e) {
        throw new MyRuntimeException(
                "Cannot write to " + tempFilePath,
                e
            );
    }
}
1 голос
/ 30 апреля 2019

Я не знаю, почему вы ищете более «естественное» решение, но вы можете просто return null в своем блоке catch.

1 голос
/ 30 апреля 2019

Если вы не хотите возвращать null, я бы предпочел использовать Optional из Java 8

public Optional<Path> writeToFile() {
    try {
        Path tempFilePath = Files.createTempFile(Paths.get(""), "sorting_test_", ".txt");
        BufferedWriter bw = new BufferedWriter(new FileWriter(tempFilePath.toFile()));

        for (List<Integer> arr : arrays) {
            // Convert array ints to strings, join it to single string and write
            bw.write(arr.stream()
                    .map(String::valueOf)
                    .collect(Collectors.joining(" ")));
            bw.newLine();
        }
        bw.close();

        return Optional.of(tempFilePath);
    } catch (IOException e) {
        e.printStackTrace();
    }
   return Optional.empty()
}

Так что в методе вызова вы можете использовать

public void ifPresent (Потребительский потребитель)

или

public boolean isPresent ()

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