Reading text file using stream - Variable in lambda expression - java

I would like to read a text file, work with the string I have from each line, add a variable and continue.
For example: I have a text file with three lines and I'd like to add a variable to the end of each line which gets upped by one for each line.
To break everything down I made an example program but I still do not get fully behind it.
My text file "test.txt" has three lines of text "Line1", "Line2" and "Line3" and I have an Integer named testNum with a value of 500 which I would like to up after each line.
My code is the following:
String fileName = "test.txt";
int testNum = 1024;
Stream<String> readFileStream = null;
try {
readFileStream = Files.lines(Paths.get(fileName));
} catch (IOException e) {
e.printStackTrace();
}
readFileStream.forEach( line -> {
System.out.println(line+testNum);
testNum++;
});
Now I understand that the issue lies in the lambda expression. Can someone explain to me why I need local variables for the lambda expression and am unable to access variables declared outside from it?
Moreover, I tried to change my code to use a for each instead but for each seems not applicable for "Stream", e.g.:
for(String line : readFileStream){
}
Thanks a lot in advance.

Generally, the time and place of creation of a lambda expression differs from the time and place of execution. Sometimes, a lambda expression is created in method A and executed in method B half minutes or hours later. And it might be executed on a different thread. So it would not be sensible to write to variables with method scope (i.e. stack variables that only exist while the method is executed). Read access to those variable is allowed as their value is 'copied' into the lambda expression at creation time.
In your case, it might be easier to give up streams and use the List version of Files.lines(...), so you can iterate via for-loop:
List<String> lines = Files.readAllLines(Paths.get(filename));
int testNum = 500;
for(String line : lines) {
System.out.println(line + testNum);
testNum++;
}

If you want to use streams for this task you can create a specific String consumer https://docs.oracle.com/javase/8/docs/api/java/util/function/Consumer.html
String fileName = "test.txt";
Stream<String> readFileStream = null;
try {
readFileStream = Files.lines(Paths.get(fileName));
} catch (IOException e) {
e.printStackTrace();
}
readFileStream.forEach(
new Consumer<String>() {
int testNum = 1024;
public void accept(String line) {
try {
System.out.println(line + testNum++);
} catch (Exception e) {
e.printStackTrace();
}
}
});

Related

In Java, Is it possible to return more than one value from try catch block?

I want to read the Id, name and score from console for another use. However these three variables are inside try-catch block scope. I wonder if there is any way I can get these three values return from try-catch.(If I don't want to put the three variables individually in three pairs of try-catch block) Thanks for the time.
Here is my sample code:
StuManage sm = new StuManage();
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("Please enter the student ID: ");
try {
String Id = br.readLine();
String name = br.readLine();
float score =Float.parseFloat(br.readLine());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Yes. Just declare the method as throws IOException and remove the try catch altogether.
yes , you can declare and initialize those to an invalid value
String id = null;
String name = null;
float score = 1.0f;
try {
id = br.readLine();
name = br.readLine();
score = Float.parseFloat(br.readLine());
} catch (IOException e) {
then you need to check after that try block which values are still holding and invalid initial value...
Just ensure that the variables are declared global to the method with their default values, that way it should be fine to access them throughout the method.
Another solution would be to remove the try/catch from the method and rather put the try/catch within the main method, that way you'll let the exception(s)(if any) bubble up to the main method and then handle them there, which you'll also benefit from because you no longer need to worry about scoping issues.
Easily you can't, Because try and catch block is for check block of code for errors, Because of that the block of code should't be accessible outside the try block to be truly tested.

What would be a safe way to split a string into multiple parts in Java?

Let me clarify the question I am asking. I have a java program I am working on that takes input from the keyboard via a readline library called JLine2. The library takes the entire line types as a command instead on breaking it up into space separated commands and arguments. What I am looking for is a safe way to break up the string that is passed as input.
I have tried using an array but since I am in the early stages of concept I don't yet know how many arguments my largest command will have so using a pre-initialized array I don't think will work. The problem I have ran into is when I check for null values in the array or when I check to see if a particular command or argument is present. Java keeps throwing an exception about the array index being out of scope or something. Because the array does not actually have a value for say array index 1 which is an argument to command in array index 0.
So what I am looking for is a way to take a string and safely split it into parts without having Java yelling at me when and array exception has occurred.
Here is the very slim code I can provide...
ConfigShell.class
package shell;
import java.io.IOException;
import configFS.ConfigFS;
import jline.console.ConsoleReader;
public class ConfigShell {
private ConfigFS config;
public ConfigShell() throws IOException {
config = new ConfigFS();
}
public void init() throws IOException {
ConsoleReader console = new ConsoleReader();
// When the program starts we want to be placed at / (root).
console.setPrompt(">> ");
// In this case an infinite loop is better than a loop based on whether line is equal to null.
// This allows line to be equal to null and still stay inside the shell.
while (true) {
String line = console.readLine();
if (line != null) {
// If pre-initialize the array I can check for null as a value for an array index.
// If I did this at time I needed the array and there were not enough index occupied the system would return an exception.
String[] cmdArgs = new String[4];
// We need to split up the incoming line because JLine2 does not do it for me.
// This allows me to evaluate the entire command piece by piece rather all at once.
cmdArgs = line.split("\\s+");
if (cmdArgs[0] != null && cmdArgs[0].equals("add")) {
if (cmdArgs[1] != null && cmdArgs[1].equals("server")) {
if (cmdArgs[2] != null) {
config.addServer(cmdArgs[2]);
System.out.println("Added server " + cmdArgs[2] + " to the configuration successfully.");
}
}
}
if (cmdArgs[0].equals("exit")) {
System.exit(0);
}
}
}
}
}
Note for testing: My Start.class main method makes a call to the init method in the above file.
You can do:
String cmdArgs = line.split("\\s+");
and then, before accessing any particular index, check the size of the array so that you do not get ArrayIndexOutOfBoundException
Something like this:
if(cmdArgs.length>=2){
//It means you have at least 2 elements
//Now its safe to access cmdArgs[0] and cmdArgs[1]
}
If all your problem is to have a storage for a variable number of strings you can use ArrayList<String> object.
You declare it like ArrayList<String> as = new ArrayList<String>();
Then when you split something from your command string you will simply use add method:
as.add(yourString);
If you need to retrieve a particular element of the ArrayList you can use its get method:
as.get(0);
You can process all elements with for each loop:
for(String str: as) {
println(str):
}
Have a look here for info and here for an example.
As I think you can use StringTokenizer class and its methods for your requirement.
see the sample code below:
if(line!=null)
{
StringTokenizer st=new StringTokenizer(line);// by default it takes space as delimiter....you can use as required as second argument in constructor...
while(st.hasMoreTokens())
{
String token1=st.nextToken();
// do your stuffs here..........
// I don't know exactly about your required logic here......
/* if(token1.equals("add"))
{
String token2=st.nextToken();
if(token2.equals("server"))
{
String token3=st.nextToken();
config.addServer(token3);
System.out.println("Added server " + token3 + " to the configuration successfully.");
}
}
*/
}// while closing...
}// outer if closing...
Or as PM 77-1 told you can use ArrayList. But as my opinion LinkedList should be a better option here.

Java: Read from Config File & Efficiently Perform Tests Based on Values

Okay, I'm sure that I'm not going about this in the most efficient way and I'm looking for some help regarding how to do this more efficiently...
config.txt file contains key/value pairs, where key = name of test and value = whether to execute test
parse through config file and create a list of tests to run
run those tests
Here is how I'm currently going about this
create an ArrayList by passing to a helper function, parseConfig, a BufferedReader over my config file. parseConfig returns a TreeSet , which I use in the constructor method for my ArrayList
parseConfig iterates over lines of text in config file. If value indicates to perform test, add name of test to TreeSet. Return TreeSet.
Iterate over ArrayList with enhanced for loop. Body of enhanced for loop is basically a long if/else statement...if key.equals ("thisTest"), perform thisTest, else if key.equals (thatTest), perform thatTest...etc
It's that last part that I really don't like. It works well enough, but it seems clumsy and inefficient. Since my ArrayList is constructed using a TreeSet, it is in sorted order. I would like to use a more elegant and deterministic method for mapping my keys to tests to perform. Can anyone help me?
I would do something else since all you need to do with this list is to test it's entries or not.
I would take line by line and apply a regular expression on it, from what I see it is going to be really simple with only two groups and a positive lookahead, this way I could extract all the matching lines only and create an ArrayList out of those, then iterate the ArrayList and test every method. If you can give some input of how the file looks I can help you put with the code.
UPDATE
For example here is the code I come up (in 5 min could be improved) that would do the parsing:
/**
*
* #param inputFile location of inputFile
* #return {#link ImmutableSet} of tests to run
*/
public static ImmutableSet<String> parseConfigFile(File inputFile){
HashSet<String> innerSet = Sets.newHashSet();
BufferedReader bufferedReader = null;
try {
bufferedReader = new BufferedReader(new FileReader(inputFile));
String newLine = "";
while( (newLine = bufferedReader.readLine()) != null){
Pattern p = Pattern.compile("(.+)=(?=yes|1|true)(.+)");
Matcher m = p.matcher(newLine);
while(m.find()){
//System.out.println(m.group(1));
innerSet.add(m.group(1));
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(bufferedReader != null)
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return ImmutableSet.copyOf(innerSet);
}
I testes it for a file that looks like this for example:
SomeTest=true
SomeOtherTest=false
YetAnotherTest=1
LastTest=yes
GogoTest=no
OneMore=0
The answer was to create a HashMap <String, Method> object.

Java ConcurrentHashMap corrupt values

I have a ConcurrentHashMap that exhibits strange behavior on occasion.
When my app first starts up, I read a directory from the file system and load contents of each file into the ConcurrentHashMap using the filename as the key. Some files may be empty, in which case I set the value to "empty".
Once all files have been loaded, a pool of worker threads will wait for external requests. When a request comes in, I call the getData() function where I check if the ConcurrentHashMap contains the key. If the key exists I get the value and check if the value is "empty". If value.contains("empty"), I return "file not found". Otherwise, the contents of the file is returned. When the key does not exist, I try to load the file from the file system.
private String getData(String name) {
String reply = null;
if (map.containsKey(name)) {
reply = map.get(name);
} else {
reply = getDataFromFileSystem(name);
}
if (reply != null && !reply.contains("empty")) {
return reply;
}
return "file not found";
}
On occasion, the ConcurrentHashMap will return the contents of a non-empty file (i.e. value.contains("empty") == false), however the line:
if (reply != null && !reply.contains("empty"))
returns FALSE. I broke down the IF statement into two parts: if (reply != null) and if (!reply.contains("empty")). The first part of the IF statement returns TRUE. The second part returns FALSE. So I decided to print out the variable "reply" in order to determine if the contents of the string does in fact contain "empty". This was NOT the case i.e. the contents did not contain the string "empty". Furthermore, I added the line
int indexOf = reply.indexOf("empty");
Since the variable reply did not contain the string "empty" when I printed it out, I was expecting indexOf to return -1. But the function returned a value approx the length of the string i.e. if reply.length == 15100, then reply.indexOf("empty") was returning 15099.
I experience this issue on a weekly basis, approx 2-3 times a week. This process is restarted on a daily basis therefore the ConcurrentHashMap is re-generated regularly.
Has anyone seen such behavior when using Java's ConcurrentHashMap?
EDIT
private String getDataFromFileSystem(String name) {
String contents = "empty";
try {
File folder = new File(dir);
File[] fileList = folder.listFiles();
for (int i = 0; i < fileList.length; i++) {
if (fileList[i].isFile() && fileList[i].getName().contains(name)) {
String fileName = fileList[i].getAbsolutePath();
FileReader fr = null;
BufferedReader br = null;
try {
fr = new FileReader(fileName);
br = new BufferedReader(fr);
String sCurrentLine;
while ((sCurrentLine = br.readLine()) != null) {
contents += sCurrentLine.trim();
}
if (contents.equals("")) {
contents = "empty";
}
return contents;
} catch (Exception e) {
e.printStackTrace();
if (contents.equals("")) {
contents = "empty";
}
return contents;
} finally {
if (fr != null) {
try {
fr.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (br != null) {
try {
br.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (map.containsKey(name)) {
map.remove(name);
}
map.put(name, contents);
}
}
}
} catch (Exception e) {
e.printStackTrace();
if (contents.equals("")) {
contents = "empty";
}
return contents;
}
return contents;
}
I think your problem is that some of your operations should be atomic and they aren't.
For example, one possible thread interleaving scenario is the following:
Thread 1 reads this line in the getData method:
if (map.containsKey(name)) // (1)
the result is false and Thread 1 goes to
reply = getDataFromFileSystem(name); // (2)
in getDataFromFileSystem, you have the following code:
if (map.containsKey(name)) { // (3)
map.remove(name); // (4)
}
map.put(name, contents); // (5)
imagine that another thread (Thread 2) arrives at (1) while Thread 1 is between (4) and (5): name is not in the map, so thread 2 goes to (2) again
Now that does not explain the specific issue you are observing but it illustrates the fact that when you let many threads run concurrently in a section of code without synchronization, weird things can and do happen.
As it stands, I can't find an explanation for the scenario you describe, unless you call reply = map.get(name) more than once in your tests, in which case it is very possible that the 2 calls don't return the same result.
First off, don't even think that there is a bug in ConcurrentHashMap. JDK faults are very rare and even entertaining the idea will pull you away from properly debugging your code.
I think your bug is as follows. Since you are using contains("empty") what happens if the line from the file has the word "empty" in it? Isn't that going to screw things up?
Instead of using contains("empty") I would use ==. Make the "empty" a private static final String then you can use equality on it.
private final static String EMPTY_STRING_REFERENCE = "empty";
...
if (reply != null && reply != EMPTY_STRING_REFERENCE) {
return reply;
}
...
String contents = EMPTY_STRING_REFERENCE;
...
// really this should be if (contents.isEmpty())
if (contents.equals("")) {
contents = EMPTY_STRING_REFERENCE;
}
This is, btw, the only time you should be using == to compare strings. In this case you want to test it by reference and not by contents since lines from your files could actually contain the magic string.
Here are some other points:
In general, whenever you are using the same String in multiple places in your program, it should be pulled up to a static final field. Java will probably do this for you anyway but it makes the code a lot cleaner as well.
#assylias is spot on about race conditions when you make 2 calls to ConcurrentHashMap. For example, instead of doing:
if (map.containsKey(name)) {
reply = map.get(name);
} else {
You should do the following so you do only one.
reply = map.get(name);
if (reply == null) {
In your code you do this:
if (map.containsKey(name)) {
map.remove(name);
}
map.put(name, contents);
That should be rewritten as the following. There is no need to remove before the put which introduces race conditions as #assylias mentioned.
map.put(name, contents);
You said:
if reply.length == 15100, then reply.indexOf("empty") was returning 15099.
This is not possible with the same reply String. I suspect that you were looking at different threads or in some other way misinterpreting the output. Again, don't be fooled into thinking that there are bugs in java.lang.String.
First, using ConcurrentHashMap does not protect you if you call its methods from multiple threads in sequence. If you call containsKey and get afterwards and another thread calls remove in between you will have a null result. Be sure to call only get and check for null instead of containsKey/get. It's also better regarding performance, because both methods nearly have the same cost.
Second, the weird indexOf call result is either due to a programming error, or points to memory corruption. Is there any native code involved in your application? What are you doing in getDataFromFileSystem? I observed memory corruption when using FileChannel objects from multiple threads.

Problems initializing a final variable in Java

I keep running into slight variations of a problem in Java and it's starting to get to me, and I can't really think of a proper way to get around it.
I have an object property that is final, but dynamic. That is, I want the value to be constant once assigned, but the value can be different each runtime. So I declare the class level variable at the beginning of the class - say private final FILE_NAME;. Then, in the constructor, I assign it a value - say FILE_NAME = buildFileName();
The problem begins when I have code in the buildFileName() method that throws an exception. So I try something like this in the constructor:
try{
FILE_NAME = buildFileName();
}
catch(Exception e){
...
System.exit(1);
}
Now I have an error - "The blank final field FILE_NAME may not have been initialized." This is where I start to get slightly annoyed at Java's strict compiler. I know that this won't be a problem because if it gets to the catch the program will exit... But the compiler doesn't know that and so doesn't allow this code. If I try to add a dummy assignment to the catch, I get - "The final field FILE_NAME may already have been assigned." I clearly can't assign a default value before the try-catch because I can only assign to it once.
Any ideas...?
How about
String tempName = null;
try{
tempName = buildFileName();
}
catch(Exception e){
...
System.exit(1);
}
FILE_NAME = tempName;
Either
try {
FILE_NAME = buildFileName();
} catch (Exception e){
...
System.exit(1);
throw new Error();
}
Or some prefer:
private static final String FILE_NAME = fileName();
private static String fileName() {
try {
return buildFileName();
} catch (Exception e){
...
System.exit(1);
throw new Error();
}
}
But calling System.exit in a static initialiser is probably a bad idea. It's going to mess your unit tests up.
On second thought, I think I just came up with a solution! - use an intermediate variable.
String fileName = null;
try{
fileName = buildFileName();
}
catch(Exception e){
...
System.exit(1);
}
FILE_NAME = fileName;
Don't know why it took me so long to think of this...
I would personally just throw an Error -- if your error flow is properly designed, the System.exit() should be redundant. Your program presumably doesn't plough on into the wilderness if an Error is thrown...?
Along the same lines as the OP's issue, I had to be able to find a way to assign values to final fields to be read in from a .properties file on the filesystem, so the values couldn't be known by my app until that happened. Using a generalized method call to assign the value after reading the content of the .properties file into a Properties object on app startup was a Hail Mary pass that thankfully worked out. It also limits the no. of times the file has to be read to once per the app's getting loaded into the memory simply by the code checking to see if the Properties object is or is not currently null. But of course, once assigned, the final field's value cannot be altered except by altering its "final" status via manuipulating the field's modifying definition at runtime (as discussed in some other places here on SO, such as https://stackoverflow.com/a/3301720/1216686 - sneaky, but I love it!). Code example, with typical runtime error checking such as for NPEs omitted for brevity:
import java.util.Properties;
public class MyConstants {
private static Properties props; // declared, not initialized,
// so it can still be set to
// an object reference.
public static String MY_STRING = getProperty("prop1name", "defaultval1");
public static int MY_INT = Integer.parseInt(getProperty("prop2name", "1"));
// more fields...
private static String getProperty(String name, String dflt) {
if ( props == null ) {
readProperties();
}
return props.getProperty(name, dflt);
}
private static void readProperties() {
props = new Properties(); // Use your fave way to read
// props from the file system; a permutation
// of Properties.load(...) worked for me.
}
// Testing...
public static void main(String[] args) {
System.out.println(MY_STRING);
System.out.println(MY_INT);
}
}
This lets you externalize properties to be read into the app and still mark the fields used to hold their values as "final". It also allows you to guarantee a returned value for the final field value since getProperty() in the Properties class allows the method's calling code to pass in a default value to use in case the property's key-value pair wasn't found in the external .properties file.

Categories

Resources