I have the following code for logging all the errors after every command I run in cmd with my tool. (It runs p4 integrate commands, about 1000-1500/task)
if (errorArrayList.size() > 0) {
LoggerSingleton.I.writeDebugInfoTimeStampedLog("[INFO-CMD] CommandExecuter.java -> runAndGetResults: errors happened while running the following command: [ " + commandResultBean.getCommand() + " ]");
for (int i = 0; i < errorArrayList.size(); i++) {
LoggerSingleton.I.writeDebugErrorTimeStampedLog(errorArrayList.get(i));
commandResultBean.addToCLI_Error(errorArrayList.get(i));
}
LoggerSingleton.I.writeDebugInfoTimeStampedLog("[INFO-CMD] CommandExecuter.java -> runAndGetResults: Listing errors of command [" + commandResultBean.getCommand() + "] finished");
}
The feature that I'm working on right now is check the error I get, and if that's on a predefined error list (list of errors that doesn't matter, and in fact not real errors, for example "all revision(s) already integrated") do nothing else, but when it's a "real" error, write it to an other log file too (Because these debug logs way too long for the users of the tool, it's made for the developers more likely).
The question is, what is the best way for this?
I want to avoid big deceleration. I have many commands, but the number of errors less then the commands, but that is not unusual at all that I get 700-800 "irrelevant" errors in one task.
I will use another class to make the I/O part, and that is not a problem to extend the running time in case we catch a "real" error.
The list is constant, it is okay if it can be modified only by coding.
At the moment I don't know what type to use (2-3 single Strings, List, Array ...). What type should I use? I never used enums in Java before, in this one should I?
I guess a for or foreach and errorArrayList.get(i).contains(<myVariable>)in a method is the only option for the checking.
If I'm wrong, there is a better way to do this?
EDIT
If I have an ArrayList<String>called knownErrors with the irrelevant errors (can define only parts of it), and I use the following code will better performance than a method wrote above? Also, can I use it if I have only parts of the String? How?
if (errorArrayList.removeAll(knownErrors) {
//do the logging and stuff
}
ArrayList itself has a method removeAll(Collection c) which removes all the elements which are matching with input collection elements. Below program show it evidently. So if you have the known error to be skipped in arraylist and pass it to removeall method it will remove the known errors and errorArrayList will have only new errors.
Related
I am relatively new to development so please forgive me if some of this seems rather amateurish. Part of my reason for posting the question is to help nudge me to the answer, part is to make sure I'm following good coding practice.
The challenge -
I'm using Java & Selenium to check a very large, dynamically populated table. I need to find a specific list of elements where the text matches a case-sensitive String -
List<WebElement> AllPaths = getCurrentDriver().findElements(By.xpath("//*[text()[contains(.,'" + fixedString + "')]]"));
The table I'm checking is basically a large calendar-style grid. If I don't find evidence of fixedString, I then want to iterate back one month at a time until I DO find the fixedString.
The problem -
The code above returns an exception if it cannot find an element. My first thought was to setup a while loop, trying/catching the exception and then repeating until exceptions stopped. However this feels wrong to me - I don't think I should be essentially "swallowing" exceptions. That said, I'm not sure what the correct way of trying to find this element is that doesn't lead to an exception if it fails to locate it.
Am I right in thinking it's a bad idea to write code that you know causes an exception and then simply swallow it and move on?
Hope this makes sense, as I say I'm a beginner so please be gentle :)
You can try something like -
if(AllPaths.size()>0){
//logic when elements found with fixed string
}else{
//logic to iterate over another month
}
Also, your statement seems wrong to me. It should be -
List<WebElement> AllPaths = getCurrentDriver().findElements(By.xpath("//*[contains(text(),'" + fixedString + "')]"));
findElements doesn't throw exception this way. It will return empty if no elements located. The exception seems due to incorrect statement that you are using to find elements.
The code above returns an exception if it cannot find an element.
The documentation says findElements returns an empty list when no elements are found. It should not throw any exception in this case. Is it possible that you by mistake used findElement instead of findElements? What type of exception is thrown and what is the message?
You shouldn't need to catch exceptions here. You are right though that control flow using exceptions should be avoided and that swallowing exceptions is bad. On the other hand frameworks don't always let you write code the way you want so sometimes exceptions have to be made.
I am asking this question particularly for an Expect implementation in Java. However, I would like to know general suggestions as well.
In Expect programming, is it possible to expect exactly what is prompted after spawning a new process?
For example, instead of expecting some pattern or a fixed string, isn't it better to just expect what is prompted. I feel this should be really helpful at times(especially when there's no conditional sending).
Consider the sample java code here that uses JSch and Expect4j java libraries to do ssh and execute list of commands(ls,pwd,mkdir testdir) on the remote machine.
My question here is why is it necessary to specify a pattern for the prompt? Is it not possible it to get the exact prompt from Channel itself and expect it?
I've programmed in "expect" and in "java".
I think you misunderstand what "expect" basically does. It doesn't look for exact items prompted after spawning a new process.
An expect program basically consists of:
Something that reads the terminal
A set of patterns (typically regular expressions), coupled to a blocks of code.
So, when a new process is spawned, there's a loop that looks something like this
while (terminal.hasMoreText()) {
buffered_text += terminal.readInput();
for (Pattern pattern : patterns) {
if (pattern.matches(buffered_text)) {
String match = pattern.getMatch(buffered_text);
bufferedText.removeAllTextBefore(match);
bufferedText.removeText(match);
pattern.executeBlock();
}
}
}
Of course, this is a massive generalization. But it is close enough to illustrate that expect itself doesn't "exactly expect" anything after launching a process. The program provided to the expect interpreter (which primarily consists of patterns and blocks of code to execute when the patterns match) contains the items which the interpreter's loop will use to match the process's output.
This is why you see some pretty odd expect scripts. For example, nearly everyone "expects" "ogin:" instead of "Login:" because there's little consistency on whether the login prompt is upper or lower case.
You don't have to expect anything. You're free to just send commands immediately and indiscriminately.
It's considered good practice to only reply to specific prompts so that you don't accidentally ruin something by saying the wrong thing at the wrong time, but you're entirely free to ignore this.
The main consideration is that while your normal flow might be:
$ create-backup
$ mkdir latest
$ mv backup.tar.gz latest
With no expectations and just blindly writing input, you can end up with this:
$ create-backup
Disk full, cleanup started...
Largest file: precious-family-memories.tar (510MB)
[R]emove, [S]ave, [A]bort
Invalid input: m
Invalid input: k
Invalid input: d
Invalid input: i
Removing file...
$ latest
latest: command not found
$ mv backup.tar.gz latest
whereas a program that expects $ before continuing would just wait and eventually realize that things are not going according to plan.
A few commands are sensitive to timing (e.g. telnet), but other than that you can send commands whenever you want, with or without waiting for anything at all.
I saw the following code in this commit for MongoDB's Java Connection driver, and it appears at first to be a joke of some sort. What does the following code do?
if (!((_ok) ? true : (Math.random() > 0.1))) {
return res;
}
(EDIT: the code has been updated since posting this question)
After inspecting the history of that line, my main conclusion is that there has been some incompetent programming at work.
That line is gratuitously convoluted. The general form
a? true : b
for boolean a, b is equivalent to the simple
a || b
The surrounding negation and excessive parentheses convolute things further. Keeping in mind De Morgan's laws it is a trivial observation that this piece of code amounts to
if (!_ok && Math.random() <= 0.1)
return res;
The commit that originally introduced this logic had
if (_ok == true) {
_logger.log( Level.WARNING , "Server seen down: " + _addr, e );
} else if (Math.random() < 0.1) {
_logger.log( Level.WARNING , "Server seen down: " + _addr );
}
—another example of incompetent coding, but notice the reversed logic: here the event is logged if either _ok or in 10% of other cases, whereas the code in 2. returns 10% of the times and logs 90% of the times. So the later commit ruined not only clarity, but correctness itself.
I think in the code you have posted we can actually see how the author intended to transform the original if-then somehow literally into its negation required for the early return condition. But then he messed up and inserted an effective "double negative" by reversing the inequality sign.
Coding style issues aside, stochastic logging is quite a dubious practice all by itself, especially since the log entry does not document its own peculiar behavior. The intention is, obviously, reducing restatements of the same fact: that the server is currently down. The appropriate solution is to log only changes of the server state, and not each its observation, let alone a random selection of 10% such observations. Yes, that takes just a little bit more effort, so let's see some.
I can only hope that all this evidence of incompetence, accumulated from inspecting just three lines of code, does not speak fairly of the project as a whole, and that this piece of work will be cleaned up ASAP.
https://github.com/mongodb/mongo-java-driver/commit/d51b3648a8e1bf1a7b7886b7ceb343064c9e2225#commitcomment-3315694
11 hours ago by gareth-rees:
Presumably the idea is to log only about 1/10 of the server failures (and so avoid massively spamming the log), without incurring the cost of maintaining a counter or timer. (But surely maintaining a timer would be affordable?)
Add a class member initialized to negative 1:
private int logit = -1;
In the try block, make the test:
if( !ok && (logit = (logit + 1 ) % 10) == 0 ) { //log error
This always logs the first error, then every tenth subsequent error. Logical operators "short-circuit", so logit only gets incremented on an actual error.
If you want the first and tenth of all errors, regardless of the connection, make logit class static instead of a a member.
As had been noted this should be thread safe:
private synchronized int getLogit() {
return (logit = (logit + 1 ) % 10);
}
In the try block, make the test:
if( !ok && getLogit() == 0 ) { //log error
Note: I don't think throwing out 90% of the errors is a good idea.
I have seen this kind of thing before.
There was a piece of code that could answer certain 'questions' that came from another 'black box' piece of code. In the case it could not answer them, it would forward them to another piece of 'black box' code that was really slow.
So sometimes previously unseen new 'questions' would show up, and they would show up in a batch, like 100 of them in a row.
The programmer was happy with how the program was working, but he wanted some way of maybe improving the software in the future, if possible new questions were discovered.
So, the solution was to log unknown questions, but as it turned out, there were 1000's of different ones. The logs got too big, and there was no benefit of speeding these up, since they had no obvious answers. But every once in a while, a batch of questions would show up that could be answered.
Since the logs were getting too big, and the logging was getting in the way of logging the real important things he got to this solution:
Only log a random 5%, this will clean up the logs, whilst in the long run still showing what questions/answers could be added.
So, if an unknown event occurred, in a random amount of these cases, it would be logged.
I think this is similar to what you are seeing here.
I did not like this way of working, so I removed this piece of code, and just logged these
messages to a different file, so they were all present, but not clobbering the general logfile.
As you can probably understand from the question itself, I'm new to Java.
I was given an exercise to write a Java program which receives a character, prints it and the next character in the Unicode table.
Now, I have the solution to this exercise:
public static void main(String[] args){
char c = args[0].charAt(0);
char c1 = (char)(c + 1);
System.out.println(c + "\t" + c1);
}
I understand basic idea of this code, but I'm trying to run this code in Eclipse I get an annoying error:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
at MainClass.main(MainClass.java:9)
Note: I have yet to run a Java program that actually receives something as a parameter so I guess it's a stupid beginners' mistake... Here is the full code that I tried to compile in Eclipse:
public class MainClass {
/**
* #param args
*/
public static void main(String[] args){
char c = args[0].charAt(0);
char c1 = (char)(c + 1);
System.out.println(c + "\t" + c1);
}
}
Thanks in advance
Select "Run -> Run Configurations" from the menu.
Search for you project in the list on the left and select it.
Select the "Arguments" tab on the right.
Write the argument you want to pass to the programm in "Programm arguments".
Click "Run"
Right click on your java file in project explorer of your eclipse. Then Run As> Run Configuration
Then you will get a window. Like-
Click on Arguments Tabs, and then write some text there, may be a character.
And then Click on Apply button and Run Button.
The default run configuration in Eclipse runs a Java program without any arguments, hence the ArrayIndexOutOfBoundsException. Your code is trying to get first element of the args array when there aren't any!
You can edit the run configuration to provide the arguments to run your program with. Then it should not throw this exception.
However, a good practice is to check the size of array before accessing it's elements, more so when the array is coming as an argument from outside of your code.
This is a great question with some very good answers. I would like to add some pointers about how to debug your own program. Debugging is as important (if not more important) than writing code.
For one thing, Eclipse has some great debugging features. You can use this debugger to find problems in your code. I suggest that you learn how to use it. In particular, you can set watches for variables to see what value they have as you step through the execution of your code.
Alternatively, you can add calls to System.out.println() to print out the values of any variables. For example, adding the following line at the beginning of your code might help you narrow down the problem:
System.out.println(args[0]);
This would also give an ArrayIndexOutOfBoundsException if no command-line arguments are given. Then you could do something like
System.out.println(args.length);
which would print out 0. This then gives you a clue as to where the problem is.
Of course, even when you get to this point, you still might not know how to solve the problem. This is where sites like StackOverflow come in handy.
Good luck with your Java experience. Please come back when you need more help.
If your Run Configurations are in place (as already shown in above answers):
Shortcut to Run a class is:
Ctrl + F11
I recently started using the findbugs static analysis tool in a java build I was doing. The first report came back with loads of High Priority warnings. Being the obsessive type of person, I was ready to go knock them all out. However, I must be missing something. I get most of the warnings when comparing things. Such as the following code:
public void setSpacesPerLevel(int value)
{
if( value >= 0)
{
spacesPerLevel = value;
}
else
{
spacesPerLevel = 0;
}
}
produces a high priority warning at the if statement that reads.
File: Indenter.java, Line: 60, Type:
BIT_AND_ZZ, Priority: High, Category:
CORRECTNESS Check to see if ((...) &
0) == 0 in
sample.Indenter.setSpacesPerLevel(int)
I am comparing an int to an int, seems like a common thing. I get quite a few of that type of error with similar simple comparisons.
I have alot of other high priority warnings on what appears to be simple code blocks. Am I missing something here? I realize that static analysis can produce false positives, but the errors I am seeing seem too trivial of a case to be a false positive.
This one has me scratching my head as well.
for(int spaces = 0;spaces < spacesPerLevel;spaces++)
{
result = result.concat(" ");
}
Which gives the following findbugs warning:
File: Indenter.java, Line: 160, Type: IL_INFINITE_LOOP, Priority: High, Category: CORRECTNESS
There is an apparent infinite loop in sample.Indenter.indent()
This loop doesn't seem to have a way to terminate (other than by perhaps throwing an exception).
Any ideas?
So basically I have a handful of files and 50-60 high priority warnings similar to the ones above. I am using findbugs 1.3.9 and calling it from the findbugs ant task
UPDATE:
I have this build being executed by a hudson server and had the code being instrumented by Clover for code coverage. When I turned that off, all of my high priority warnings disappeared. That makes sense now. Thanks for the feedback.
UPDATE: I have this build being executed by a hudson server and had the code being instrumented by Clover for code coverage. When I turned that off, all of my high priority warnings disappeared. That makes sense now. Thanks for the feedback.
A side note:
for(int spaces = 0;spaces < spacesPerLevel;spaces++)
{
result = result.concat(" ");
}
If result is a java.lang.String, this may be inefficient, as you do the following steps for each space character:
create a new char[] to hold the result of the concatenation
create a new java.lang.String instance that is wrapped around the character array
If you do this repeatedly, especially when result is already long, this takes a lot of time.
If performance (both time and memory) is important for that method, you should consider using a StringBuilder (not thread-safe) or a StringBuffer (thread-safe).
Are you running Findbugs thru Eclipse plugin, ant or gui? is it possible that the code hasn't recompiled since you ran it (before making changes)?
if setSpacesPerLevel isn't too long, post the output of
javap -v TheClassThatContainssetSpacerPerLevel
As for the second bug, you'd have to show the whole loop before one could say if it was a problem.