0

Right, yes that makes more sense, here is the update method:

public List<String> fileInArray(){//save file text into array        
        Path path = Paths.get(fileName);        
        if(!(Files.isReadable(path))){
            System.out.println("The file is empty. You need to save something in it first.");//to be printed in the textArea
            return null;            
        }
        try{
            return Files.readAllLines(path, ENCODING);          
        }
        catch(IOException ioexception){
            System.err.println("General Error with IO");
            ioexception.printStackTrace();
            System.exit(1);
        }
        return null;        
    }

If there is no file in the folder, which would be when you run the application the first time, you get this in the console (and the application doesn't run at all): I believe that's correct

G:\JAVA\GUI\2015\createFrames\files\withSearch>java SentenceRecorderTest
The file is empty. You need to save something in it first.
Array contains:
Exception in thread "main" java.lang.NullPointerException
        at SentenceRecorder.printSentenceArray(SentenceRecorder.java:187)
        at SentenceRecorder.<init>(SentenceRecorder.java:72)
        at SentenceRecorderTest.main(SentenceRecorderTest.java:5)
G:\JAVA\GUI\2015\createFrames\files\withSearch>

The reason why you get "array contains:" is because the function that prints the array

public void printSentenceArray(){
        System.out.println("Array contains: ");
        for(int count = 0; count < allSentences.size(); count++){
            //System.out.printf("%s", allSentences.get(count));
            System.out.println(allSentences.get(count));
        }           
}

runs anyway as it is called from inside the constructor:

public SentenceRecorder(){
        ...
        fileName = "sample.txt";        
        file = new File(workingDir, fileName);
        allSentences = fileInArray();//copying content of file in arrayList
        printSentenceArray();
        setLayout(gbLayout);//set layout of jframe
        ...
}//end of constructor

You just need to load allSentences once, when you initialise the program.

yep that's done in the constructor above allSentences = fileInArray();

searching does not belong anywhere in that code.

I have a separate function for that, still haven't coded much as yet, but the idea is that, for now, i call it with a hardcoded string in it and use that as search term. Is it safe to call that function from the constructor or should it be called from inside public List<String> fileInArray(){}?

public String searchWord(String keyword){// search for keyword and return the whole string/s
        System.out.printf("Keyword is %s", keyword);
        return keyword;     
    }

Edited by Violet_82

0

You can call the search method from anywhere anytime after allSentences has been initialised.

To avoid that NPE you could start your print method by testing for allSentences == null and just print a suitable message and return.

0

OK done and it works nicely, and the search as well:

public SentenceRecorder(){
        super("List of sentences to remember");
        ...     
        fileName = "sample.txt";        
        file = new File(workingDir, fileName);
        allSentences = fileInArray();//copying content of file in arrayList
        printSentenceArray();
        searchWord("sentence");
        ...       
 }
public List<String> fileInArray(){//save file text into array        
        Path path = Paths.get(fileName);        
        if(!(Files.isReadable(path))){
            System.out.println("The file is empty. You need to save something in it first.");//to be printed in the textArea
            return null;            
        }       
        try{
            return Files.readAllLines(path, ENCODING);          
        }
        catch(IOException ioexception){
            System.err.println("General Error with IO");
            ioexception.printStackTrace();
            System.exit(1);
        }
        return null;        
    }
    public void printSentenceArray(){
        if(!(allSentences == null)){//to avoid NPE
            System.out.println("Array contains: ");
            for(int count = 0; count < allSentences.size(); count++){
                //System.out.printf("%s", allSentences.get(count));
                System.out.println(allSentences.get(count));
            }
        }       
    }
    public String searchWord(String keyword){// search for keyword and return the whole string/s
        System.out.printf("\n\nKeyword is %s. Sentence(s) containing the keyword:\n", keyword);
        for(String toFind : allSentences){
            if(toFind.contains(keyword)){
                System.out.println(toFind);
            }
        }       
        return keyword;     
    }

Now the searching functionality of course will change quite a bit when the GUI is implemented, but there is nothing I can do to emulate the functinality we discussed (the application starts returning results as soon as you begin typing), so I'll now create the GUI and implement the rest of the functionality

0

OK, excellent!

I suggest you try a couple more tests before moving on - just to be sure - change the keyword to (1) a value that is not prersent anywhere and (2) a value that appears in multiple sentences.

This is a good time for a quick tidy up - remove redundant code etc.
It's also a good time to review your names to make them really clear and correct, eg for someone reading that code what would they understand by "fileInArray" it doesn't even have an array anywhere? How much clearer would "getSentenceList" be, for example.

It's also a good time to tidy up method parameters. Your code tends todepend on variables that are shared, eg fileName. Someone reading fileInArray immediatly hits fileName, but he's going to have to search through the whole of the code to find where it is declared, initialised, and possibly updated. In such cases it's better to pass that value in as a parameter so the method is self-contained.

Finally, I wouldn't expect the search method to change too much with the GUI. Obviously you will want it to return a List or array of matching sentences, but that's all. The responsibility for displaying those results belongs in the GUI code, not in the search method.

0

HI, yes you're right, I should do a bit of tidying up:
-I removed - to the best of my knowledge - needless code;
-changed findInArray to getSentenceList;
-parametized public List<String> getSentenceList(String theFileName) so fileName is passed to it;
-change the keyword string to test for:1) value that returns more than one sentence, and that works OK (I tried that before in fact); 2) value not found, and that prompted me to make some changes: I added an int control variable whose value is increased everytime there is a match. If there is no match its value remains 0 and the message "None found matching keyword" is printed. Update method here:

public String searchWord(String keyword){// search for keyword and return the whole string/s
        System.out.printf("\n\nKeyword is %s. Sentence(s) containing the keyword:\n", keyword);
        int instanceFound = 0;
        for(String toFind : allSentences){
            if(toFind.contains(keyword)){
                instanceFound++;
                System.out.println(toFind);
            }
        }
        if(instanceFound == 0){//no matches
            System.out.println("None found matching the keyword");          
        }
        return keyword;     
    }

Obviously you will want it to return a List or array of matching sentences

Just thinking, why would I return that? The GUI ill display the sentences in the textArea and I should be able to insert those in it directly from the method, like the List contains already all the sentences, so all I have to do, I would think, is to loop through it, as I do now, and insert those sentences into the textArea. So the current search method returns a String

public String searchWord(String keyword){// search for keyword and return the whole string/s
        System.out.printf("\n\nKeyword is %s. Sentence(s) containing the keyword:\n", keyword);
        int instanceFound = 0;
        for(String toFind : allSentences){
            if(toFind.contains(keyword)){
                instanceFound++;
                System.out.println(toFind);
            }
        }
        if(instanceFound == 0){//no matches
            System.out.println("None found matching the keyword");          
        }
        return keyword;     
    }

but I'm even thinking to get it to return void. Isn't that OK?

0

Well yes, you can update the GUI directly from inside the search method. However it's best practice to separate GUI from logic, and to keep methods as simple and local as possible. I was steering you towards a logic method that performs searches and returns the results, so you can call that from the GUI then display those results in the GUI, or call it from a command line or web UI, or from some unit test code.

0

That's cool, happy to follow your suggestion.
So, to do that the searchWord method needs some changes, like I need to create another array of strings that can take in the sentences that I want to display as results because the way I display them now is simply looping through the allSenteces List and then change the type from String to List<String> and return a List item :

public String searchWord(String keyword){// search for keyword and return the whole string/s
        System.out.printf("\n\nKeyword is %s. Sentence(s) containing the keyword:\n", keyword);
        int instanceFound = 0;
        for(String toFind : allSentences){
            if(toFind.contains(keyword)){
                instanceFound++;
                System.out.println(toFind);
            }
        }
        if(instanceFound == 0){//no matches
            System.out.println("None found matching the keyword");          
        }
        return allSentences;        
    }
0

OK cool, so I quickly changed the function to have another List which I didn't bother declaring in the constructor but it's local to the function and contains a list of matches and that returns that list and I've modified the logic of printing information, so that now I call a printing function, like so:

public List<String> searchWord(String keyword){// search for keyword and return the whole string/s
        System.out.printf("\n\nKeyword is %s. Sentence(s) containing the keyword:\n", keyword);
        List< String > matchedSentences = new ArrayList< String >();//stores all the matched sentences in the file
        int instanceFound = 0;
        for(String toFind : allSentences){
            if(toFind.contains(keyword)){
                instanceFound++;
                matchedSentences.add(toFind);//add the found sentences to the List
                //System.out.println(toFind);               
            }
        }
        if(instanceFound == 0){//no matches
            System.out.println("None found matching the keyword");          
        }
        else if(instanceFound > 0){
            printSentenceArray(matchedSentences);
        }
        return matchedSentences;        
    }

    public void printSentenceArray(List< String > toPrint){
        if(!(toPrint == null)){//to avoid NPE
            System.out.println("Array contains: ");
            for(int count = 0; count < toPrint.size(); count++){
                //System.out.printf("%s", toPrint.get(count));
                System.out.println(toPrint.get(count));
            }
        }       
    }

I'll code the event handling in now, if we're all happy with the above

0

That looks OK.
If you're interested I have a few very small suggestions:
1. As always - naming. eg searchWord really means getSentencesContaining(String s). eg instanceFound sounds like a boolean
2. No need to maintain a count of found instances - the list's size() tells you that
3. The print method can use an enhanced for loop - much clearer amd safer.
4. print method - rather than that if test and indenting the whole following code, I think it's clearer to code it as

if (param is null) {
   return:
}
// now can can forget about that and get on with the important case
0

If you're interested I have a few very small suggestions:

Sure I don't see why not.
-I've changed the name of the function from searchWord to getSentenceContaining;
-removed instanceFound and replaced it with size:
if(matchedSentences.size() == 0){//no matches

            System.out.println("None found matching the keyword");          
        }
        else if(matchedSentences.size() > 0){
            printSentenceArray(matchedSentences);
        }

-The print functionality, printSentenceArray that is, is not there to stay really, it's just a debugging tool, for me to see what gets printed, so it will go. I generally don't like for enhanced loops, it feels like they're hiding stuff from me as opposed to normal for loops, but again, I'm not knowledgeable enough to have a reason not to use them, so if you say they're better, fair enough. Still on the print method: I don't think I'll change it for the reason above, still, if I read correctly you're suggesting this:

public void printSentenceArray(List< String > toPrint){
    if(toPrint == null){
        return null;
    }
    else{
            System.out.println("Array contains: ");
            for(List<String> sentence : toPrint)         
                System.out.println(sentence.get(count));
            }
        }       
    }
0

Yes, except after the return null you don't need to use an else clause, so lines 5 and 9 can be deleted and lines 6-8 indented less, leaving the code shoter and easier to comprehend.
The enhanced for loop is easier to read for all but the most traditional C programmers, and is harder to get wrong. Having said that, you did get it wrong.
toPrint is a List<String>, so its elements are Strings. so the loop starts
for (String s : toPrint) {
which is read out loud as
"for each String s in the list toPrint..."

so what I'm really suggesting is something like (including fixes to syntax and naming (arrays and lists are quite different)

public void printSentenceList(List< String > toPrint){
    if(toPrint == null || toPrint.size() == 0){
        System.out.println("List is empty);
        return;
    }
    System.out.println("List contains " + toPrint.size() + " sentences:");
    for(List<String> sentence : toPrint)  {       
        System.out.println(s);
    }       
}

Don't underestimate the on-going value of bits of debug/test code like this. They will always be useful.

0

Thanks, I'implemented it, and seems to be working, but I think there are some mistakes in the code you pasted, as you said (String s : toPrint) { but your code at the bottom says for(List<String> sentence : toPrint) { :-)
Anyway, all good. Now, about the implementation of the search in the GUI, we said there won't be any search button. I'm thinking about having 2 more TextAreas ( in addition to the one I already have where I type the text that goes into the file of course): in the first one (let's call it searchCriterium) I can type the search criterium (word or sentence) and the second one (let's call it searchResult) will instead display the results in real time.
In terms of code this is roughly what I was thinking should happen:

if the focus is on the SearchCriterium TextArea{
    add a keyListener
    store keystroke text in String keyword
    String matchedResult = getSentenceContaining(keyword);
    copy matchedResult into TextArea        
}

I've added an if statement to the getSenteceContaining function as well, so that it reads:

public List<String> getSentenceContaining(String keyword){// search for keyword and return the whole string/s
        System.out.printf("\n\nKeyword is %s. Sentence(s) containing the keyword:\n", keyword);
        if(keyword.length() > 3){...}
}

And that should make sure that I don't return every single record on the file. How does that sound?

0

Oops, sorry about the for loop. I created that code by editing yours and forgot to fix the for clause.

The GUI stuff is going in the right direction. I suggest:
add the listener once, not every time it gets focus.
getting the char and adding it to the search text won't work - consider backspace, or arrow keys for example. You have to use the current text in that field, which actually makes the code simpler.
You want to do the search every time the user changes the search text (including by mouse), so that's a
myArea.getDocument().addDocumentListener(...

document listener:
    String matchedResult = getSentenceContaining(inputField.getText());
    copy matchedResult into OutputTextArea  

(note the search word will be one line, so an ordinary entry field will be better than a multiline text area.)

You'll also have to look at how the search method returns multiple matches. A List<String> would be obvious, and then you would have to loop through that List adding each line to the output text area

0

getting the char and adding it to the search text won't work - consider backspace, or arrow keys for example. You have to use the current text in that field, which actually makes the code simpler.

Good point, but how does the application know that it is ready to process the text in that field unless I have a search button of some sort? Like, say I want to search for "house": whether I type "hou" or "hous" or "house" on way or another I need to tell the application to run the search. The more I think about the functionality, the more I'm getting persuaded that it might be better to type the search term, then have a search button you can hit when you typed your keyword and performed the search, rather than doing n automated thing as not only is simple, but also more intuitive as the user is in full control of what happens. What do you reckon?

0

The document listener will be called whenever the user changes the contents of the entry field, reagrdless of how he did it.
Personally I am 100% in favour of "live search" - instant response and no need for a search button. But hey, it's your application.

(Just for fun, you could see this in action in a little crossword tool I wrote - type anagrams or incomplete words in the entry field and it shows all matching words. NB This searches a list 26 thousand words in real time. Download from
https://www.dropbox.com/s/9vxzqx98bq9d4aa/Words.jar?dl=0

0

The document listener will be called whenever the user changes the contents of the entry field, reagrdless of how he did it.

OK, that's cool if you already have something in it, but what I think it's not clear to me, sorry for that, is what happens the first time you type something in. The first time there is an empty string in it, so, back to my "house" example again, I type "hous" and the event is fired (because I have a filter of minimum 4 words), correct? The I keep typing and add an "e" so that I have "house" and getSentenceContaining(String keyword) is called again and so on every time the string is modified. So basically the key listener, and mouse listeners (I know you pasted some pseudo code but I suppose I need to have a better look at lsteners again especially when it's key, mouse etc) need to be added to the input field where I type the search keyword in.

0

No mouse or key listeners. Just a DocumentListener.
As in inputField.getDocument().addDocumentListener(..

Yes, you start with an empty field.
The user types "H", the document listener's insertUpdate method is called, you see there is only 1 char in the field, so you do nothing.
The user types "o", the document listener is called, you see there are only 2 chars in the field, so you do nothing.
The user types "u", the document listener is called, you see there are only 3 chars in the field, so you do nothing.
The user types "s", the document listener is called, you see there are 4 chars in the field, so you call t he search method and display the results (of which there may be many)
The user types "e", the document listener is called, you see there are >4 chars in the field, so you call the search method and display the results (of which there should be fewer)

Edited by JamesCherrill

0

Thanks, so is this implemented the usual way with a class and handler or by just creating a listener and adding to the field - which is what I've done?
Trouble is, shouldn't I instantiate a DocumentListener class?

...
import javax.swing.event.*;
...
public class SentenceRecorder extends JFrame{
    ...
    private JTextField searchCriterium;
    ...
        public SentenceRecorder(){
        super("List of sentences to remember");
        searchCriterium = new JTextField();
        ...
        DocumentListener typeListener = new DocumentListener();
        searchCriterium.getDocument().addDocumentListener(typeListener);
        }
}

Oh I looked at your application by the way, you're right, the live search is nice and it looks a bit like magic :-)

EDIT: ah wait, perhaps something like this instead:

searchCriterium.getDocument().addDocumentListener(new DocumentListener()){
    //my methods
}

Edited by Violet_82: Possible solution

0

All right, I think I got it sorry, it should be something like the below (this seems to satisfy the abstract class at least) and apparently I have to use all the methods:

searchCriterium.getDocument().addDocumentListener(new DocumentListener(){
            public void changedUpdate(DocumentEvent e){
                System.out.println("changedUpdate");
            }
            public void removeUpdate(DocumentEvent e){
                System.out.println("removeUpdate");
            }
            public void insertUpdate(DocumentEvent e){
                System.out.println("insertUpdate");
            }
        });

Now, I think I can call my function from within those methods (by the way, not sure when changedUpdate is fired, the API is a bit cryptic saying that "Gives notification that an attribute or set of attributes changed.")
So no event handlers as I thought I had to do at the beginning

Edited by Violet_82

0

Yes, that's right. (Equally you could have created an inner class to do the same thing.) When the user edits, it's the insert and removes that will mainly be called. But just keep it simple and write a tiny method to get the latest text, do the search, display the results, and call it from each of the three. That way you're OK no matter what.

0

Eh eh, it's easy to do but a little more complicated to achieve :-).
The principle sort of works but it doesn't execute that well. So, let's look at some code. I've arranged everything into methods so I can call things when I need them.
First of all two extra functions, one just returning the content of the search box (where users type the keyword) and another one looping through the returned set of matched strings (this last functions you'll notice has some problems: I need to append sentences to the JTextArea and therefore I used the append method but because the function gets called at every character typed I end up with loads of results):

public String getKeyword(){//get keyword from input field
        String text = searchCriterium.getText();
        return text;
    }
    public void getMatchedSentence(List< String > matchedSent){//loops thru matched sentences
        for(String theSentence : matchedSent){
            searchResults.append(theSentence + separator);
        }

    }

Then this, which gets thing started:

searchCriterium.getDocument().addDocumentListener(new DocumentListener(){
            public void changedUpdate(DocumentEvent e){
                //System.out.println("changedUpdate");
            }
            public void removeUpdate(DocumentEvent e){
                //System.out.println("removeUpdate");               
                //searchResults.setText(getSentenceContaining(getKeyword()));
                getMatchedSentence(getSentenceContaining(getKeyword()));
            }
            public void insertUpdate(DocumentEvent e){
                //System.out.println("insertUpdate");
                getMatchedSentence(getSentenceContaining(getKeyword()));
                //searchResults.setText(getSentenceContaining(getKeyword()));
            }
        });

Now, other than the obvious problems, there is something really weird going on. I have a filter, let's call it like that, inside the getSentenceContaining function so that if the keyword is less than 4 it returns null:

public List<String> getSentenceContaining(String keyword){
        if(keyword.length() > 3){
        ...
        }
        else{//necessary, otherwise compiler complains no return statement
            return null;
        }
    }

But this is causing enormous issues, not sure why but if I type the first character I get load of errors in the console, exceptions, as below, but when it gets past the fourth character it's all good, so I have removed that filter completely and things run smoothly now, except I don't know how to make sure that I don't end up with too many duplicates inside the results TextArea:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
        at SentenceRecorder.getMatchedSentence(SentenceRecorder.java:239)
        at SentenceRecorder$1.insertUpdate(SentenceRecorder.java:100)
        at javax.swing.text.AbstractDocument.fireInsertUpdate(Unknown Source)
        at javax.swing.text.AbstractDocument.handleInsertString(Unknown Source)
        at javax.swing.text.AbstractDocument.insertString(Unknown Source)
        at javax.swing.text.PlainDocument.insertString(Unknown Source)
        at javax.swing.text.AbstractDocument.replace(Unknown Source)
        at javax.swing.text.JTextComponent.replaceSelection(Unknown Source)
        at javax.swing.text.DefaultEditorKit$DefaultKeyTypedAction.actionPerformed(Unknown Source)
        at javax.swing.SwingUtilities.notifyAction(Unknown Source)
        at javax.swing.JComponent.processKeyBinding(Unknown Source)
        at javax.swing.JComponent.processKeyBindings(Unknown Source)
        at javax.swing.JComponent.processKeyEvent(Unknown Source)
        at java.awt.Component.processEvent(Unknown Source)
        at java.awt.Container.processEvent(Unknown Source)
        at java.awt.Component.dispatchEventImpl(Unknown Source)
        at java.awt.Container.dispatchEventImpl(Unknown Source)
        at java.awt.Component.dispatchEvent(Unknown Source)
        at java.awt.KeyboardFocusManager.redispatchEvent(Unknown Source)
        at java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(Unknown Source)
        at java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(Unknown Source)
        at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(Unknown Source)
        at java.awt.DefaultKeyboardFocusManager.dispatchEvent(Unknown Source)
        at java.awt.Component.dispatchEventImpl(Unknown Source)
        at java.awt.Container.dispatchEventImpl(Unknown Source)
        at java.awt.Window.dispatchEventImpl(Unknown Source)
        at java.awt.Component.dispatchEvent(Unknown Source)
        at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
        at java.awt.EventQueue.access$500(Unknown Source)
        at java.awt.EventQueue$3.run(Unknown Source)
        at java.awt.EventQueue$3.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
        at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
        at java.awt.EventQueue$4.run(Unknown Source)
        at java.awt.EventQueue$4.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
        at java.awt.EventQueue.dispatchEvent(Unknown Source)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
        at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
        at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
        at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
        at java.awt.EventDispatchThread.run(Unknown Source)

Full class is here http://pastebin.com/bUU8GYiP

0

That's a null pointer exception, so that presumably starts when you return null from getSentenceContaining. getMatchedSentence tries to loop through all the Strings in that returned value, which is obviously a disaster if the value is null. You have 2 options:
in getMatchedSentence test for null OR
change getSentenceContaining to return an empty List<String> instead of null

When you do get matching sentances you can't just append them to the text area - you will just fill it up with obsolete irrelevant old entries. So in getMatchedSentence you have to clear the text area before you start appending the latest results.

And finally I'm going to have one last attempt to get you thinking about names.
What do you think a method called getMatchedSentence will do? I would say either it returns a sentence (probably a String) OR whoever wrote it is deliberatly trying to confuse everybody. What I would never guess is that it displays multiple sentences in a text area and returns nothing.

0

OK that worked, thanks, getSentenceContaining now has a new return statement :

else{//necessary, otherwise compiler complains no return statement
            return new ArrayList< String >();
        }

and I'm clearing the text area before appending anything else.

And finally I'm going to have one last attempt to get you thinking about names.

Yep, sorry, name changed to displayMatchedSentences.
This is how my application looks like now:
with_search.jpg
and it all works.
Not sure whether it's a good idea or not, but I was thinking to perhaps add a message to the results textArea saying "No matches" if no matches are found. But that got me to look at the code a bit more carefully and I spotted something odd.

public SentenceRecorder(){      
        ...
        searchCriterium.getDocument().addDocumentListener(new DocumentListener(){
            public void changedUpdate(DocumentEvent e){
                //System.out.println("changedUpdate");
            }
            public void removeUpdate(DocumentEvent e){              
                displayMatchedSentences(getSentenceContaining(getKeyword()));
            }
            public void insertUpdate(DocumentEvent e){              
                displayMatchedSentences(getSentenceContaining(getKeyword()));               
            }
        });
    }//end of constructor
 public List<String> getSentenceContaining(String keyword){// search for keyword and return the whole string/s       
        if(keyword.length() > 3){
            System.out.printf("\n\nKeyword is %s. Sentence(s) containing the keyword:\n", keyword);
            List< String > matchedSentences = new ArrayList< String >();//stores all the matched sentences in the file            
            for(String toFind : allSentences){//loop thru all sentences
                if(toFind.contains(keyword)){//find the ones with matching the keyword              
                    matchedSentences.add(toFind);//add the found sentences to the List                                  
                }
            }           
            if(matchedSentences.size() == 0){//no matches
                System.out.println("None found matching the keyword");
                searchResults.setText("No matching found");
            }
            else if(matchedSentences.size() > 0){
                printSentenceArray(matchedSentences);
            }
            return matchedSentences;
        }
        else{//necessary, otherwise compiler complains no return statement
            return new ArrayList< String >();
        }
    }   
    public String getKeyword(){//get keyword from input field
        String text = searchCriterium.getText();
        return text;
    }
    public void displayMatchedSentences(List< String > matchedSent){//loops thru matched sentences and display them
        searchResults.setText("");//clear output
        for(String theSentence : matchedSent){
            searchResults.append(theSentence + separator);
        }           
    }

Now, the logic in getSentenceContaining is that, I create a list, loop through the sentences stored in the file, check if the keywords match any sentence and then, crucially, return that set of matched sentence, regardless of whether there is a set of matched sentences or not. And I think I did that because the compiler was being unreasonable with return statements, complaining that there was none etc. But this seems wrong as I should return nothing (or perhaps an empty list) if there is no match - and I could then add a message to the textArea as well, and I should return the set of matched sentences only if (matchedSentences.size() > 0){.
If I move the return statement return matchedSentences; inside an if/else statement the compiler won't like it though

Edited by Violet_82

0

How you have it now looks OK to me.
The compiler is just doing its job! If you declare a method as returning something then the copmpiler checks that you always return something, regardless of whichif statements are executed. It checks every possible path through your method and checks that every one reaches a valid return. It's up to you to ensure that every path does reach a return somehow or another (doesn't matter how).
As it is now it will return an empty list if there are no matched sentences, which is OK.
Personally I would turn it round a bit, and titdy it up like this:

List<String> getSentenceContaining ...
     List< String > matchedSentences = new ArrayList< String >();
     if (keyword.length() <= 3) return matchedSentences; // an empty list

     for(String toFind : a ... {
        ...
     }

     if (matchedSentences.size() == 0)
           matchedSentences.add(" no matches found");

     return matchedSentences

now you can just display whatever is returned:
if there are <3 letters it will display nothing
if there are matches it will display them
if there are no matches it will display "no matches"

0

OK I see, thanks for that. It works, but can I ask you, you used matchedSentences.add(" no matches found"); and it works, I attempted this instead searchResults.setText("No matching found"); and it doesn't work: why is that? all I was doing was attempting to change the text inside the textArea, is that because it gets cleared out just after the message is entered? It's not hugely important, just curious, because my first instinct was to add a message to the text box rather than adding it to the List

Edited by Violet_82

0

is that because it gets cleared out just after the message is entered?

Yes, I expect so. That's a good example of why you should keep logic and GUI separate - if you start updating the GUI from both places they are certain to clash sooner or later.

0

OK cool, thanks for all your help and guidance with it, full source code here:
SentenceRecorder.java

/*SentenceRecorder.java
takes a sentence or word as input and saves it on text file. Every new word/sentence is appended at the end of the file
*/
import javax.swing.event.*;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.JLabel;
import javax.swing.JButton;
import javax.swing.JTextArea;
import javax.swing.JScrollPane;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import static java.awt.GridBagConstraints.*;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.Dimension;
import java.io.File;


import java.nio.file.*;//for readAllLines()
import java.nio.file.Paths;//used to get the path of the file
import java.util.ArrayList;//to work with the array list to save the sentences in an ArrayList 
import java.util.List;
import java.util.Collection;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

import java.util.Scanner;
import java.io.FileWriter;
import java.lang.SecurityException;//if no permission to write to file
import java.io.FileNotFoundException;//if the file can't be created
import java.io.IOException;
import java.util.Properties;//to get working directory
import java.io.BufferedWriter;

public class SentenceRecorder extends JFrame{   
    private JLabel instructions;
    private JLabel searchInstructions;
    private JButton submit;
    private JButton search;
    private GridBagLayout gbLayout;
    private JButton clear;
    private JTextArea input;
    private JTextArea searchResults;//displays the search results
    private String stringInput;
    private List< String > allSentences = new ArrayList< String >();//stores all the sentences in the file
    private String filePath;
    private String fileName;
    private JTextField searchCriterium;
    private File file;
    private BufferedWriter fileWriter;
    private String workingDir;
    private String separator;
    private Scanner scannerInput;//to input data into the file
    private Scanner scannerOutput;//to output data from the file
    private final static Charset ENCODING = StandardCharsets.UTF_8;
    public SentenceRecorder(){
        super("List of sentences to remember");
        searchCriterium = new JTextField();
        separator = System.getProperty("line.separator");//getting the system-dependent separator       
        workingDir = System.getProperty("user.dir");        
        instructions = new JLabel("Enter your sentence.");
        searchInstructions = new JLabel("Search the file");
        input = new JTextArea(10,12);//holds the text input
        searchResults = new JTextArea(10,12);
        submit = new JButton("Submit");//submit button
        //search = new JButton("Search");//search button
        clear = new JButton("Clear");//clear button
        stringInput = "";//initialize string to empty       
        gbLayout = new GridBagLayout();
        //System.out.println("workingDir is " + workingDir);
        //input = new Scanner(System.in);       
        fileName = "sample.txt";        
        file = new File(workingDir, fileName);
        allSentences = getSentenceList(fileName);//copying content of file in arrayList
        printSentenceArray(allSentences);
        //getSentenceContaining("sentence");
        setLayout(gbLayout);//set layout of jframe
        add(instructions, new GridBagConstraints(0,0,2,1,0,0,CENTER,HORIZONTAL, new Insets(10,15,10,15),0,0));
        add(new JScrollPane(input), new GridBagConstraints(0,1,2,1,0.5,0.5,CENTER,BOTH, new Insets(10,15,10,15),10,10));        
        add(submit, new GridBagConstraints(0,2,1,1,1.0,1.0,CENTER,HORIZONTAL,new Insets(10,15,10,15),1,1));
        add(clear, new GridBagConstraints(1,2,1,1,1.0,1.0,CENTER,HORIZONTAL,new Insets(10,15,10,15),1,1));
        add(searchInstructions, new GridBagConstraints(0,3,2,1,0,0,CENTER,HORIZONTAL, new Insets(10,15,10,15),0,0));
        add(searchCriterium, new GridBagConstraints(0,4,2,1,1.0,1.0,CENTER,HORIZONTAL,new Insets(10,15,10,15),1,1));
        add(new JScrollPane(searchResults), new GridBagConstraints(0,5,2,1,0.5,0.5,CENTER,BOTH, new Insets(10,15,10,15),10,10));
        //System.out.printf("Enter your sentence or end of file - ctrl+z or Enter+ctrl+d\n");           

        searchCriterium.getDocument().addDocumentListener(new DocumentListener(){
            public void changedUpdate(DocumentEvent e){
                //System.out.println("changedUpdate");
            }
            public void removeUpdate(DocumentEvent e){              
                displayMatchedSentences(getSentenceContaining(getKeyword()));
            }
            public void insertUpdate(DocumentEvent e){              
                displayMatchedSentences(getSentenceContaining(getKeyword()));               
            }
        });

        ProcessButtonHandling handler1 = new ProcessButtonHandling();
        ClearButtonHandling handler2 = new ClearButtonHandling();
        //SearchButtonHandling handler3 = new SearchButtonHandling();
        submit.addActionListener(handler1);
        clear.addActionListener(handler2);  
    }//end of constructor
    //inner class for event handlings
    private class ProcessButtonHandling implements ActionListener{
        public void actionPerformed(ActionEvent event){
            stringInput = input.getText();//copy text from textArea to string
            scannerInput = new Scanner(stringInput);
            try{    
                fileWriter = new BufferedWriter( new FileWriter(file,true));
            }           
            catch(SecurityException securityException){//if you don't have write access
                System.err.println("You don't have write access to this file");
                System.exit(1);
            }
            catch(FileNotFoundException fileNotFoundException){
                System.err.println("Error opening or creating the file");
                System.exit(1);
            }
            catch(IOException ioexception){
                System.err.println("General Error with IO");
                System.exit(1);
            }
            while(scannerInput.hasNext()){
                stringInput = scannerInput.nextLine();
                try{
                    fileWriter.append(stringInput + separator);
                }
                catch(IOException ioexception){
                    System.err.println("General Error with IO");
                    ioexception.printStackTrace();
                    System.exit(1);
                }
                //System.out.printf("Enter your sentence or end of file - ctrl+z or Enter+ctrl+d\n");
            }
            CloseFile();
            Clear();
        }//end of actionPerformed

    }//end of inner class
    private class ClearButtonHandling implements ActionListener{
        public void actionPerformed(ActionEvent event){         
            Clear();
        }//end of actionPerformed       
    }
    /* private class SearchButtonHandling implements ActionListener{
        public void actionPerformed(ActionEvent event){
            //return the matched sentences
            //copy them into the textArea
        }
    } */
    private void Clear(){
        stringInput = "";
        input.setText("");
        CloseFile();        
    }
    public void CloseFile(){
        try{
            fileWriter.close();
        }
        catch(IOException ioexception){
                System.err.println("General Error with IO");
                ioexception.printStackTrace();
                System.exit(1);             
            }
    }//closeFile
    public List<String> getSentenceList(String theFileName){//save file text into array      
        Path path = Paths.get(theFileName);

        if(!(Files.isReadable(path))){
            System.out.println("The file is empty. You need to save something in it first.");//to be printed in the textArea
            return null;            
        }       
        try{
            return Files.readAllLines(path, ENCODING);          
        }
        catch(IOException ioexception){
            System.err.println("General Error with IO");
            ioexception.printStackTrace();
            System.exit(1);
        }
        return null;        
    }   
    public void printSentenceArray(List< String > toPrint){
        if((toPrint == null)||(toPrint.size() == 0)){//to avoid NPE
            System.out.println("List is empty: ");
            return;
        }
        System.out.println("Array contains " + toPrint.size() + " sentences:");
            for(String s: toPrint){
                //System.out.printf("%s", toPrint.get(count));
                System.out.println(s);
            }

    }
    public List<String> getSentenceContaining(String keyword){// search for keyword and return the whole string/s        
        List< String > matchedSentences = new ArrayList< String >();//stores all the matched sentences in the file            
        if(keyword.length() <= 3){           
            return matchedSentences;//empty list
        }
        System.out.printf("\n\nKeyword is %s. Sentence(s) containing the keyword:\n", keyword);

        for(String toFind : allSentences){//loop thru all sentences
            if(toFind.contains(keyword)){//find the ones with matching the keyword              
                matchedSentences.add(toFind);//add the found sentences to the List                                  
            }
        }           
        if(matchedSentences.size() == 0){//no matches
            System.out.println("None found matching the keyword");          
            matchedSentences.add(" no matches found");
        }   
        printSentenceArray(matchedSentences);
        return matchedSentences;        
    }   
    public String getKeyword(){//get keyword from input field
        String text = searchCriterium.getText();
        return text;
    }
    public void displayMatchedSentences(List< String > matchedSent){//loops thru matched sentences and display them
        searchResults.setText("");//clear output
        for(String theSentence : matchedSent){
            searchResults.append(theSentence + separator);
        }

    }
}//end of SentenceRecorder

And SentenceRecorderTest.java

/*SentenceRecorderTest.java*/
import javax.swing.JFrame;
public class SentenceRecorderTest{
    public static void main(String[] args){ 
        SentenceRecorder sentenceRecorder = new SentenceRecorder();
        sentenceRecorder.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);        
        //sentenceRecorder.CloseFile();
        sentenceRecorder.pack();
        //sentenceRecorder.setSize(900,800);
        sentenceRecorder.setVisible(true);
    }
}
0

OK. now that's done I want to show you one more thing.
Your code mixes program logic with GUI and makes both of them confusing. I just did a cut/paste job on your code to separate the logic from the GUI. There's now a GUI class with the main method that just has GUI code in it and uses an instance of a SentenceRecorder class that is pure logic, and delegates all its processing to that. (There were lots of other things I wanted to tidy up but all I did here was cut/paste your code).
Just look at how much clearer the code is now (I omitted the include statements because they are not interesting):.

public class SentenceRecorderGUI extends JFrame {

    public static void main(String[] args) {
        new SentenceRecorderGUI();
    }

    SentenceRecorder sentenceRecorder = new SentenceRecorder();

    private String stringInput;

    private String separator = System.getProperty("line.separator");

    private JTextField searchCriterium;
    private JLabel instructions;
    private JLabel searchInstructions;
    private JButton submit;
    private JButton search;
    private GridBagLayout gbLayout;
    private JButton clear;
    private JTextArea input;
    private JTextArea searchResults;//displays the search results

    public SentenceRecorderGUI() {

        super("List of sentences to remember");
        searchCriterium = new JTextField();
        instructions = new JLabel("Enter your sentence.");
        searchInstructions = new JLabel("Search the file");
        input = new JTextArea(10, 12);//holds the text input
        searchResults = new JTextArea(10, 12);
        submit = new JButton("Submit");//submit button
        //search = new JButton("Search");//search button
        clear = new JButton("Clear");//clear button
        stringInput = "";//initialize string to empty       
        gbLayout = new GridBagLayout();
        setLayout(gbLayout);//set layout of jframe
        add(instructions, new GridBagConstraints(0, 0, 2, 1, 0, 0, CENTER, HORIZONTAL, new Insets(10, 15, 10, 15), 0, 0));
        add(new JScrollPane(input), new GridBagConstraints(0, 1, 2, 1, 0.5, 0.5, CENTER, BOTH, new Insets(10, 15, 10, 15), 10, 10));
        add(submit, new GridBagConstraints(0, 2, 1, 1, 1.0, 1.0, CENTER, HORIZONTAL, new Insets(10, 15, 10, 15), 1, 1));
        add(clear, new GridBagConstraints(1, 2, 1, 1, 1.0, 1.0, CENTER, HORIZONTAL, new Insets(10, 15, 10, 15), 1, 1));
        add(searchInstructions, new GridBagConstraints(0, 3, 2, 1, 0, 0, CENTER, HORIZONTAL, new Insets(10, 15, 10, 15), 0, 0));
        add(searchCriterium, new GridBagConstraints(0, 4, 2, 1, 1.0, 1.0, CENTER, HORIZONTAL, new Insets(10, 15, 10, 15), 1, 1));
        add(new JScrollPane(searchResults), new GridBagConstraints(0, 5, 2, 1, 0.5, 0.5, CENTER, BOTH, new Insets(10, 15, 10, 15), 10, 10));
        searchCriterium.getDocument().addDocumentListener(new DocumentListener() {
            public void changedUpdate(DocumentEvent e) {
                //System.out.println("changedUpdate");
            }

            public void removeUpdate(DocumentEvent e) {
                displayMatchedSentences(sentenceRecorder.getSentenceContaining(getKeyword()));
            }

            public void insertUpdate(DocumentEvent e) {
                displayMatchedSentences(sentenceRecorder.getSentenceContaining(getKeyword()));
            }
        });

        ProcessButtonHandling handler1 = new ProcessButtonHandling();
        ClearButtonHandling handler2 = new ClearButtonHandling();
        //SearchButtonHandling handler3 = new SearchButtonHandling();
        submit.addActionListener(handler1);
        clear.addActionListener(handler2);

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pack();
        //sentenceRecorder.setSize(900,800);
        setVisible(true);

    }

    //inner class for event handlings
    private class ProcessButtonHandling implements ActionListener {

        public void actionPerformed(ActionEvent event) {
            stringInput = input.getText();//copy text from textArea to string
            sentenceRecorder.processSentences(stringInput);
            Clear();

        }//end of actionPerformed

    }//end of inner class

    private class ClearButtonHandling implements ActionListener {

        public void actionPerformed(ActionEvent event) {
            Clear();
        }//end of actionPerformed       
    }

    private void Clear() {
        stringInput = "";
        input.setText("");
        sentenceRecorder.CloseFile();
    }

    public String getKeyword() {//get keyword from input field
        String text = searchCriterium.getText();
        return text;
    }

    public void displayMatchedSentences(List< String> matchedSent) {//loops thru matched sentences and display them
        searchResults.setText("");//clear output
        for (String theSentence : matchedSent) {
            searchResults.append(theSentence + separator);
        }

    }

}

and the logic:

/*SentenceRecorder.java
takes a sentence or word as input and saves it on text file. Every new word/sentence is appended at the end of the file
*/

public class SentenceRecorder {   


    private List< String > allSentences = new ArrayList< String >();//stores all the sentences in the file
    private String filePath;
    private String fileName;
    private File file;
    private BufferedWriter fileWriter;
    private String workingDir;
    private String separator = System.getProperty("line.separator"); 
    private Scanner scannerInput;//to input data into the file
    private Scanner scannerOutput;//to output data from the file
    private final static Charset ENCODING = StandardCharsets.UTF_8;

    public SentenceRecorder(){

        workingDir = System.getProperty("user.dir");        

        //System.out.println("workingDir is " + workingDir);
        //input = new Scanner(System.in);       
        fileName = "sample.txt";        
        file = new File(workingDir, fileName);
        allSentences = getSentenceList(fileName);//copying content of file in arrayList
        printSentenceArray(allSentences);
        //getSentenceContaining("sentence");

        //System.out.printf("Enter your sentence or end of file - ctrl+z or Enter+ctrl+d\n");           
    }//end of constructor

  public void processSentences(String stringInput) {
            scannerInput = new Scanner(stringInput);
            try{    
                fileWriter = new BufferedWriter( new FileWriter(file,true));
            }           
            catch(SecurityException securityException){//if you don't have write access
                System.err.println("You don't have write access to this file");
                System.exit(1);
            }
            catch(FileNotFoundException fileNotFoundException){
                System.err.println("Error opening or creating the file");
                System.exit(1);
            }
            catch(IOException ioexception){
                System.err.println("General Error with IO");
                System.exit(1);
            }
            while(scannerInput.hasNext()){
                stringInput = scannerInput.nextLine();
                try{
                    fileWriter.append(stringInput + separator);
                }
                catch(IOException ioexception){
                    System.err.println("General Error with IO");
                    ioexception.printStackTrace();
                    System.exit(1);
                }
                //System.out.printf("Enter your sentence or end of file - ctrl+z or Enter+ctrl+d\n");
            }
            CloseFile();
  }


    public void CloseFile(){
        try{
            fileWriter.close();
        }
        catch(IOException ioexception){
                System.err.println("General Error with IO");
                ioexception.printStackTrace();
                System.exit(1);             
            }
    }//closeFile
    public List<String> getSentenceList(String theFileName){//save file text into array      
        Path path = Paths.get(theFileName);

        if(!(Files.isReadable(path))){
            System.out.println("The file is empty. You need to save something in it first.");//to be printed in the textArea
            return null;            
        }       
        try{
            return Files.readAllLines(path, ENCODING);          
        }
        catch(IOException ioexception){
            System.err.println("General Error with IO");
            ioexception.printStackTrace();
            System.exit(1);
        }
        return null;        
    }   

    public void printSentenceArray(List< String > toPrint){
        if((toPrint == null)||(toPrint.size() == 0)){//to avoid NPE
            System.out.println("List is empty: ");
            return;
        }
        System.out.println("Array contains " + toPrint.size() + " sentences:");
            for(String s: toPrint){
                //System.out.printf("%s", toPrint.get(count));
                System.out.println(s);
            }

    }
    public List<String> getSentenceContaining(String keyword){// search for keyword and return the whole string/s        
        List< String > matchedSentences = new ArrayList< String >();//stores all the matched sentences in the file            
        if(keyword.length() <= 3){           
            return matchedSentences;//empty list
        }
        System.out.printf("\n\nKeyword is %s. Sentence(s) containing the keyword:\n", keyword);

        for(String toFind : allSentences){//loop thru all sentences
            if(toFind.contains(keyword)){//find the ones with matching the keyword              
                matchedSentences.add(toFind);//add the found sentences to the List                                  
            }
        }           
        if(matchedSentences.size() == 0){//no matches
            System.out.println("None found matching the keyword");          
            matchedSentences.add(" no matches found");
        }   
        printSentenceArray(matchedSentences);
        return matchedSentences;        
    }   

}//end of SentenceRecorder

Edited by JamesCherrill: Instantiated correct class in main method!

This topic has been dead for over six months. Start a new discussion instead.
Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.