【问题标题】:Is it possible to make a catch block that waits until the whole try block is executed?是否可以创建一个等待整个 try 块执行的 catch 块?
【发布时间】:2018-08-16 20:39:52
【问题描述】:

我在做什么

我正在尝试制作一个更简洁的嵌套 try catch 块,同时我正在解决一个非常基本的异常问题。我正在制作一个可以做很多事情的计算器。然而,在此之前,它必须将用户输入作为字符串接收,并将它们转换为浮点数或整数。我通过简单地调用 java 的内置 parseInt 和 parseFloat 函数来做到这一点。现在我正在使用嵌套的 try catch 块来执行此操作:

String stringToParse = "1.0"
try{Integer.parseInt(stringToParse);}
catch(NumberFormatException n){
    try{Float.parseFloat(stringToParse);}
    catch(NumberFormatException n){
        System.out.println(n)
        }
    }

为什么会有这样的问题?

这对我来说很混乱,我宁愿有一个 try 块来收集错误但不会立即转到 catch 块,而是执行整个 try 并在 try 执行后捕获任何错误。我自己做了一个可运行的例子来展示我想要的:

    String num = "1.0";
    int i = 0;
    ArrayList<Object> listofResults = new ArrayList<>();
    ArrayList<Integer> listOfErrorIndices = new ArrayList<>();
    try {
        listofResults.add(Integer.parseInt(num));
        i++;
        listofResults.add(Float.parseFloat(num));
        i++;
        listofResults.add(Integer.parseInt(num));
    } catch (NumberFormatException n) {
        listOfErrorIndices.add(i);
    }
    for (Integer element:listOfErrorIndices) {
        System.out.println(element);
        //this currently prints out 0 and I want it to print out both 0 and 
        //2 so that it catches both errors.
    }

我对如何解决问题的想法/我尝试过的其他方法

我的计划是收集在尝试中抛出的所有NumberFormatException 索引 (i) 的列表。每次我尝试解析字符串时,都会在resultsList 中添加一个元素。我的目标是使用这个理论上的 try catch 块来获取所有异常的索引,然后如果它们抛出错误,则将它们从 resultsList 中删除。 TLDR;现在上面的代码打印出 0,我希望它打印出 0 和 2。基本上,我没有使用嵌套的 try catch 块,而是使用列表理解和异常处理索引来删除错误结果并只保留好的结果。我不知道这是否可能,因此这个问题。我已经查看了“实现嵌套 try catch 块的更好方法”问题,但这对我没有用,因为它在 delphi 中提供了一个解决方案,我不明白它是如何工作的,或者它是否像我一样工作想让我的工作。我起初认为 finally 块可能是我需要的,但它只在执行 catch 之后运行,或者如果没有异常,在 try 之后运行。我需要一些东西来推迟 catch 块,直到尝试完成,我想不出/找到任何这样做的东西。

你是什么,疯子?

现在你可能会问,这到底是什么意思?想象一下,如果您遇到上述问题,而不是两种方法来解析您拥有 10 或 100 的字符串。很快,使用嵌套的 try catch 块处理异常几乎是不可能的。我已经看到了 catch 块调用自定义异常方法的解决方案,该方法至少可以处理错误的格式。它看起来像这样:

try{
//bad code
}
catch{
    trysomethingelse();
}
trysomethingelse(){
//equally bad code
catch{
//ya done screwed up son
}
}

但是我不满意,因为这意味着您需要一百万个不同的方法名称才能潜在地处理一个错误。想象一下错误总是一样的,你只需要尝试 100 种不同的字符串解析方法。如果您尝试将字符串转换为数字,它总是会出现 numberformatException,那么为什么要为相同的错误设置一百万个 catch 块呢?我想尝试使用一个理论上的 catch 块来执行此操作,该块指定一个在 try 块中多次发生的错误。

【问题讨论】:

  • 只有一点:您可能不会/不应该尝试在一个块中解析字符串 100 次。
  • 如果发生异常,您不能忽略它并继续。如果Integer.parseInt 抛出异常,它不会返回任何东西。甚至没有null。你没有任何东西可以添加到你的列表中。
  • 您可以在每个 catch 中使用具有相同或相似代码的一堆小的 try/catch 构造,但这是一种基本的 Java 行为,当抛出异常时,它中断当前控制流并转到最里面适用的catchfinally。事实上,这几乎就是异常的定义特征。
  • 总是使用double(或BigDecimal)而不是尝试解析多种类型的数字会更简单。

标签: java parsing exception try-catch


【解决方案1】:

您构建一个解析器列表/数组,然后迭代该列表,为每个列表捕获异常。

使用 Java 8 方法引用,这真的很容易。首先,定义一个允许抛出异常的Parser函数接口:

@FunctionalInterface
public interface Parser {
    Object parse(String text) throws Exception;
}

接下来,构建你的解析器数组来尝试:

Parser[] parsers = {
        Integer::valueOf,
        Double::valueOf,
        BigInteger::new,
        BigDecimal::new
};

最后,一次尝试一个:

String text = "45.8";

Object[] results = new Object[parsers.length];
for (int i = 0; i < parsers.length; i++) {
    try {
        results[i] = parsers[i].parse(text);
    } catch (Exception e) {
        results[i] = e;
    }
}

现在你可以查看结果了:

for (Object result : results) {
    if (result instanceof Exception)
        System.out.println("Error: " + result);
    else
        System.out.println("Parsed as " + result.getClass().getSimpleName() + ": " + result);
}

输出

Error: java.lang.NumberFormatException: For input string: "45.8"
Parsed as Double: 45.8
Error: java.lang.NumberFormatException: For input string: "45.8"
Parsed as BigDecimal: 45.8

或者将解析的对象和异常放入两个不同的列表中。由你决定。

【讨论】:

    【解决方案2】:

    你可以这样做:

     interface Parser {
           Number parse(String);
     }
    
     class IntegerParser implements Parser {
        @Override
        public Number parse(String) {
             // implementation here
        }
     }
     class FloatParser implements Parser {
     }
    
     List<Parser> parsers = asList(new FloatParser(), new IntegerParser(), ...);
     Number result = null;
     List<NumberFormatException> exceptions = new ArrayList<>();
     for (Parser parser : parsers) {
         try {
             result = parser.parse(stringToParse);
             break;
         } catch (NumberFormatException e) {
             exceptions.add(e);
         }
     }
     if (result != null) {
        // parsed ok with some parser
        // probably discard exceptions
     } else {
        // show exceptions from the list
     }
    

    【讨论】:

      【解决方案3】:

      试试这个:

      public static void test() {
          final String num = "1.0";
          final ArrayList<Object> listofResults = new ArrayList<>();
          final java.util.function.Function<String, ?>[] parseMethods = new java.util.function.Function[3];
          parseMethods[0] = Integer::parseInt;
          parseMethods[1] = Float::parseFloat;
          parseMethods[2] = Integer::parseInt;
          int[] badIndeces = IntStream.range(0, parseMethods.length).map(i -> {
              try {
                  listofResults.add(parseMethods[i].apply(num));
                  return -i-1;
              } catch (NumberFormatException exc) {
                  return i;
              }
          }).filter(i -> i >= 0).toArray();
          for (int element : badIndeces) {
              System.out.println(element);
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2020-12-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-01
        相关资源
        最近更新 更多