True-way solution in Java: parse 2 numbers out of 2 lines and then return their sum

Pretty silly question. Based on the code:

public static int sum(String a, String b) /* throws? WHAT? */ { int x = Integer.parseInt(a); // throws NumberFormatException int y = Integer.parseInt(b); // throws NumberFormatException return x + y; } 

Could you say whether this is good Java or not? I am saying that NumberFormatException is an exception. You do not have to specify it as part of the sum() signature. Moreover, as I understand it, the idea of ​​unchecked exceptions is to signal that the implementation of the program is incorrect, and even more, catching unchecked exceptions is a bad idea, since it is like fixing a bad program at runtime.

Someone please clarify if:

  • I have to specify a NumberFormatException as part of the method signature.
  • I have to define my own checked exception ( BadDataException ), handle a NumberFormatException inside the method and throw it as BadDataException .
  • I have to define my own test exception ( BadDataException ), check both lines in some way, like regular expressions, and throw my BadDataException if they do not match.
  • Your idea

Update

Imagine that this is not an open source infrastructure that you should use for some reason. You look at the signature of the method and think - "OK, it never throws." Then, someday, you get an exception. This is normal?

Update 2 :

There are a few comments saying that my sum(String, String) bad design. I absolutely agree, but for those who believe that the original problem simply will not appear if we have a good design, here's another question:

The problem definition looks like this: you have a data source where numbers are stored as String s. This source can be an XML file, a web page, a desktop window with 2 edit fields, whatever.

Your goal is to implement logic that takes these 2 String s, converts them to int and displays a message box that says: "sum xxx".

No matter which approach you use to develop / implement this, you will have these two points of internal functionality:

  • The place where you convert String to int
  • The place where you add 2 int s

The main question of my original post:

Integer.parseInt() expects the correct string to be passed. Whenever you pass a bad string, it means that your program is incorrect (and not "your user idiot"). You need to implement a code fragment in which, on the one hand, you have Integer.parseInt () with MUST semantics, and on the other hand, you need to be in order with cases when the input is incorrect - SHOULD use semantics.

So, briefly: how can I implement SHOULD semantics if I only have MUST libraries.

+84
java exception parsing
Aug 25 '11 at 11:23
source share
18 answers

That's a good question. I want more people to think about such things.

IMHO, throwing unchecked exceptions is acceptable if you have passed the garbage options.

Generally speaking, you should not throw BadDataException , because you should not use Exceptions to control the flow of the program. Exceptions for exceptional. Callers to your method may know before they call it if their lines are numbers or not, so garbage switching can be avoided and, therefore, can be considered a programming error, which means that it should make excepted exceptions.

Regarding the throws NumberFormatException is not that useful, because few will notice that a NumberFormatException is not set. However, the IDE can use it and suggest try/catch correctly. A good option is to use javadoc, for example:

 /** * Adds two string numbers * @param a * @param b * @return * @throws NumberFormatException if either of a or b is not an integer */ public static int sum(String a, String b) throws NumberFormatException { int x = Integer.parseInt(a); int y = Integer.parseInt(b); return x + y; } 

EDITED :
Browsers made valid points. You need to think about how this will be used and the overall design of your application.

If the method will be used universally, and it is important that all callers cause problems, declare the method as throwing a checked exception (causing callers to solve problems), but cluttering up the code with try/catch blocks.

If, on the other hand, we use this method with data that we trust, and then declare it as described above, because it is not expected to ever explode, and you avoid randomly cloning unnecessary try/catch blocks.

+35
Aug 25 '11 at 11:32
source share

In my opinion, it would be preferable to handle the logic of exceptions as far as possible. Therefore, I would prefer a signature

  public static int sum(int a, int b); 

With your method signature, I would not change anything. Or you

  • Programmatically using incorrect values, where instead you can check your producer algorithm
  • or sending values, for example, user input, in which case this module should check

Therefore, exception handling in this case becomes a documentation problem.

+49
Aug 25 '11 at 11:29
source share

Number 4. As indicated, this method should not take strings as parameters that must accept integers. In this case (since java wraps instead of overflow) there is no possibility of an exception.

  x = sum(Integer.parseInt(a), Integer.parseInt(b)) 

much clearer what is meant than x = sum(a, b)

You want the exception to occur as close to the source (input signal) as possible.

As for options 1-3, you are not defining an exception because you expect your subscribers to assume that otherwise your code cannot fail, you are defining an exception to determine what happens under known conditions of failure that are unique to you METHOD. That is, if you have a method that is a wrapper around another object, and it throws an exception and then passes it. Only if the exception is unique to your method, you should throw a custom exception (frex, in your example, if the amount were to only return positive results, then checking this and throwing an exception would be appropriate if, on the other hand, java throws an overflow exception instead of wrapping, then you pass it on, don’t define it in your signature, rename it or eat it).

Update in response to an update of a question:

So, briefly: how can I implement SHOULD semantics if I only have MUST libraries.

The solution to this is to wrap the MUST library and return the SHOULD value. In this case, a function that returns an integer. Write a function that takes a string and returns an Integer object — either it works or returns null (for example, guava Ints.tryParse). Do your verification separately from your operation, your operation should take ints. Regardless of whether your operation is called with default values, when you have invalid input or something else depends on your specifications - what can I say about this is that it is actually unlikely that there is room for In making this decision, the method was implemented.

+5
Aug 25 '11 at 16:35
source share

1. I must specify a NumberFormatException as part of the method signature.

I think so. This is good documentation.

2. I have to define my own checked exception (BadDataException exception), throw a NumberFormatException inside the method and re-throw it as a BadDataException.

Sometimes yes. Checked exceptions are considered the best in some cases, but working with them is pretty PITA. Therefore, many frameworks (like Hibernate) only use runtime exceptions.

3. I have to define my own checked exception (BadDataException), check both lines in some way as regular expressions, and throw a BadDataException if it doesn't match.

Never. More work, less speed (unless you expect the exception to become the rule) and you won’t get it at all.

4. What is your idea?

Not at all.

+3
Aug 25 2018-11-11T00:
source share

Nr 4.

I think that this method would not change at all. I would put an attempt to catch a call method or higher in the stack trace, where I am in a context where I can gracefully restore business logic from an exception.

I'm not sure if this will be # 3, as I find it redundant.

+2
Aug 25 '11 at 11:30
source share

Assuming that what you write will be consumed (like an API, for example) by someone else, then you should go with 1, NumberFormatException is specifically designed to pass such exceptions and should be used.

+2
Aug 25 '11 at 11:45
source share
  • First you need to ask yourself if the user of my method can worry about entering the wrong data, or should he wait for the correct data to be entered (in this case, String). This expectation is also known as design contract .

  • and 3. Yes, you should probably define a BadDataException or even better use some of the exceptions, such as NumberFormatException, but rather leave a standard message for display. Catch a NumberFormatException in the method and throw it using your message, remembering to include the original stack trace.

  • It depends on the bu situation, I would probably go with a rethrow of a NumberFormatException with some additional information. And there should also be an explanation of javadoc what are the expected values ​​for String a, String b

+2
Aug 25 2018-11-21T00:
source share

Depends on which scenario you are in.

Case 1. You always debug it, and no one else and an exception causes a bad user experience.

Throw a default NumberFormatException

Case2: The code should be extremely user-friendly.

Define your own exception and add a lot more data to debug when throwing it.

You do not need regular expression checks, since in any case it will throw an exception if the input is unsuccessful.

If it were performance level code, my idea would be to define more than one user exception, like

  • Format Number Exception
  • Overflow exception
  • Null exception, etc.

and handle all these individual

+1
Aug 25 '11 at 11:32
source share
  • You can do this to make it clear that this can happen for incorrect input. This may help someone using your code to remember this situation. More specifically, you make it clear that you yourself do not process it in the code or return a specific value. Of course, JavaDoc should do this too.
  • Only if you want to force the caller to work with a checked exception.
  • This is like busting. Rely on parsing to detect bad input.

Overal, a NumberFormaException is not thrown because the correct syntax input is expected to be provided. Validating input is what you need. However, actually parsing the input is the easiest way to do this. You can simply leave your method as it is and warn in the documentation that the correct input is expected, and anyone who calls your function should check both inputs before use.

+1
Aug 25 '11 at 11:33
source share

Although I agree with the answer that a runtime exception should be skipped, in terms of design and usability, it would be nice to include it in an IllegalArgumentException, rather than throwing it as a NumberFormatException. This will then simplify the contract of your method, in which it declares that an illegal argument was passed to it, due to which it made an exception.

Regarding the update to the question “Imagine that this is not an open source framework that you should use for some reason. You look at the signature of the method and think“ OK, it never throws. ”Then, someday, You are Excluded. Is this normal? The javadoc of your method should always distinguish between the behavior of your method (pre and post constraints). Think of collection interface lines in which if, if null is not allowed, javadoc says that a null pointer exception will be thrown, although it will never not part of the method signature.

+1
Aug 25 2018-11-11T00:
source share

Any exceptional behavior should be clarified in the documentation. Either it should indicate that this method returns a special value in case of failure (for example, null , by changing the return type to Integer ), or case 1 should be used. The presence of an explicit method in the signature allows the user to ignore it if it provides the correct lines in other ways , but it’s still obvious that the method does not cope with this failure on its own.

+1
Aug 25 2018-11-11T00:
source share

Answer the updated question.

Yes, it’s normal to get an “unexpected” exception. Think about all the runtime errors that were received when creating new programs.

 eg ArrayIndexOutofBound 

Also a common surprise for each cycle.

 ConcurrentModificationException or something like that 
+1
Aug 25 '11 at 11:45
source share

As you say good Java practice, I think it's always better

  • To handle an unchecked exception, analyze it with a special exception.

  • In addition, when a special exception is thrown, you can add an exception message that your client can understand, as well as print a stack trace of the original exception.

  • It is not necessary to declare a custom exception as a "throw" because it is not marked.

  • Thus, you do not violate the use of excluded exceptions, at the same time, the code client easily understands the reason and solution for the exception.

  • Also properly documenting in java-doc is good practice and helps a lot.

+1
Aug 25 '11 at 13:44
source share

I think it depends on your goal, but I would document this at least:

 /** * @return the sum (as an int) of the two strings * @throws NumberFormatException if either string can't be converted to an Integer */ public static int sum(String a, String b) int x = Integer.parseInt(a); int y = Integer.parseInt(b); return x + y; } 

Or take a page from the Java source code for the java.lang.Integer class:

 public static int parseInt(java.lang.String string) throws java.lang.NumberFormatException; 
+1
Aug 25 '11 at 19:48
source share

There are many interesting answers to this question. But I still want to add this:

For parsing strings, I always prefer to use "regular expressions". The java.util.regex package should help us. This way I will end up with something like this that never raises any exceptions. I need to return a special value if I want to catch an error:

 import java.util.regex.Pattern; import java.util.regex.Matcher; public static int sum(String a, String b) { final String REGEX = "\\d"; // a single digit Pattern pattern = Pattern.compile(REGEX); Matcher matcher = pattern.matcher(a); if (matcher.find()) { x = Integer.matcher.group(); } Matcher matcher = pattern.matcher(b); if (matcher.find()) { y = Integer.matcher.group(); } return x + y; } 

As you can see, the code is a little longer, but we can process what we want (and set default values ​​for x and y, control what happens with else clauses, etc.) We could even write a more general conversion procedure, to which we can pass strings, defaut return values, REGEX code for compilation, error messages for throw, ...

Hope this was helpful.

Warning: I could not verify this code, so please excuse the possible syntax problems.

+1
Aug 31 2018-11-11T00:
source share

What about the input validation pattern implemented by the Google 'Guava' library or the Apache 'Validator' library ( comparison )?

In my experience, it is considered good practice to check function parameters at the beginning of a function and, if necessary, throw exceptions.

In addition, I would find this question largely independent of the language. The “good practice” here applies to all languages ​​that have functions that may take parameters, which may or may not be valid.

+1
Aug 31 2018-11-11T00:
source share

I think your first sentence, “Pretty dumb question,” is very relevant. Why would you ever write a method with this signature? Does it make sense to sum two lines? If the calling method wants to sum two lines, it is the responsibility of the calling method to ensure that they are valid int and convert them before calling the method.

In this example, if the calling method cannot convert two strings to int, it can do several things. Actually, it depends on which layer this summation is on. I assume that the String conversion would be very close to the interface (if it were done correctly), so case 1 is most likely.

  • Set error message and stop processing or redirect to error page
  • Returns false (i.e. it puts the sum in some other object and is not required to return it).
  • Throw some BadDataException that you are suggesting, but if summing these two numbers is very important, it is too much, and as mentioned above, this is probably a bad design, as it means the conversion is being performed in the wrong place
+1
Aug 31 '11 at 16:16
source share

You run into this problem because you make user errors that propagate too deeply into the core of the application, and also because you abuse Java data types.

You should have a clear separation between input validation and business logic, using the correct data entry, and this problem will go away by itself.

The known fact of the semantics of Integer.parseInt() is the primary goal - to analyze real integers. You are missing the explicit step of validating / analyzing user input.

0
Oct 11 '13 at 20:05
source share



All Articles