Java: reading from File folder and adding each to ArrayList - java

Consider this piece of code:
private static ArrayList<Level> levels = new ArrayList<>();
static {
try (Stream<Path> paths = Files.walk(Paths.get("levels"))) {
paths
.filter(Files::isRegularFile)
.forEach(levels.add(new Level(file))); //CAN'T DO!!
} catch (IOException e) {
e.printStackTrace();
}
}
I think the code pretty much says what I'm trying to do. I found this piece of code somewhere and I tried to apply it, to create Level objects from folder with files such as level1.txt, level2.txt, etc. The Level class takes a File as argument.
The forEach method gives out a SyntaxError.
What are the "::" in the filter method?
Why is the path, fallowed by a new line and 2 methods? Never seen such a thing before.
How can I make this work properly?

The following explains well what is :: (double colon) operator since Java 8
Code can be run written on several lines, but this is same as the following. Your calling the method filter then calling forEach on the object returned by filter
paths.filter(Files::isRegularFile).forEach(levels.add(new Level(file)));
Get it work, you need to define file variable this is done with lambda functions
paths.filter(Files::isRegularFile).forEach(file -> levels.add(new Level(file)));
NOT POSSIBLE because walks() throws IOException
In case you don't need the try/catch you can use Collectors to directly build the list
private static ArrayList<Level> levels = Files.walk(Paths.get("levels"))
.filter(Files::isRegularFile)
.map(file -> new Level(file))
.collect(Collectors.toList());

Related

Background of "resource leak: stream is never closed"

Given a Java function which uses a stream:
List<String> function(List<String> input) {
Stream<String> a = input.parallelStream();
Stream<String> b = a.map(c -> c.toString());
return b.collect(Collectors.toList());
}
Now, I want to control whether the mapping is performed by a parameter. Eclipse/the compiler gives me a warning: Resource leak: 'a' is never closed
List<String> function(List<String> input, boolean doMap) {
Stream<String> a = input.parallelStream(); // Resource leak: 'a' is never closed
Stream<String> b = doMap ? a.map(c -> c.toString()) : a;
return b.collect(Collectors.toList());
}
I can work around this with a try-with-resources statement:
List<String> function(List<String> input, boolean doMap) {
try (Stream<String> a = input.parallelStream()) {
Stream<String> b = doMap ? a.map(c -> c.toString()) : a;
return b.collect(Collectors.toList());
}
}
My question is: Why can there be resource leaks at all when I work with streams instead of for-loops? Why is there a resource leak if I only optionally add the mapping step? (Why isn’t there a resource leak in the first version of the function?) Is it “dangerous” to compose processing streams conditionally? What am I missing?
I summarize #Nikolas answer again in other words: There is no problem in Java, but the “problem” (if you want to call it that at all) is the variable. If a variable is declared to a type that implements AutoCloseable (and Stream does), Eclipse apparently reports a warning here that it is not being closed, if it does not find a call to close().
Since this error is Eclipse-related, it is likely that other checking tools will not fail on this and does not need to be “fixed” to pass such checks.
To my understanding, this shows a basic problem of Java, namely that it does not release the object on a variable as soon as it is no longer needed, but at some random point. With resources, that fails. Therefore, resources have to be tracked manually by the developer, where to close them, and manually to be closed. The Java runtime would (hypothetically) have to implement an approach like C++’s std::auto_ptr, then this would not be necessary and if the last reference to the resource was deleted, this could be closed. But it's not like java "thinks".

Add Arraylists together created by a method call

I know that there are a few question already in this forum relating to my question, but none of them really seems the help me.
Since I am new to Coding I am still trying to figure out what exactly getClass() and getMethod() calls help me with.
What I want to accomplish:
// init:
List<Preview> listPreview;
List<Preview> listTemp;
// now create the Lists (from a Database)
listPreview = dbHelper.getPreview("Hero", "Axe");
listTemp = dbHelper.getPreview("Hero", "Beastmaster");
// now I want to add ListTemp to ListPreview
Class myClass = listPreview.getClass();
Method m = myClass.getDeclaredMethod("add", new Class[] {Object.class});
m.invoke(listTemp, 2);
The Problem:
Obviously this is not working right now, but I think the idea is pretty straight forward. I want to add listTemp to listPreview. The getDeclaredMethod is already considered a undeclared exception I do not really understand why.
If you want to add two list one after another just use this:
listPreview.addAll(listTemp);
This is relatively simple. Why don't you use listPreview.addAll(listTemp);. This will add all the elements in listTemp to listPreview.
If you want to add the elements of List with your approach, use the below code.
Class myClass = listPreview.getClass();
Method m = myClass.getDeclaredMethod("addAll", Collection.class);
m.invoke(listPreview, listTemp);
OR
For a simpler way, you can use
listPreview.addAll(listTemp);
The error is
getDeclaredMethod is already considered a undeclared exception
Which means there are unreporteds exception must be caught or declared to be thrown.
so below is a complete sample:
try {
Class myClass = listPreview.getClass();
Method m = myClass.getDeclaredMethod("addAll", Collection.class);
m.invoke(listPreview, listTemp);
}
catch (Throwable e) {
System.err.println(e);
}

Iterate over certain subpaths in Path in Java

I am working with code which makes use of java.nio.file.Path. I have a path like
/tmp/something/first/second/third/last
which I see only as
{parent.dir}/first/second/third/{path.end}
In this example /tmp/something or {parent.dir} is a path which can be different during runtime and which is irrelevant for me. The same applies for the last element in the path {path.end}
What I would need is to iterate over elements between {parent.dir} and {path.end}. Basically to test each element in the path if it exists and if it is a file or
a directory or something else (it doesn't matter).
I am therefore looking for some elegant/simple and proper way to iterate over instance of Pathwhere I can access paths like these:
/tmp
/tmp/something/
/tmp/something/first
...
/tmp/something/first/second/third/last
ideally in this case without the first 2 and the last iteration.
I am looking for a good solution using Path and java.nio and not the old way. I know I can achieve this using old io API but I am interested in the proper way of using nio.
Here I print all directories child of your parent dir:
Files.walk(Paths.get(${parent.dir})).filter(path -> Files.isDirectory(path, LinkOption.NOFOLLOW_LINKS)).forEach(System.out::println);
You can pass another lambda to the forEach method for your own purpose.
Also replace ${parent.dir} with your correct value as a String.
(The code above may throw IOException).
Assuming that the base and end parts are parameters, while the in-between part is fixed, a solution can look like this:
static void iterate(Path base, Path end) {
if(!base.isAbsolute() || end.isAbsolute()) throw new
IllegalArgumentException("base must be absolute, end must be relative");
// test the fixed in-between paths
Path fixed=Paths.get("first", "second", "third");
for(Path part: fixed) {
base=base.resolve(part);
System.out.print(base);
if(Files.isDirectory(base)) {
System.out.println(" is a directory");
}
else {
System.out.println(Files.exists(part)?" is not a directory":" does not exist");
return;
}
}
// test the end path
end=base.resolve(end);
System.out.print(end+(
Files.isDirectory(end)? " is a directory":
Files.exists(end)? " is not a directory": " does not exist"));
}
It stops the iteration once it encounters a non-directory path component. You will have to adapt this behavior if you want to enforce a specific policy regarding following symbolic links…

RxJava operators

I'm learn rxjava using this article: http://blog.danlew.net/2014/09/22/grokking-rxjava-part-2/
and can't reproduce first example of this article
I did next:
Observable<List<String>> query(String text); //Gradle: error: missing method body, or declare abstract
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
query.subscribe(urls -> { //Gradle: error: cannot find symbol variable query
for (String url : urls) {
System.out.println(url);
}
});
}
But I have an errors, which I added as comments
What I did wrong?
Java 8 lambdas aside, most of the people here are missing the fact that your code won't compile regardless RetroLambda or any other nifty tool that you find somewhere to work around the missed lambda feature in Android...
So, take a close look to your code, you even had added some comments to the snippet which are actually explaining you why you are having some compilation errors:
1 You have a method with an empty body:
Observable<List<String>> query(String text);
So, add a method body to it and problem solved. What do you want to do? You don't know yet? Then add a dummy or empty body and work that out later:
Observable<List<String>> query(String text) {
return Observable.just(Arrays.asList("url1", "url2"));
}
2 There is no query variable at all in your code. What you've got is a query method, and the syntax to use methods requires you to use braces:
query("whatever").subscribe(urls -> {
for (String url : urls) {
System.out.println(url);
}
});
Now add the RetroLambda or use anonymous classes and you are done. Bear in mind that nothing out of this will add much functionality to your code but will solve just those compilation errors. Now ask yourself what do you want to do in your query method and carry on.
Note: An Observable object is a stream of data, which basically means that you might get zero elements, one element, or many; all of them instances of the specified type. So your code seems to expect a stream of lists of strings, if what you really want is a stream of strings, then replace Observable<List<String>> for Observable<String>.
By Gradle: error: you mean compilation error? You should probably put parentheses between query and .subscribe(urls -> { as this is not a variable or class filed but method instead, so you should call it to get Observable to subscribe to.
Well, also you need to implement query method to return Observable, for example like this:
private Observable<String> query() {
return Observable.just("one", "two", "three");
}
You'll get another build error because of Java 8 but as already mentioned in comments you can easily use retrolamda with gradle to fix the problem. Otherwise you can use Android Studio quick fixes to convert java 8 lambdas into java 6 anonymous classes.

JEditorPane - setText from ArrayList<String> contents?

I have read through the JEditorPane Docs, from what I can understand you simply need to editorpane.setText(String value); however I am quite new to java and this solution does not work with my code. I think I am missing something obvious but completely out of ideas.
I have created a new tab with this class that extends JEditorPane, this class is designed to open the contents of the file, put them on an array, reverse the array (so latest entry is on the top) then display this list in the JEditorPane (using JeditorPane because I need to make the save url's into hyperlinks),
public class HistoryPane extends JEditorPane{
ArrayList<String> historyToSort = new ArrayList<String>();
public HistoryPane(){
setEditable(false);
historySort();
}
public void historySort() {
try (BufferedReader reader = new BufferedReader(new FileReader("BrowserHistory.txt")))
{
String currentLine;
String newLine = new String("\n");
while ((currentLine = reader.readLine()) != null) {
historyToSort.add(currentLine + newLine);
}
} catch (IOException e) {
e.printStackTrace();
}
Collections.reverse(historyToSort);
System.out.println(historyToSort);
}
{
}
private void displayHistory(){
String sorted = historyToSort.toString();
***** HistoryPane.setText(String sorted); <<<------ PROBLEM SYNTAX.*****
}
}
I have tried multiple different entries into the setText() parenthesis with no luck. What am I missing? Thank You.
NOTE:
This class won't compile because it is reliant on another class (I can't paste all of it) but this code sits within a tabbed pane created by my main class:
Error Message:
Exception in thread "AWT-EventQueue-0" java.lang.Error: Unresolved compilation problems:
Syntax error on token "setText", Identifier expected after this token
Return type for the method is missing
This method requires a body instead of a semicolon
OK, despite the fact that you haven't read the error message, it seems you're really a newbie, so I'll help.
HistoryPane.setText(String sorted);
The above isn't valid Java. A method invocation takes a list of arguments, without a type.
HistoryPane.setText(sorted);
Now that is a valid method invocation. But it tries to invoke a static method called setText() of the class HistoryPane. What you want is to invoke the instance method setText() on the current object. So the valid syntax is
this.setText(sorted);
or simply
setText(sorted);
That should solve this particular compilation error. Don't try to run your app before every compilation error, listed in the Problems view of Eclipse, is fixed.
Note that the above line won't do what you want it to do, but I'll let you investigate what you should do instead.
My advice: don't try using Swing, which is quite a complex beast, if you don't even know how to call a method yet. Start with very simple Java exercises, not involving any GUI, until you're familiar with the Java syntax, and understand how to read, understand and fix basic compilation problems.

Categories

Resources