How to catch an NSRangeException with do...catch? - java

I am translating this Java code to swift:
for (int i = 0 ; i < groups.length ; i++) {
try {
groups[i] = integerPart.substring (i * 3, i * 3 + 3);
} catch (IndexOutOfBoundsException ex) {
groups[i] = integerPart.substring (i * 3);
}
groups[i] = new StringBuilder (groups[i]).reverse ().toString ();
groups[i] = get1To3DigitString (groups[i]) + " " + getTheWord (i) + " ";
}
Note:
integerPart is a string.
groups is a string array.
please ignore get1To3DigitString and getTheWord.
My thoughts and tries:
Since swift's string is really annoying (can't be indexed with Int), I decided to use NSString's substringFromIndex and substringWithRange methods to do the substring Java method. So I wrote these 2 methods to help me:
func substring (s: String, start: Int, end: Int) throws -> String{
let ns = NSString(string: s)
return String(ns.substringWithRange(NSRange(start..<end)))
}
func substring (s: String, start: Int) -> String {
let ns = NSString(string: s)
return String(ns.substringFromIndex(start))
}
And I know that the two substring methods from NSString throws an NSRangeException, just like Java's IndexOutOfBoundsException. So here's my swift code:
for var i = 0 ; i < groups.count ; i++ {
do {
try groups[i] = substring(integerPart, start: i * 3, end: i * 3 + 3)
} catch NSRangeException {
groups[i] = substring(integerPart, start: i * 3)
}
groups[i] = String (groups[i].characters.reverse())
groups[i] = get1To3DigitString (groups[i]) + " " + getTheWord (i) + " "
}
And I get an error saying the catch pattern does not match ErrorType! I thought it does match ErrorType, because if it doesn't, how am I supposed to catch the exception? So I deleted the word NSRangeException.
I thought if an exception is thrown in substring, I would catch it in the catch part. But when I tested it, an exception occurred on the try line! I think this is because I wrote the catch pattern incorrectly.
How should I catch NSRangeException?

Just like in Java you never ever ever catch a IndexOutOfBoundsException you never ever ever catch a NSRangeException in Swift or Objective-C.
Those exceptions are caused because you as the developer screwed up, not the application or some outside factor, or the user with his input. In Java you have the term checked exceptions and unchecked exceptions. The first one you can and should or even have to catch, the second ones occur at runtime and signal mostly bugs in the program.
You simply must not substring a String of length 5 until its tenth char - that is something you as the developer could and have to know and be aware of. If you do this, the program should crash.
I am not sure if you actually can catch a NSRangeException - I would be very happy if you cannot do it. For regular Errors you define custom errors types:
enum LevelParsingException : ErrorType {
case MalformedJson
case InvalidLevelContent
}
Then you have some function which might throw them:
func parseLevel() throws {
guard someCondition {
throw LevelParsingException.InvalidLevelContent
}
}
And then you call that method and catch all the different errors that you know might arise:
func call() {
do {
try parseLevel()
} catch LevelParsingException.InvalidLevelContent {
print("something")
} catch {
print("something else")
}
}
The apple docs explain that all relatively well.

Related

Making a Java Scanner program be more robust?

I don't normally do Java in my daily work, although I wish I did since there is a class for everything (sometimes too many). Yesterday I spent the bulk of my day writing the program below. Tiny rant: java.util.scanner is less than intuitive, IMO. What I want to do with it is to scan a log file for two certain patterns and do some date arithmetic on it and print the results. This program works if I take my log file and delete non-matching lines then run it. I can do this with vi, sed, whatever, but I'm more interested in taking this utility and making it more usable for someone who isn't as comfortable with shell scripting or using vi. I'll be hammering on this a little more today but I wonder if there is some expertise here that can make me move forward more quickly.
import java.util.*;
import java.util.concurrent.*;
import java.text.SimpleDateFormat;
import java.util.regex.Pattern;
import java.util.regex.MatchResult;
import java.io.*;
import java.time.*;
import java.time.format.*;
public class TimeDiff {
private static SimpleDateFormat m_formatter = new SimpleDateFormat("yyyy-MM-dd-HH.mm.ss");
private static Pattern m_startRunPattern = Pattern.compile("start of run=([^,]+)");
private static Pattern m_currentTimePattern = Pattern.compile("current time=(.+)");
private String m_fileArg;
private File m_file;
private Scanner m_scanner;
public TimeDiff(String[] args)
{
if (args.length == 0) {
System.err.println("nope.");
System.exit(1);
}
m_fileArg = args[0];
m_file = new File(m_fileArg);
}
public String findPattern(Scanner fileScan, Pattern pattern)
{
String ret_val = null;
try {
ret_val = fileScan.findInLine(pattern);
MatchResult result = fileScan.match();
if (result.groupCount() > 0) {
ret_val = result.group(1);
}
}
catch (java.util.InputMismatchException e) {
System.out.println("failed at second");
}
catch (java.lang.IllegalStateException e) {
System.out.println("failed at second match " + e);
}
return ret_val;
}
public void run(String[] args) throws Exception
{
try (Scanner fileScan = new Scanner(m_file)) {
while (fileScan.hasNext()) {
String beginTimeStr = findPattern(fileScan, m_startRunPattern);
String endTimeStr = findPattern(fileScan, m_currentTimePattern);
if (beginTimeStr == null && endTimeStr == null) {
if (fileScan.hasNext()) {
fileScan.next();
}
}
else {
Date startDate = m_formatter.parse(beginTimeStr);
Date endDate = m_formatter.parse(endTimeStr);
long duration = endDate.getTime() - startDate.getTime();
long diffInSeconds = TimeUnit.MILLISECONDS.toSeconds(duration);
long diffInMinutes = TimeUnit.MILLISECONDS.toMinutes(duration);
long remainderSeconds = 0;
if (diffInMinutes > 0) {
remainderSeconds = diffInSeconds % diffInMinutes;
}
else {
remainderSeconds = diffInSeconds;
}
System.out.println("elapsed seconds: " + diffInSeconds + ", (" + diffInMinutes + " minutes, " + remainderSeconds + " seconds).");
if (fileScan.hasNext()) {
fileScan.next();
}
}
}
}
catch (IOException exception) {
System.out.println(exception);
}
}
public static void main(java.lang.String args[])
{
try {
TimeDiff app = new TimeDiff(args);
app.run(args);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
The massaged log file entries look like:
DealWithResponse.cpp, DealWithResponse(XMLSocketApp &, DOMDocument *), 247 2020-07-29 17:54:13 start of run=2020-07-29-17.53.31.216800, current time=2020-07-29-17.54.13.530384
DealWithResponse.cpp, DealWithResponse(XMLSocketApp &, DOMDocument *), 247 2020-07-29 17:54:13 start of run=2020-07-29-17.53.29.903984, current time=2020-07-29-17.54.13.805200
DealWithResponse.cpp, DealWithResponse(XMLSocketApp &, DOMDocument *), 247 2020-07-29 17:54:13 start of run=2020-07-29-17.53.14.356440, current time=2020-07-29-17.54.13.907528
DealWithResponse.cpp, DealWithResponse(XMLSocketApp &, DOMDocument *), 247 2020-07-29 23:16:01 start of run=2020-07-29-23.15.27.722784, current time=2020-07-29-23.16.01.016640
DealWithResponse.cpp, DealWithResponse(XMLSocketApp &, DOMDocument *), 247 2020-07-29 23:16:04 start of run=2020-07-29-23.15.39.955272, current time=2020-07-29-23.16.04.418160
DealWithResponse.cpp, DealWithResponse(XMLSocketApp &, DOMDocument *), 247 2020-07-29 23:16:05 start of run=2020-07-29-23.15.52.154920, current time=2020-07-29-23.16.05.480384
Of course, what the rest of the log file looks like contains business logic stuff (SQL, etc).
From the docs of Scanner's findInLine:
Attempts to find the next occurrence of the specified pattern ignoring delimiters. If the pattern is found before the next line separator, the scanner advances past the input that matched and returns the string that matched the pattern. If no such pattern is detected in the input up to the next line separator, then null is returned and the scanner's position is unchanged. This method may block waiting for input that matches the pattern.
What you're observing is findInLine not finding anything matching the pattern specified before hitting a newline, and thus returning null and not changing the position whatsoever.
Perhaps findWithinHorizon(pattern, 0) is more to your liking? This will keep looking, forever (until end of input) if need be, until it finds a match on your regexp.
It then returns the match. If you need the entire line, just expand on your regexp: "^.*current time = (.*)$" would always match an entire line.
A second tip: your exception handling is atrocious. if you catch an exception, handle it. 'print some text and carry right on as if nothing is wrong' is not handling it. Trivial solution: add throws Exception onto your main method (which is almost always a good idea in any case). Then just.. get rid of every try{ and catch{} block in your code. Makes it way shorter and easier to read, and better to boot!

Recursive command parser that solves a repeat statement

I am building a parser that recognizes simple commands such as "DOWN.", "UP." and "REP 3.". It must be able to parse the commands rather freely. It should be legal to write
"DOWN % asdf asdf asdf
."
Where % represents a comment and the fullstop signifying end-of-command. This fullstop can be on the next line.
This is all good and well so far, however I'm struggling with the Rep part (represents Repeat.)
I should be able to issue a command as follows:
DOWN .DOWN. REP 3 " DOWN. DOWN.
DOWN . % hello this is a comment
REP 2 " DOWN. ""
This should give me 17 DOWNS. The semantics is as follows for repeat: REP x " commands " where x is the amount of times it shall repeat the commands listed inside the quotation marks. Note that REP can be nested inside of REP. The following code is for handling the DOWN command. The incoming text is read from System.in or a text file.
public void repeat(String workingString) {
if (workingString.matches(tokens)) {
if (workingString.matches("REP")) {
repada();
} else
if (workingString.matches("(DOWN).*")) {
String job = workingString.substring(4);
job = job.trim();
if (job.equals("")) {
String temp= sc.next();
temp= temp.trim();
// Word after DOWN.
if (temp.matches("\\.")) {
leo.down()
// If word after DOWN is a comment %
} else if (temp.matches("%.*")) {
boolean t = comment();
} else {
throw SyntaxError();
}
} else if (job.matches("\\..*")) {
workingString += job;
System.out.println("Confirm DOWN with .");
}
} else if (workingString.matches("\\.")) {
instructions += workingString;
System.out.println("Fullstop");
} else if (workingString.matches("%.*")) {
comment();
} else {
// work = sc.next();
work = work.trim().toUpperCase();
System.out.println(work);
}
} else {
System.out.println("No such token: " + workingString);
}
}
I got a working start on the repeat function:
public String repada(){
String times = sc.next();
times.trim();
if (times.matches("%.*")) {
comment();
times = sc.next();
}
String quote = sc.next();
quote.trim();
if(quote.matches("%.*")){
comment();
quote = sc.next();
}
String repeater = "";
System.out.println("REP " + times + " "+quote);}
However I'm thinking my whole system of doing things might need a rework. Any advice on how I could more easily solve this issue would be greatly appreciated!

Java else part is not getting executed

I am having a piece of if-else code to check if a string is displayed, to my surprise the Else part is not getting executed at all.
For eg: If the error string is shown, the IF part works fine. In cases where the error string is not shown, the Else part is not getting executed. Kindly help
if(getErrText.length() > 0) {
System.out.println(getErrText + " For "+ readerIterator);
} else {
System.out.println(" Error is not displayed - Err Cell" + " For "+ readerIterator);
}
When I make a few assumptions,
public static void main(String[] args) {
String getErrText = ""; // <--------------- To trigger else.
String readerIterator = "Yes it is"; // <-- To display a message.
if (getErrText.length() > 0) { // <-------- else means that getErrText **must** be ""
System.out.println(getErrText + " For "
+ readerIterator);
} else {
System.out.println("Error is not displayed "
+ "- Err Cell For " + readerIterator);
}
}
Output is
Error is not displayed - Err Cell For Yes it is
As I would expect.
Edit
As per comment(s), your actual problem is likely to be one of
// trim() the String!
if (getErrText != null && getErrText.trim().length() > 0) {
// as before...
}
or silently swallowing your exception. Please don't do that.
try {
getErrText = toSearch.errorCell.getText();
getErrText = (getErrText != null) ? getErrText.trim() : "";
}catch(Exception e){
e.printStackTrace();
}
You are probably enclosing this within a block where error is set which is why your getErrText length is always greater than zero.
Could you please add your enclosing code for getting the error text please
In case you else is not getting executed, print the if part of your code and debug.
If both your if and else dont get executed, then the flow is not reaching your if-else at all for those scenarios .
To find out your problem, print the error on your else:
System.out.println(" Error is not displayed - Err Cell" + " For "+ readerIterator+" The getErrText is ["+getErrText+"]);

unexpected behavior in java exception flow

I have written following code snippet:-
public Collection<?> constructResponse (...........) throws RemoteException {
while (keyIterator.hasNext())
{
String keyValue = (String) keyIterator.next();
keyString = new StringBuilder(); // since multiple keys will be there in map need to ensure every time keyString and valueString is created
valueString = new StringBuilder();
keyString.append(keyValue + ";" + "name");
List<CustomValuePOJO> customPOJOlist = employeeValuesMap.get(keyValue );
for (CustomValuePOJO customPOJO : customPOJOlist )
{
if (protocol == null || protocol.equals(""))
{
valueString.append(rpNatPOJO.getDcnPort() + ":"+ rpNatPOJO.getProtocol() + ";");
}
else if (customPOJO .getProtocol().equals(protocol))
{
valueString.append(customPOJO .getPort() + ":"+ protocol + ";");
}
else
{ throw new RemoteException("Invalid Argument: Unsupported protocol "+ protocol);
}
}
if (valueString.length() == 0)
{
return generateErrorResponse("No info found");
}
responseMap.put(keyString.toString(), valueString.toString());
}
}
The weird behavior which is happening is that while iterating through the customPOJO its coming inside elseIf and also setting the value in valueString by executing below code:
else if (customPOJO .getProtocol().equals(protocol))
{
valueString.append(customPOJO .getPort() + ":"+ protocol + ";");
}
After this elseif its coming directly on line
throw new RemoteException("Invalid Argument: Unsupported protocol "+ protocol);
There is no error which is coming in append operation and checked in debug perspective the value is getting appended successfully in valueString.
Please tell what i am missing
Figure I should put this as an answer instead of just a comment...
This sort of behavior can occur when your code (what you are stepping through in the debugger) is out of sync with the compiled class files (that are actually running). Since debug information is associated with line numbers, the lines may be different in the class files than in the source code you see.
Try running a clean build and make sure that there are no duplicate jars on your classpath that may be causing this.

not printing to textbox

I am trying to create a way of retrieving from a hashtable an authorID for the articleName that the user enters. Here is the code that is activated on the client's side when the user presses a button:
public String getAuthorID() // returns a String
{
try
{
articleName = txtArticleName.getText();
argAuthorID = new Vector();// create vector for the args
argAuthorID.addElement(articleName);// name to search for to get AuthorID
// make the call to the server
authorIDVector = (Integer)client.execute("GetSize.sendAuthorID", argAuthorID);
System.out.println(argAuthorID);
}
catch (XmlRpcException exception) {
System.err.println("JavaClient: XML-RPC Consumer Fault #" +
Integer.toString(exception.code) + ": " +
exception.getCause() + "" + exception.toString());
} catch (Exception exception) {
System.err.println("JavaClient: XML-RPC Consumer Fault #" + exception.toString());
}
String StrAuthorID = Integer.toString(authorID); // Cast AuthorID to String
return StrAuthorID;
}
This is the method on the server side:
public int sendAuthorID(String articleNameRequest) {
// get info from the hashtable
aNumber = (Integer) theHashtable.getAuthorID(articleNameRequest); // was this.
return aNumber;
}
This is the code in the class that contains the hashtable:
public int getAuthorID(String articleName)
{
int intfoundit;
String foundit = (String)hashtab.get(articleName);
System.out.print(foundit);
intfoundit = Integer.parseInt(foundit);
System.out.print(foundit);
System.out.print(intfoundit);
return intfoundit;
}
The program can retrieve the AuthorID but won't input it into the textbox. Via testing I discovered that the exception was thrown by this code:
catch (XmlRpcException exception) {
System.err.println("JavaClient: XML-RPC Consumer Fault #" +
Integer.toString(exception.code) + ": " +
exception.getCause() + "" + exception.toString());
This is the error that is given:
'JavaClient: XML-RPC Consumer Fault #0:
nullorg.apache.xmlrpc.XmlRpcException: java.lang.Exception:
java.lang.NumberFormatException: For input string: " 3377"'
UPDATE: removed the space before the ID number in the hashtable and it doesn't throw an error anymore but it still isn't inputting the ID number into the textbox instead it just inputs a '0'
It seems to be failing in cases when you have spaces in your string. As we can see in your exception trace that parseInt failed to parse " 3377" and it threw NumberFormatException while executing:
intfoundit = Integer.parseInt(foundit);
So you may try to trim the string and see whether it solves your problem:
intfoundit = Integer.parseInt(foundit.trim());
Better you should do the trim where you are saving/putting the key/value in the hashtable.
The answer to the first problem was space before ID number on the hashtable because the space couldn't be converted to an Integer.
The answer to the second problem was that the following line was trying to convert the wrong variable
String StrAuthorID = Integer.toString(authorID); // Cast AuthorID to String
because the Integer was in the AuthorID variable
I corrected this by changing
authorIDVector = (Integer)client.execute("GetSize.sendAuthorID", argAuthorID);
to
authorID = (Integer)client.execute("GetSize.sendAuthorID", argAuthorID);

Categories