Read the file once and use the data multiple times - java

I wrote a java class which reads a file and stores each line in an arraylist. I want to access this arraylist large number of times. Everytime the class is called to access the arraylist, it reads the file again. I want the file to be read once and then access the arraylist multiple times. How can I do this?

Store it in a field of the class. I.e.:
public class Foo {
private List<String> list;
public List<String> readData() {
if (list != null) {
return list;
}
// do the reading.
}
}
Note that if this is used in a multithreaded environment you'd have to take extra measures. For example put synchronized on the method.
As Peter noted, if you can read multiple files, then you can use a Map<String, List<String>>
Another note is that you should use only one instance of this class. If you create multiple instances you won't have the desired effect.

It sounds like you should be reading the file on construction of the class rather than when accessing it. That doesn't necessarily mean in the constructor, mind you - you may well want to have a static factory method that reads the files into an ArrayList, and then passes that list to the real constructor. This would make the class easier to test (and use in other tests).
Then you only need to create the class once, and make the rest of your code use the same instance. Note that this doesn't require use of the singleton pattern, which would itself make testing harder. It just means propagating the instance to all the code that needs it.

Maybe you need to make a singleton? Then you will read the file only once - when you create a really new instance of class.

If its a web application, maybe you would consider storing it in the ServletContext or in the user HttpSession depending on how much does the file changes

Related

How to create a HashMap with methods as values?

I am working a small program which can receive several commands. Each of these commands should cause different methods to run. I was thinking that if there were a way to put all the methods into a HashMap and invoke them directly by getting the value paired with the command Key instead of using if statements, it could make things much simpler but as far as I understand this is not possible since methods aren't treated as objects in Java. Still, it will be educative to find out if there is a way to do this.
Methods aren't objects (at least mostly not), but there is a concept that matches what you want: the functional interface, which is defined as an interface that has exactly one abstract method. Two out-of-the-box candidates are Runnable, which takes no parameters, and Consumer, which takes a single parameter and might be the best option if you want to pass in some kind of input (like a Scanner). (If you also want a configurable output, BiConsumer taking a Scanner and a PrintWriter might be suitable.)
Java has a convenience feature called method references that can automatically transform a method into an instance of a functional interface. Put together, it might look like this:
Map<String, Consumer<Scanner>> commands = new HashMap<>();
...
commands.put("foo", someCommand::go); // where someCommand is a variable with a go(Scanner) method
commands.put("bar", new OtherCommand());
commands.put("hello", unused -> { System.out.println("Hello!"); });
...
String commandName = scanner.next();
commands.get(commandName).accept(scanner);
This is not a good idea, make methods as hashmap value don't satisfied shell command complex scene, maybe you can use Runnable Object as value.
Another solution, you can use Spring Shell.
#ShellMethod("commandName")
public String doSomething(String param) {
return String.format("Hi %s", param);
}

Running a class with the name within in a variable at run-time in JAVA

I have been learning Java and over the last few weeks I have created a bunch of classes for practice purposes. It got into my head that it would be cool to create a class that allowed me to see a list of all the classes that I have created and run them by choosing the class I want.
The way I did it and how far I have gone:
I read into a HashMap<Integer,String> a list of all my classes with a SimpleFileVisitor.
From this list the user can chose a file by entering the number associated with the class.
A string is returned with the class name.
Now here comes the issue.
I end up for example with a string called Clock.class.
I want to run this. How?
Let's say that I knew the class I wanted to run. I could simple use Clock.main()
The issue here is that I will not know which class to run until run-time, so I am lost.
I have been toying around with the Reflection API. I am able to instantiate an object of the Clock.class but nothing happens.
Maybe I should not be using reflection at all? Maybe there is a simpler way?
This is where I am stuck, I hope someone can enlighten me. :)
You could use reflection to call the main method of the class:
Class<?> cls = Class.forName("package.path.yourClassName");
Method m = cls.getMethod("main", String[].class); //mandatory signature for main()
String[] params = null; // any params on the call?
m.invoke(null, (Object) params);
Note: The first parameter of invoke() would be the instance on which you'd like to invoke the call. But static mehtods don't belong to instances, therefore use null.
You have the File path to your class files from traversing via SimpleFileVisitor. Store the file name and path in a Map. When user chooses lets say Clock.class get path corresponding to it and start another java process.
Simply do
Process process = Runtime.getRuntime().exec("/pathToJDK/bin/java", pathToClassFile);
You can play around with I/O and Error streams like -
InputStream inputStream= process .getErrorStream();
//print this stream

pattern for getting around final limitation of Java closure

I'm trying to write a very simple piece of code and can't figure out an elegant solution to do it:
int count = 0;
jdbcTemplate.query(readQuery, new RowCallbackHandler() {
#Override
public void processRow(ResultSet rs) throws SQLException {
realProcessRow(rs);
count++;
}
});
This obviously doesn't compile. The 2 solutions that I'm aware of both stink:
I don't want to make count a class field because it's really a local variable that I just need for logging purposes.
I don't want to make count an array because it is plain ugly.
This is just silly, there got to be a reasonable way to do it?
A third possibility is to use a final-mutable-int-object, for example:
final AtomicInteger count = new AtomicInteger(0);
....
count.incrementAndGet();
Apache Commons also have a MutableInteger I believe, but I have not used it.
You seem to already be aware of the solutions (they are different though); and you are probably aware of the reasons (it cannot capture local variables by reference because the variable might not exist by the time the closure is run, so it must capture by value (have multiple copies); it is bad to have the same variable refer to different copies in different scopes that each can be changed independently, so they cannot be changed).
If your closure does not need to share state back to the enclosing scope, then a field in the class is the right thing to do. I don't understand what your objection is. If the closure needs to be able to be called multiple times and it needs to increment each time, then it needs to maintain state in the object. A field (instance variable) properly expresses the storing of state in an object. The field can be initialized with the captured value from the outside scope.
If your closure needs to share state back to the enclosing scope (which is not a very common situation), then using a mutable structure (like an array) is the right thing to do, because it avoids the problem of the lifetime of the local variable.
I typically make count a class field but add a comment that it is only a field because it is used by an inner closure, Runnable etc...

Java 1.4 singleton containing a mutable field

I'm working on a legacy Java 1.4 project, and I have a factory that instantiates a csv file parser as a singleton.
In my csv file parser, however, I have a HashSet that will store objects created from each line of my CSV file. All that will be used by a web application, and users will be uploading CSV files, possibly concurrently.
Now my question is : what is the best way to prevent my list of objects to be modified by 2 users ?
So far, I'm doing the following :
final class MyParser {
private File csvFile = null;
private Set myObjects = Collections.synchronizedSet(new HashSet);
public synchronized void setFile(File file) {
this.csvFile = file;
}
public void parse()
FileReader fr = null;
try {
fr = new FileReader(csvFile);
synchronized(myObjects) {
myObjects.clear();
while(...) { // foreach line of my CSV, create a "MyObject"
myObjects.add(new MyObject(...));
}
}
} catch (Exception e) {
//...
}
}
}
Should I leave the lock only on the myObjects Set, or should I declare the whole parse() method as synchronized ?
Also, how should I synchronize - both - the setting of the csvFile and the parsing ? I feel like my actual design is broken because threads could modify the csv file several times while a possibly long parse process is running.
I hope I'm being clear enough, because myself am a bit confused on those multi-synchronization issues.
Thanks ;-)
Basically you are assuming methods need to setFile first and then call parser. Let us consider this,
t1 (with setFile XX) and t2 (with setFile YY) are coming at the same time and t2 set the file to be YY. Then t1 asks for parse() and starts getting records from YY. No amount of synchronised is going to solve this for you and the only way out is to have the parse method take a File parameter or remove the singleton constraint (so that each thread has its own file object). So use a
public void parse(File file) //and add synchronised if you want.
I think there are multiple issues which are there in this code.
If this class is a singleton, this class should be stateless i.e no state should be present in this class. therefore having setter for the file itself is not the right thing to do. Pass the file object into parse method and let it work on the argument. This should fix your issue of synchronizing across various methods
Though your myObjects Set is private, I am assuming you are not passing this to any other calling classes. In case you are, always return clone of this set to avoid callers making changes to original set.
Synchronized on the object is good enough if all your set changes are within the synchronized block.
Use separate MyParser object for every parse request and you will not have to deal with concurrency (at least not in MyParser). Also, then will you be able to truly service multiple users at a time, not forcing them to wait or erasing the results of previous parsing jobs.
The singleton thing is mostly a red herring. Nothing to do with concurrency issues you are considering. As far as synchronisation goes, I think you are ok. Making the method synchronized will also work despite the fact that myObjects is static because it is a singleton.

Static method in Java

Looking through some java code and this just does not seem right. To me, it looks like every time you call projects, you will get a new hashmap, so that this statement is always false
projects.get(soapFileName) != null
Seems like it should have a backing field
public static HashMap<String,WsdlProject> projects = new HashMap<String,WsdlProject>();
public Object[] argumentsFromCallSoapui(CallT call, Vector<String> soapuiFiles, HashMap theDPLs,int messageSize)
{
try {
for (String soapFileName:soapuiFiles){
System.out.println("Trying "+soapFileName);
WsdlProject project ;
if (projects.get(soapFileName) != null){
project = projects.get(soapFileName);
} else {
project = new WsdlProject(soapFileName);
projects.put(soapFileName,project);
}
}
} ...
}
Nope. In Java that static variable only gets initialized once.
So, this line will only get called once.
public static HashMap<String,WsdlProject> projects = new HashMap<String,WsdlProject> ();
The projects variable will be initialized once, when the class first loads.
Generally, static maps of this sort are a bad idea: they often turn into memory leaks, as you hold entries long past their useful life.
In this particular case, I'd also worry about thread safety. If you have multiple threads calling this method (which is likely in code dealing with web services), you'll need to synchronize access to the map or you could corrupt it.
And, in a general stylistic note, it's a good idea to define variables using the least restrictive class: in this case, the interface Map, rather than the concrete class HashMap.
You don't call projects - it's a field, not a method.
As it's a static field, it will be initialized exactly once (modulo the same type being loaded in multiple classloaders).
if you add a static initialiser (static constructor?) you'll be able to see that statics are just initialised the first time the class is loaded:
public class Hello {
static { System.out.println("Hello static World!"); }
...
}
You won't get a new HashMap every time you invoke a method on projects, if that's what you are referring to. A new HashMap will be created once, however all instances of the class will share a single HashMap.

Categories

Resources