I'm looking for a way to pass a code block to a method, which will then perform actions on other arguments passed to method, take the results of those actions, and pass those results to the code block passed to the method. For clarity:
private static void method1(String filename, int sheetNum) {
runOnSheet(filename, () -> {
doStuffWithStream(FileInputStream fileStream); // Does something with a file stream
doOtherStuffWithStream(FileInputStream fileStream); // Does something else with a file stream
});
}
// Elsewhere
private static void runOnFile(String fileName, Runnable block1) {
try {
fileStream = new FileInputStream(fileName);
} catch (IOException e) {
e.printStackTrace();
}
block1.run(); // I'd like to pass fileStream to this code block. Ideally i could do block1.run(fileStream );
fileStream.close();
}
I want to be able to reuse runOnFile anywhere I need to open a file, run some code on the stream, and close the stream.
What I actually want to do is more complicated, and uses other libraries in addition to FileInputStream, but the structure of what I wish to accomplish is the same.
Thanks for any help!
Java 8+ has a Class called Consumer that can be used for your usecase:
https://docs.oracle.com/javase/8/docs/api/java/util/function/Consumer.html
private static void method1(String filename, int sheetNum) {
runOnFile(filename, (fileStream) -> {
doStuffWithStream(fileStream);
doOtherStuffWithStream(fileStream);
});
}
// Elsewhere
private static void runOnFile(String fileName, Consumer<FileInputStream> block1) {
try {
fileStream = new FileInputStream(fileName);
} catch (IOException e) {
e.printStackTrace();
}
block1.accept(fileStrean);
fileStream.close();
}
EDIT: As suggested by Dimitri using the try-with-resource syntax:
// Elsewhere
private static void runOnFile(String fileName, Consumer<FileInputStream> block1) {
try (FileInputStream fis = new FileInputStream(fileName)) {
block1.accept(fis);
} catch (IOException e) {
e.printStackTrace();
}
}
Try something like this:
private static void method1(String filename, int sheetNum)
{
try ( final FileInputStream fileStream = new FileInputStream(filename))
{
runOnSheet(filename, () ->
{
doStuffWithStream(fileStream); // Does something with a file stream
doOtherStuffWithStream(fileStream); // Does something else with a file stream
});
}
}
Related
I have PVPStats objects stored in PlayerMeta.java:
public static Map <UUID, PVPstats> sPVPStats = new HashMap<>();
I know for sure the map is getting populated with objects that contain the expected vars for each uuid.
I'm trying to write these objects (converted to single lines of strings) into plugins/core/killstats.txt when the server calls onDisable() in Main.java
Along with the Map object, in PlayerMeta.java are also the methods to update and retrieve PVPStats objects from the Map. Those are all working.
The part that is not is working is the write method:
public static void writePVPStats() throws IOException {
BufferedWriter w = new BufferedWriter(new FileWriter("plugins/core/killstats.txt"));
sPVPStats.keySet().forEach(user -> {
try {
System.out.println(sPVPStats);
// stdout = {a6b6e3a1-a1ec-4fee-9d6d-f5e495c3e9d7=a6b6e3a1-a1ec-4fee-9d6d-f5e495c3e9d7:1:0}
w.write(user.toString() + "\n");
w.flush();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
});
w.close();
}
kill.txt after onDisable() is done:
a6b6e3a1-a1ec-4fee-9d6d-f5e495c3e9d7
Instead it needs to be:
{a6b6e3a1-a1ec-4fee-9d6d-f5e495c3e9d7=a6b6e3a1-a1ec-4fee-9d6d-f5e495c3e9d7:1:0}
For reference, here is the complete PVPStats class.
Lastly, in case it matters / helps, the reader on server launch:
Files.readAllLines(killstats_user_database.toPath()).forEach(line -> {
PVPstats stats = PVPstats.fromString(line);
PlayerMeta.sPVPStats.put(stats.playerid, stats);
});
Source Code:
backend.FileManager.java
backend.PlayerMeta.java
backend.PVPstats.java
events.PVP.java
EDIT
I just tried this with killstats.txt file type nad killstats.txt doesnt have anything in it now.
public static void writePVPStats() throws IOException {
BufferedWriter w = new BufferedWriter(new FileWriter("plugins/core/killstats.txt"));
for (PVPstats object: sPVPStats.values()) {
try {
System.out.println(sPVPStats);
w.write(object.toString() + "\n");
w.flush();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
};
w.close();
}
Ok so there were multiple issues. I wasn't controlling the flushing of the buffer, I declared the hasmap incorrectly, I wasn't accessing the value part of the hash map, and I wasn't correctly enforcing plain text.
SOLUTION
public static Map <UUID, PVPstats> sPVPStats = new HashMap<UUID, PVPstats>();
public static void writePVPStats() throws IOException {
BufferedWriter w = new BufferedWriter(new FileWriter("plugins/core/killstats.txt"));
for (PVPstats object: sPVPStats.values()) {
try {
System.out.println(sPVPStats);
System.out.println(object.toString());
w.write(object.toString() + "\n");
w.flush();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
};
w.close();
}
I have a class method that logs output to a file and I want more control over format specifying.
public class Logger {
private static boolean FIRST_CALL = true;
public static void log(String content) {
try {
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("debug.txt", !FIRST_CALL)));
if(FIRST_CALL) {
FIRST_CALL = false;
}
out.println(content);
out.close();
} catch (IOException e) {
//exception handling left as an exercise for the reader
}
}
}
I'm not sure how to go about it. changing println to printf creates a whole host of problems.
E.g I call the method as follows:
Logger.log("testval=" + testVal);
Where testVal would be a double for example. It would output 1.9547E-5 but I actually want it in decimal format instead.
Any help appreciated. I'm new to Java.
Take a look at the MessageFormat class.
You can do something like
Logger.log(MessageFormat.format("testval={0}", testVal));
Like printf you can configure the format of your output. See the Javadoc for all the options.
You can use String.format().
In your example:
Logger.log(String.format("testval=%f", testVal));
Well, if to fix your code for a double, I'd write in this way:
private void log(double )
{
// use try-with-resource - it's better
try(PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("debug.txt", !FIRST_CALL))))
{
if(FIRST_CALL) {
FIRST_CALL = false;
}
out.printf("value = %5.7f\n", d);
out.close();
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
and call this code:
log(1.9547E-5)
the following code is incomplete but the main focus of my question is on the method processConfig() anyway. It reads the properties out of a file and I want to handover these properties to the method replaceID(). It worked already when the content of processConfig was in the main()-method. But now I wanted to put this code into it´s own method. What is the best way of handing over the properties (which I saved in Strings like difFilePath). I´m not that familiar with OO-programming and want to understand the concept. Thanks for your help.
public class IDUpdater {
....
public static void main(String[] args) throws Exception {
//Here I want to call the variables from processConfig() to make them available for replaceID(...)
replaceID(difFilePath, outputDifPath, encoding);
}
public static void replaceID(String difFilePath, String outputDifPath, String encoding) throws Exception{
return record;
}
public void processConfig(){
Properties prop = new Properties();
InputStream input = null;
try {
input = new FileInputStream("config.properties");
} catch (Exception e) {
logger.error("File 'config.properties' could not be found.");
}
try {
prop.load(input);
} catch (Exception e) {
logger.error("Properties file could not be loaded.");
}
String difFilePath = prop.getProperty("dif_file_path");
String outputDifPath = prop.getProperty("output_dif_path");
String encoding = prop.getProperty("encoding");
}
}
You've to declare your variables globally. This way they can be accessed in each method. After you've declared them globally you first call your processConfig in your main method, which will set your variables to what they should be.
public class IDUpdater {
private String difFilePath;
private String outputDifPath;
private String encoding;
public void main(String[] args) throws Exception {
processConfig();
replaceID();
}
public void replaceID() throws Exception{
// You can use your variables here.
return record;
}
public void processConfig(){
Properties prop = new Properties();
InputStream input = null;
try {
input = new FileInputStream("config.properties");
} catch (Exception e) {
logger.error("File 'config.properties' could not be found.");
}
try {
prop.load(input);
} catch (Exception e) {
logger.error("Properties file could not be loaded.");
}
difFilePath = prop.getProperty("dif_file_path");
outputDifPath = prop.getProperty("output_dif_path");
encoding = prop.getProperty("encoding");
}
}
Note that I declared the variables privately. For more information about protecting your variables see https://msdn.microsoft.com/en-us/library/ba0a1yw2.aspx.
You may want to read an article (or even better yet - a book) on topic of encapsulation and objects. This or this may be a good starting point for you. There is no point in anyone fixing your code, if you don't understand the concepts behind it.
Consider the following test code.
I am trying to find out if I can use piped streams like "normal" I/O streams, together with the commonly used Reader and Writer implementations (specifically, another part of the code base I am working on demands that I use OutputStreamWriter).
The problem here is that nothing appears to show up on the read end. The program at least appears to correctly write the message to the write-end of the pipe, but when trying to read from the other end I block indefinetly, or if I (as in this case) check for available bytes, the call returns 0.
What am I doing wrong?
public class PipeTest {
private InputStream input;
private OutputStream output;
public PipeTest() throws IOException {
input = new PipedInputStream();
output = new PipedOutputStream((PipedInputStream)input);
}
public void start() {
Stuff1 stuff1 = new Stuff1(input);
Stuff2 stuff2 = new Stuff2(output);
Thread thread = new Thread(stuff1);
thread.start();
Thread thread2 = new Thread(stuff2);
thread2.start();
}
public static void main(String[] args) throws IOException {
new PipeTest().start();
}
private static class Stuff1 implements Runnable {
InputStream inputStream;
public Stuff1(InputStream inputStream) {
this.inputStream = inputStream;
}
#Override
public void run() {
String message;
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
try {
//message = reader.readLine();
System.out.println("Got message!");
System.out.println(inputStream.available());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private static class Stuff2 implements Runnable {
OutputStream outputStream;
public Stuff2(OutputStream outputStream) {
this.outputStream = outputStream;
}
#Override
public void run() {
String message = "Hej!!\n";
OutputStreamWriter writer = new OutputStreamWriter(outputStream);
try {
writer.write(message);
System.out.println("Wrote message!");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
As you are never reading from the read end, it is impossible to see how you could possibly arrive at that conclusion, and any such conclusion is therefore baseless and invalid.
All you are doing is printing available() at an arbitrary point in time, which isn't sufficient to prove that nothing ever shows up at the read end.
I'm trying to read ObjectOutputStream from a file and convert it to an arraylist.
This whole thing is happening inside a method which should read the file and return the array list:
public static List<Building> readFromDatabase(){
String fileName="database.txt";
FileInputStream fileIStream=null;
ObjectInputStream in=null;
List<Building> buildingsArr=null;
try
{
fileIStream = new FileInputStream(fileName);
in = new ObjectInputStream(fileIStream);
buildingsArr=(ArrayList<Building>)in.readObject();
}
catch(IOException e)
{
e.printStackTrace();
}
catch(ClassNotFoundException e)
{
Console.printPrompt("ArrayList<Building> class not found.");
e.printStackTrace();
}
finally{
Console.printPrompt("Closing file...");
close(in);
close(fileIStream);
return buildingsArr;
}
}
Java tells me that this is dangerous.
What are the alternatives?
I can't put the return in the "try" block because it won't do it / it won't close files in the "finally" block.
I need to both make sure files will be closed, and return the array list I created as well.
Any ideas?
I can't put the return in the "try" block because it won't do it / it
won't close files in the "finally" block.
Wrong, finally block would still execute if you put return in try block. Thus you can return in your try block.
try
{
//your code
return buildingsArr;
}
catch(IOException e)
{
e.printStackTrace();
}
catch(ClassNotFoundException e)
{
Console.printPrompt("ArrayList<Building> class not found.");
e.printStackTrace();
}
finally{
Console.printPrompt("Closing file...");
close(in);
close(fileIStream);
}
I would suggest starting to use Java 7, and the try with resources clause. http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html
Ex:
static String readFirstLineFromFile(String path) throws IOException {
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
return br.readLine();
}
}
You must either throw an Exception or return a value:
All you need to prove this is comment out the return "File Not Found" after the finally block and see that it won't compile.
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class ReturnFinallyExample
{
public static void main(final String[] args)
{
returnFinally();
}
private static String returnFinally()
{
try
{
final File f = new File("that_does_not_exist!");
final FileInputStream fis = new FileInputStream(f);
return "File Found!";
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
finally
{
System.out.println("finally!");
}
return "File Not Found!";
}
}
You must have the return after the finally or you have to either:
declare the method to throws FileNotFoundExceptoin and re-throw the FileNotException out.
or
wrap the FileNotFoundException with throw new RuntimeException(e)