I was working upon a program when i noticed something weird in its output behaviour :
Getting required output :
while ((str = input.readLine()) != null)
{
if(str.contains("sometext"))
{
while(str.contains("some_diff_text")==false)
{
if(str.contains("something"))
break;
else
{
//my code;
}
}
break; //difference in output because of this break position
}
}
Not Getting required output :
while ((str = input.readLine()) != null)
{
if(str.contains("sometext"))
{
while(str.contains("some_diff_text")==false)
{
if(str.contains("something"))
break;
else
{
//my code;
}
}
}
break; //not giving me the required output
}
Can someone explain me why there is a difference in the output behaviour ?
You moved the break out of the if in the second snippet, so it breaks out of the loop no matter what.
In the first code snippet, the second break is inside the outer if statement. The outer while loop will break only when the outer if condition is true.
In the second code snippet, the second break follows the outer if statement. Whether or not the outer if condition is true, the outer while loop will break.
In second code:
}
} <--- "this is placed wrong"
break; //not giving me the required output
"} <-- should be present here"
}
That is why correct indentation is important. Indent your code while writing code (but not after writing).
Even in your first code indentation is not correct (Uniform size tab missing), it should be like:
while ((str = input.readLine()) != null)
{
if(str.contains("sometext"))
{// <------
while(str.contains("some_diff_text")==false)
{
if(str.contains("something"))
break;
else
{
//my code;
}
}
break;
}// <------ if ends
}
// 1 2 3 uniform tab spaces ...
Notice each } comes just vertically below { in same line (for example I marked for if in comment). Also each line between code block {...} start at one more tab spaces then { tab spaces.
Related
Suppose we are trying to find some string in a class, and suppose that class has this string repeated several times. How do I make the .contains() method stop whenever it finds the first match? Here is an example of what I mean:
for (File f : list) {
if (f.isDirectory()) {
walk(f.getAbsolutePath());
}
if (f.getName().endsWith(".java")) {
System.out.println("File:" + f.getName());
countFiles++;
Scanner sc2 = new Scanner(f);
while (sc2.hasNextLine()) {
count++;
String str = sc2.nextLine();
if (str.contains("#Test")) {
System.out.println("this is a test class");
}
As you can see I'm trying to find test classes so I'm looking for #Test notation, the program is working perfectly, but in this case its printing (this is a test class) several times as the class that I am testing has four #Test notations!
Thanks!
I would recommend the break statement as well:
break;
The break statement will exit the inner most loop. The continue statement will skip the rest of the code in that loop and since your loop ends with the print statement the continue statement at the end of the loop will do nothing.
It looks like you have a for loop over each document and then a while loop for each line in the document and your code is returning each line in each document where it finds your string.
If you put a single break statement after the print statement it will print one line for each file where it finds your text.
If you would like it to stop after the first file, you'll need to create a flag like
boolean found = False;
and then put this inside the if statement below the print
found = True;
break;
Then at the end of while loop add this:
if(found){break;}
When your program finds the first instance of the string it will set the flag to true and exit the while loop, then since the flag is set to true, it will exit the for loop and finish after printing only the first instance.
You need a label.
nextFile: //add this label
for (File f : list) {
if (f.isDirectory()) {
walk(f.getAbsolutePath());
}
if (f.getName().endsWith(".java")) {
System.out.println("File:" + f.getName());
countFiles++;
Scanner sc2 = new Scanner(f);
while (sc2.hasNextLine()) {
count++;
String str = sc2.nextLine();
if (str.contains("#Test")) {
System.out.println("this is a test class");
continue nextFile;//go for next file
}
Edited
Just in case you want to exit the method, I assume the return type is void;
if (str.contains("#Test")) {
System.out.println("this is a test class");
return; //quit method
}
break and continue are dangerous. It's very easy to lose track of which block you're breaking or continueing out of, especially when adding/editing functionality down the line. This leads to subtle, painful bugs.
I would advise a different approach, one that's more OO: separate out a method that returns whether a File is a test file or not:
for (File f : list) {
if (f.isDirectory()) {
walk(f.getAbsolutePath());
}
if (f.getName().endsWith(".java")) {
System.out.println("File:" + f.getName());
countFiles++;
if ( isTestFile(f) ) {
System.out.println("this is a test class");
}
The implementation would contain your scanning code, and return on the first hit:
private boolean isTestFile(File file) {
Scanner scanner = new Scanner(f);
while ( scanner.hasNextLine() ) {
if ( scanner.nextLine().contains("#Test") ) {
return true;
}
}
return false;
}
This is also a clearer declaration of intent because it explains what you're trying to achieve in the method name. It also gives the added benefit of separating the implementation from the intent - if down the line, you think of a better way of identifying a test class, you change the isTestFile() method body, and none of the rest of your code has to change.
I am currently working on a program that reads through a text file and prints different lines depending on what the previous line consists of. For example if the previous line was an integer, then I print a different variation of the current line. How can I check to see whether the previous line was an integer without going through the file two lines at a time?
Here is the code so far.
public void workThroughFile(String filename) {
try (BufferedReader br = new BufferedReader(new FileReader(filename))) {
String line;
while ((line = br.readLine()) != null) {
if (isInteger(line) == false && line.contains("?") == true) {
System.out.println(line);
}
if (isInteger(line) == false && line.contains("?") == false) {
System.out.println(line);
}
if (isInteger(line) == true) {
}
}
}
catch (Exception e) {
System.out.println("Did not quite work this time.");
}
}
The strategy here would be:
Save both the previous line and the current line in memory. You can declare 2 properties on the class handling the file read.
private String prevLine;
private String currLine;
Then read file lines one by one:
...
String line;
while ((line = br.readLine()) != null) {
//update line properties
prevLine = currLine;
currLine = line;
if(someConditions(prevLine)){
handleCurrLine(currLine);
}
}
You want to keep track of state. For example if you want to look at the last two lines and keep track of if they were ints or not you have 4 possible states: neither were ints, last was int, 2nd last was int, or both were ints. Just make something (ex. boolean wasLastLineInt) to keep track of the state and update it as you read lines. Booleans are probably the easiest way to keep track of the state.
wasLastLineInt = false;
was2ndLastLineInt = false;
while ((line = br.readLine()) != null) {
if(wasLastLineInt){
//do something with line if lastline was an int
}
else{
//do something with line if last line wasn't an int
}
//whatever other conditions you want
//prepare for next iteration
was2ndLastLineInt = wasLastLineInt;//condition of lastline will be condition of 2ndlastline next iteration
wasLastLineInt = line.matches("^-?\\d+$");//set last line condition for next iteration
}
It uses a regex http://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html to check if the string is a positive or negative integer. however it wont catch something with a '+' sign at the front.
Make sure to update the state after you decide how to handle the current line, or you will make decisions based on the wrong lines. And keep in mind how you want to handle the first few lines, this starts with the behavior for lines -1 and -2 being nonintegers.
i'm having a problem about the if inside my if, because it does not read the if inside my if. It does only print the "if and goto detected" once i type for example ("if 1 goto A") then next line ("A:") . Supposedly when the program finds ":" it should print there's a colon but it won't print on mine .Please help me.
public turing() {
String[] input = inputArea.getText().split("\n");
for(int i=0;i<input.length;i++){
if(input[i].startsWith("if")==true && (input[i].contains("goto")==true)){
System.out.print("If and Goto detected");
if(input[i].contains(":")==true){
System.out.print("There's a Colon");
}
}
}
}
You dont't close the if about "if" and "goto" before you open the one about ":", so ":" will only be reported if an "if" or "goto" is present.
You need to use another if because right now the program will only reach System.out.print("There's a Colon"); if if, goto, and : are in the string. This would make your code as follows:
public turing() {
String[] input = inputArea.getText().split("\n");
for(int i=0;i<input.length;i++){
if(input[i].startsWith("if")==true && (input[i].contains("goto")==true)){
System.out.print("If and Goto detected");
}
if(input[i].contains(":")==true){
System.out.print("There's a Colon");
}
}
}
Your input is wrong.
if 1 goto A prints If and Goto detected as it has an if and a goto. It doesn't print the colon part, as there is no colon.
Next your input is A:, it has no if and no goto, so it never passes the first if and will never reach the inner if.
If you enter if 1 goto A: then it will print both outputs.
So either change your input or change your logic. If you want to check for the colon independently, then you have to change the code like this:
public turing() {
String[] input = inputArea.getText().split("\n");
for(int i=0;i<input.length;i++){
if(input[i].startsWith("if") && (input[i].contains("goto"))){
System.out.print("If and Goto detected");
}
if(input[i].contains(":")){
System.out.print("There's a Colon");
}
}
}
code is missing a closing bracket.
if you want the colon to be detected in all case, put the closing bracket after the first println, as in
if (element.startsWith("if") == true
&& (element.contains("goto") == true)) {
System.out.print("If and Goto detected");
}
if (element.contains(":") == true) {
System.out.print("There's a Colon");
}
otherwise, to get the colon only when in the if
if (element.startsWith("if") == true
&& (element.contains("goto") == true)) {
System.out.print("If and Goto detected");
if (element.contains(":") == true) {
System.out.print("There's a Colon");
}
}
I have written following method in Java. But I get error message unreachable code on the line containing return (Constants.SUCCESS);
If I comment that line, I do not get error message. Now my doubt is why I do not get error message if I comment that line? There is no return value of SUCCESS to the calling portion if I comment the line. I thought there should be one return statement and there are none if all "if loops" and default is not getting executed. I thought last return statement will execute in any case. I tried return (Constants.SUCCESS) statement at the end also (Commented line), but no luck.
So for returning success, do I need to return success after each "if" loop under every case statements (creating "else" part for each).
static int validateStartAndEndStringOrder(String startStr, String endStr, ArrayList<String> swaraPool, Constants.PatternType ptrnType) {
switch (ptrnType) {
case AROHA_INCREASING: {
if (swaraPool.indexOf(endStr) < swaraPool.indexOf(startStr)) {
System.out.println("End string is before the start String");
return (-1);
}
}
case AROHA_DECREASING: {
if (swaraPool.indexOf(startStr) < swaraPool.indexOf(endStr)) {
System.out.println("End string is before the start String");
return (-1);
}
}
case AVAROHA_INCREASING: {
if (swaraPool.indexOf(endStr) < swaraPool.indexOf(startStr)) {
System.out.println("End string is before the start String");
return (-1);
}
}
case AVAROHA_DECREASING: {
if (swaraPool.indexOf(startStr) < swaraPool.indexOf(endStr)) {
System.out.println("End string is before the start String");
return (-1);
}
}
default: {
System.out.println("Invalid Enumeration Type");
return(-1);
}
return (Constants.SUCCESS);
}
//return (Constants.SUCCESS);
}
switch ... case 1 ... case n ... default covers all control paths (the default will catch all remaining cases). Since you return explicitly out of each one, there's no way program control can go beyond that switch block.
Your compiler is being helpful in emitting the error.
Use break; statements between each case in the switch block to move control flow to the end of the block.
I suspect you want to add a break; at the end of your case blocks. Otherwise the code just runs from top to bottom (like anywhere else in your code)
If you place a break; it will jump outside the switch block which appears to be what you want.
e.g.
case AROHA_INCREASING: {
if (swaraPool.indexOf(endStr) < swaraPool.indexOf(startStr)) {
System.out.println("End string is before the start String");
return (-1);
}
break; // without this, the thread will run the next case: block.
}
You default section contains
{
System.out.println("Invalid Enumeration Type");
return(-1);
}
return (Constants.SUCCESS);
What do you expect?
I have here a String that contains the source code of a class. Now i have another String that contains the full name of a method in this class. The method name is e.g.
public void (java.lang.String test)
Now I want to retieve the source code of this method from the string with the class' source code. How can I do that? With String#indexOf(methodName) i can find the start of the method source code, but how do i find the end?
====EDIT====
I used the count curly-braces approach:
internal void retrieveSourceCode()
{
int startPosition = parentClass.getSourceCode().IndexOf(this.getName());
if (startPosition != -1)
{
String subCode = parentClass.getSourceCode().Substring(startPosition, parentClass.getSourceCode().Length - startPosition);
for (int i = 0; i < subCode.Length; i++)
{
String c = subCode.Substring(0, i);
int open = c.Split('{').Count() - 1;
int close = c.Split('}').Count() - 1;
if (open == close && open != 0)
{
sourceCode = c;
break;
}
}
}
Console.WriteLine("SourceCode for " + this.getName() + "\n" + sourceCode);
}
This works more or less fine, However, if a method is defined without body, it fails. Any hints how to solve that?
Counting braces and stopping when the count decreases to 0 is indeed the way to go. Of course, you need to take into account braces that appear as literals and should thus not be counted, e.g. braces in comments and strings.
Overall this is kind of a thankless endeavour, comparable in complexity to say, building a command line parser if you want to get it working really reliably. If you know you can get away with it you could cut some corners and just count all the braces, although I do not recommend it.
Update:
Here's some sample code to do the brace counting. As I said, this is a thankless job and there are tons of details you have to get right (in essence, you 're writing a mini-lexer). It's in C#, as this is the closest to Java I can write code in with confidence.
The code below is not complete and probably not 100% correct (for example: verbatim strings in C# do not allow spaces between the # and the opening quote, but did I know that for a fact or just forgot about it?)
// sourceCode is a string containing all the source file's text
var sourceCode = "...";
// startIndex is the index of the char AFTER the opening brace
// for the method we are interested in
var methodStartIndex = 42;
var openBraces = 1;
var insideLiteralString = false;
var insideVerbatimString = false;
var insideBlockComment = false;
var lastChar = ' '; // White space is ignored by the C# parser,
// so a space is a good "neutral" character
for (var i = methodStartIndex; openBraces > 0; ++i) {
var ch = sourceCode[i];
switch (ch) {
case '{':
if (!insideBlockComment && !insideLiteralString && !insideVerbatimString) {
++openBraces;
}
break;
case '}':
if (!insideBlockComment && !insideLiteralString && !insideVerbatimString) {
--openBraces;
}
break;
case '"':
if (insideBlockComment) {
continue;
}
if (insideLiteralString) {
// "Step out" of the string if this is the closing quote
insideLiteralString = lastChar != '\';
}
else if (insideVerbatimString) {
// If this quote is part of a two-quote pair, do NOT step out
// (it means the string contains a literal quote)
// This can throw, but only for source files with syntax errors
// I 'm ignoring this possibility here...
var nextCh = sourceCode[i + 1];
if (nextCh == '"') {
++i; // skip that next quote
}
else {
insideVerbatimString = false;
}
}
else {
if (lastChar == '#') {
insideVerbatimString = true;
}
else {
insideLiteralString = true;
}
}
break;
case '/':
if (insideLiteralString || insideVerbatimString) {
continue;
}
// TODO: parse this
// It can start a line comment, if followed by /
// It can start a block comment, if followed by *
// It can end a block comment, if preceded by *
// Line comments are intended to be handled by just incrementing i
// until you see a CR and/or LF, hence no insideLineComment flag.
break;
}
lastChar = ch;
}
// From the values of methodStartIndex and i we can now do sourceCode.Substring and get the method source
Have a look at:- Parser for C#
It recommends using NRefactory to parse and tokenise source code, you should be able to use that to navigate your class source and pick out methods.
You will have to, probably, know the sequence of the methods listed in the code file. So that, you can look for the method closing scope } which may be right above start of next method.
So you code might look like:
nStartOfMethod = String.indexOf(methodName)
nStartOfNextMethod = String.indexOf(NextMethodName)
Look for .LastIndexOf(yourMethodTerminator /*probably a}*/,...) between a string of nStartOfMethod and nStartOfNextMethod
In this case, if you dont know the sequence of methods, you might end up skipping a method in between, to find an ending brace.