I modified this code to do several tasks in one directory:
public class HDDSerialNumber
{
public void getHDDSerialNumber() throws IOException
{
try (DirectoryStream<Path> ds = Files.newDirectoryStream(Paths.get("/sys/block"), "sd*"))
{
// Get HDD Model
StreamSupport.stream(ds.spliterator(), false)
.map(p -> p.resolve("device/model")).flatMap(wrap(Files::lines))
.forEach(System.out::println);
// Get HDD Vendor
StreamSupport.stream(ds.spliterator(), false)
.map(p -> p.resolve("device/vendor")).flatMap(wrap(Files::lines))
.forEach(System.out::println);
// Get HDD Vendor
StreamSupport.stream(ds.spliterator(), false)
.map(p -> p.resolve("device/state")).flatMap(wrap(Files::lines))
.forEach(System.out::println);
}
}
static <T, R> Function<T, R> wrap(IOFunction<T, R> f)
{
return t ->
{
try
{
return f.apply(t);
}
catch (IOException ex)
{
throw new UncheckedIOException(ex);
}
};
}
interface IOFunction<T, R>
{
R apply(T in) throws IOException;
}
}
But when I run the code I get this error stack:
run:
ST320LT012-9WS14
Exception in thread "main" java.lang.IllegalStateException: Iterator already obtained
at sun.nio.fs.UnixDirectoryStream.iterator(UnixDirectoryStream.java:118)
at sun.nio.fs.UnixSecureDirectoryStream.iterator(UnixSecureDirectoryStream.java:73)
at java.lang.Iterable.spliterator(Iterable.java:101)
at hardware.HDDSerialNumber.getHDDSerialNumber(HDDSerialNumber.java:25)
at hardware.Hardware.main(Hardware.java:12)
Java Result: 1
Can you help me to fix the code, please? I suppose that Iterator already obtained must be used only once in this example but I don't have idea how to fix this.
While DirectoryStream extends Iterable, it is not a general-purpose Iterable as it supports only a single Iterator; invoking the iterator method to obtain a second or subsequent iterator throws IllegalStateException.
(Source)
The iterator of the Iterable returned by Files.newDirectoryStream (DirectoryStream implements Iterable) can only be used once. You can solve it by calling Files.newDirectoryStream separately for each of the 3 streams you are creating.
Instead of creating one DirectoryStream<Path> ds = Files.newDirectoryStream(Paths.get("/sys/block"), "sd*"); and using it in all 3 StreamSupport.stream calls, create 3 DirectoryStream<Path>.
Example :
public void getHDDSerialNumber() throws IOException
{
try (DirectoryStream<Path> ds = Files.newDirectoryStream(Paths.get("/sys/block"), "sd*"))
{
// Get HDD Model
StreamSupport.stream(ds.spliterator(), false)
.map(p -> p.resolve("device/model")).flatMap(wrap(Files::lines))
.forEach(System.out::println);
}
try (DirectoryStream<Path> ds = Files.newDirectoryStream(Paths.get("/sys/block"), "sd*"))
{
// Get HDD Vendor
StreamSupport.stream(ds.spliterator(), false)
.map(p -> p.resolve("device/vendor")).flatMap(wrap(Files::lines))
.forEach(System.out::println);
}
try (DirectoryStream<Path> ds = Files.newDirectoryStream(Paths.get("/sys/block"), "sd*"))
{
// Get HDD State
StreamSupport.stream(ds.spliterator(), false)
.map(p -> p.resolve("device/state")).flatMap(wrap(Files::lines))
.forEach(System.out::println);
}
}
EDIT :
If you want to handle the case of a file that doesn't exist without interrupting the program execution, catch the exception thrown in that case.
For example :
try (DirectoryStream<Path> ds = Files.newDirectoryStream(Paths.get("/sys/block"), "sd*"))
{
// Get HDD State
StreamSupport.stream(ds.spliterator(), false)
.map(p -> p.resolve("device/state"))
.flatMap(wrap(path - > try {
return Files.lines(path);
} catch (IOException ioEx) {
return Stream.empty();
}))
.forEach(System.out::println);
}
This would catch the exception and return an empty Stream.
Related
I have the code snippet below. But i was wondering how to try catch exception with method references. I want to write try catch block for getUserByUserId method, probably log it and catch with NotFoundException. How do i refactor this code in case of method reference userService::getUserByUserId?
List<String> listofIds= ldapUsers.stream()
.map(PersonDTO::getUserId)
.map(userService::getUserByUserId)
.filter(Optional::isPresent)
.map(Optional::get)
.map(User::get_id)
.collect(Collectors.toList());
You could write a mapper function in the class you are doing the chaining of calls:
private Optional<User> getUser(PersonDTO personDTO) {
try {
return userService.getUserByUserId(personDTO.getUserId());
} catch (Exception ex) {
log.error("Your message here", ex);
throw new NotFoundException();
}
}
And use it like this:
List<String> listofIds = ldapUsers.stream()
.map(PersonDTO::getUserId)
.map(this::getUser)
.filter(Optional::isPresent)
.map(Optional::get)
.map(User::get_id)
.collect(Collectors.toList());
Leave the stream like that add the logic you want in the getUserByUserId method. If it doesn't find a user it logs the error and throws the exception.
EDIT: since you can't modify the method, you can do the following:
List<String> listofIds= ldapUsers.stream()
.map(PersonDTO::getUserId)
.map(userId -> {
User user = userService.getUserByUserId(userId);
if(user == null) {
log.error("User not found");
throw new NotFoundException();
}
return user;
})
.filter(Optional::isPresent)
.map(Optional::get)
.map(User::get_id)
.collect(Collectors.toList());
If it's unchecked exception, you don't need to do anything. But if its checked exception then you can do something like this:
..
.map((userService) -> {
try{
...//call userService#getUserByUserId
}catch(NotFoundException e){
//log or do something else
}
}) ...
I want to handle the exception without using try catch clauses.
void test() {
list.stream().map(obj -> {
Batch batch = x.findByBatchId(obj.getBatchId())
/// exception is thrown here
.orElseThrow(() -> new ResourceNotFoundException(""));
if (obj.getBatchStatus() != null) {
batchHelper.updateBatchStatus(batch, obj.getBatchStatus());
}
});
}
You can't throw checked exception that way.
You can:
Throw RuntimeException and handle it later, maybe in another method, or don't handle it at all:
public void test() {
list.stream().map(obj -> {
Batch batch = x.findByBatchId(obj.getBatchId())
/// exception is thrown here
.orElseThrow(() -> new RuntimeException(""));
if (obj.getBatchStatus() != null) {
batchHelper.updateBatchStatus(batch, obj.getBatchStatus());
}
});
Use for statement and add your exception to method signature:
public void test() throws ResourceNotFoundException {
for (BatchInfo bi: list) {
.findByBatchId(bi.getBatchId()).orElseThrow(
() -> new ResourceNotFoundException(""));
}
It also depends on what you want to do in case of exception.
If you just want to let users know they do something wrong - use RuntimeException
If you want just update Batch status, use forEach, not map :
list.stream().forEach(obj -> {
Batch batch = x.findByBatchId(obj.getBatchId())
/// exception is thrown here
.orElseThrow(() -> new RuntimeException(""));
if (obj.getBatchStatus() != null) {
batchHelper.updateBatchStatus(batch, obj.getBatchStatus());
}
});
This question already has answers here:
Java 8 Lambda function that throws exception?
(27 answers)
Closed 3 years ago.
I have some code that throws a checked exception. I want to call that code within a lambda in order to create a map from another map:
Map<String, Coordinate> map = getMap();
Map<String, Integer> result = map.entrySet().stream().collect(
toMap(x -> x.getKey(), x -> doSomething(x.getValue)));
where doSometing is the code that throws the exception:
int doSomething(Coordinate c) throws MyException { ... }
Now compiler surely complains about the exception not being handled. So I surround it with a try-catch, which looks pretty ugly:
Map<String, Integer> result = map.entrySet().stream().collect(
toMap(x -> x.getKey(), x -> {
try {
return doSomething(x.getValue());
} catch (MyException e) {
e.printStackTrace();
// return some error-code here???
}
}));
which also does not compile as we need to return something in the catch-case. However there´s not much sense in returning anything here in this exceptional case, which is why I actually do not want to handle the exception at that level. Can´t I just handle the exception in my calling code, where I create the lambda? So to say just one level above?
try {
Map<String, Integer> result = ...
} catch (MyException e) { ... }
But that does not compile because the exception thrown from the lambda is not handled.
From Baeldung's blog: you could define consumer which can throw Exception:
#FunctionalInterface
public interface ThrowingConsumer<T, E extends Exception> {
void accept(T t) throws E;
}
and a static wrapper to map checked exception to RuntimeException:
static <T> Consumer<T> throwingConsumerWrapper(
ThrowingConsumer<T, Exception> throwingConsumer) {
return i -> {
try {
throwingConsumer.accept(i);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
};
}
Then you can call it:
Map<String, Integer> result = map.entrySet().stream()
.collect(
throwingConsumerWrapper(toMap(x -> x.getKey(), x -> doSomething(x.getValue)))
);
Fist of all it's worth to filter your values. In case if you have values which can raise an exception.
Then you can use one of the popular wrappers (i.e. jooq.lambda) or write your own
map.entrySet().stream()
.filter(x -> makeSureNoExtection(x))
.collect(toMap(x -> x.getKey(), unchecked(x -> doSomething(x.getValue))));
I'm currently working on a frontend for visualizing the results out ouf some searches in foreign systems. At the moment the programm is asking one system by another and only continues, when alle foreign systems have answered.
The frontend is written in Vaadin 13 and this should be able to refresh the page by push.
I have six controller classes for six foreign systems to question and want to start all questions at the same time without having to wait for the privious controller to finish.
My problem is that I can't find a tutorial which helps me with this special problem. All tutorials are about starting the same process for more than once but at the same time.
This is how I start the searches at the moment:
public static void performSingleSearch(ReferenceSystem referenceSystem, String searchField, List<String> searchValues, SystemStage systemStage) throws Exception {
if(!isAvailable(referenceSystem, systemStage)) return;
Map<String, ReferenceElement> result = new HashMap<>();
try {
Class<?> classTemp = Class.forName(referenceSystem.getClassname());
Method method = classTemp.getMethod("searchElements", String.class , List.class, SystemStage.class);
result = (Map<String, ReferenceElement>) method.invoke(classTemp.newInstance(), searchField, searchValues, systemStage);
} catch (Exception e) {
return;
}
if(result != null) orderResults(result, referenceSystem);
}
I hope you can provide me an tutorial on how to, or better a book over multithreading.
Best regards
Daniel
Seems to me the simplest approach is using CompletableFuture. Ignoring your atrocious use of reflection, I'm going to assume
interface ReferenceSystem {
public Map<String,ReferenceElement> searchElements(List<String> args);
}
List<ReferenceSystem> systems = getSystems();
List<String> searchArguments = getSearchArguments();
so you can do
List<CompletableFuture<Map<String, ReferenceElement>>> futures = new ArrayList<>();
for (ReferenceSystem system : systems) {
futures.add(CompletableFuture.supplyAsync(() -> system.searchElements(searchArguments)));
}
or with Java 8 Streams
List<CompletableFuture<Map<String, ReferenceElement>>> futures =
systems.stream()
.map(s -> CompletableFuture.supplyAsync(
() -> system.searchElements(searchArguments)))
.collect(Collectors.toList());
Now the futures contains a list of futures which will eventually return the Map you're looking for; you can access them with #get() which will block until the result is present:
for (CompletableFuture<Map<String,ReferenceElement>> future : futures) {
System.out.printf("got a result: %s%n", future.get());
}
With your primitive case all you would need is either list of threads and just wait on them to finish or even easier, use thread pool and use that:
private static ExecutorService service = Executors.newFixedThreadPool(6); // change to whatever you want
public static void someMethod() {
queueActions(Arrays.asList(
() -> {
try {
performSingleSearch(null, null, null, null); // fill your data
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
},
() -> {
try {
performSingleSearch(null, null, null, null); // fill your data #2 etc
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
));
}
public static void queueActions(List<Runnable> actions) {
Semaphore wait = new Semaphore((-actions.size()) + 1);
for (Runnable action : actions) {
service.execute(() -> {
try {
action.run();
} finally {
wait.release();
}
});
}
try {
wait.acquire();
} catch (InterruptedException e) {
}
}
The question remains whether you want to orders be executed at the same time or one at a time or something else (join orders into one big order etc).
Let's say I have the following method I want to refactor
protected Stream<T> parseFile(File file, Consumer<File> cleanup) {
try {
return parser.parse(file); // returns a Stream<T>
} catch (XmlParseException e) { // child of RuntimeException
throw new CustomRuntimeException(e);
} finally {
if (file != null) {
cleanup.accept(file);
}
}
throw new IllegalStateException("Should not happen");
}
This method's purpose is to act as a proxy attaching error handling on the stream rethrowing in a wrapping exception CustomRuntimeException. So when we consume it later in the flow, I don't have to handle those exceptions everywhere but only CustomRuntimeException.
Upstream, I used that method as follow
try {
Stream<T> stream = parseFile(someFile);
stream.map(t -> ...);
catch (CustomRuntimeException e) {
// do some stuff
}
And here's what the parser.parse method looks like
public Stream<T> parse() {
// ValueIterator<T> implements Iterator<T>, AutoCloseable
XmlRootParser.ValueIterator<T> valueIterator = new XmlRootParser.ValueIterator(this.nodeConverter, this.reader, this.nodeLocalName, this.nodeName);
Stream<T> stream = StreamSupport.stream(Spliterators.spliteratorUnknownSize(valueIterator, 1040), false);
stream.onClose(valueIterator::close);
return stream;
}
The exceptions I want to handle will be thrown by the ValueIterator.hasNext method. Which means they won't be thrown at Stream creation but only at Stream consumption (calling foreach/map/count/collect/... on the stream).
How do I attach error handling on my stream in method parseFile nicely without having to consume the stream? Is it possible?
Obviously this code will work only if the parser.parse method consume its stream before returning it. Which is against using streams.
The Stream’s backend which provides the iterator logic, is the Spliterator.
So you can wrap the element processing using a wrapper Spliterator like this:
class Wrapper<T> implements Spliterator<T> {
final Spliterator<T> source;
public Wrapper(Spliterator<T> source) {
this.source = source;
}
#Override
public boolean tryAdvance(Consumer<? super T> action) {
try {
return source.tryAdvance(action);
}
catch(XmlParseException ex) {
throw new CustomRuntimeException(ex);
}
}
#Override
public void forEachRemaining(Consumer<? super T> action) {
try {
source.forEachRemaining(action);
}
catch(XmlParseException ex) {
throw new CustomRuntimeException(ex);
}
}
#Override public Spliterator<T> trySplit() {
Spliterator<T> srcPrefix = source.trySplit();
return srcPrefix == null? null: new Wrapper<>(srcPrefix);
}
#Override public long estimateSize() { return source.estimateSize(); }
#Override public int characteristics() { return source.characteristics(); }
#Override public Comparator<? super T> getComparator(){return source.getComparator();}
}
It retains all properties of the original Spliterator and only translates exceptions thrown during the iteration.
Then you can use it like
protected Stream<T> parseFile(File file) {
Stream<T> s = parser.parse();
return StreamSupport.stream(new Wrapper<>(s.spliterator()), s.isParallel())
.onClose(s::close);
}
And the caller should not forget to close the stream properly:
ResultType result;
try(Stream<T> s = parseFile(file)) {
result = s.
// other intermediate ops
// terminal operation
}
or
ResultType result;
try(Stream<T> s = parseFile(file)) {
result = s.
// other intermediate ops
// terminal operation
}
finally {
// other cleanup actions
}
You could use helper stream initialization class that handles the process of preparing stream and catch any exception there. Consider following example:
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class SafeInitializationStreamExample {
public static void main(String[] args) {
int sum = SafeInitializationStream.from(() -> Stream.of(1,2,3,4))
.onInitializationError(t -> System.out.println(t.getMessage()))
.mapToInt(it -> it)
.sum();
System.out.println(sum);
List<Object> list = SafeInitializationStream.from(() -> parse("/tmp/test.log"))
.onInitializationError(t -> System.out.println(t.getMessage()))
.map(it -> it.toString())
.collect(Collectors.toList());
System.out.println(list);
}
private static <T> Stream<T> parse(String filename) {
throw new RuntimeException("File does not exist!");
}
static class SafeInitializationStream<T> {
private final Supplier<Stream<T>> streamSupplier;
private SafeInitializationStream(Supplier<Stream<T>> streamSupplier) {
this.streamSupplier = streamSupplier;
}
public static <T> SafeInitializationStream<T> from(Supplier<Stream<T>> streamSupplier) {
return new SafeInitializationStream<>(streamSupplier);
}
public Stream<T> onInitializationError(Consumer<Throwable> onError) {
try {
return streamSupplier.get();
} catch (Exception e) {
onError.accept(e);
}
return Stream.empty();
}
}
}
In this example we introduce SafeInitializationStream class which expects a Supplier<Stream<T>>:
SafeInitializationStream.from(() -> Stream.of(1,2,3,4))
Using Supplier<Stream<T>> in this case makes stream initialization lazy - until we call Supplier.get() the body of this supplier is not executed. Now, when we call:
.onInitializationError(t -> System.out.println(t.getMessage()))
we execute suppliers body, catch any exception that may be thrown and handle this exception by passing Throwable to Consumer<Throwable> that was passed as a parameter to onInitializationError method. In case of exception Stream.empty() is returned (so you can safely apply all other transformations in chain. When there is no exception, Stream<T> provided by supplier is returned.
If you run following example you will get in console:
10
File does not exist!
[]
The first stream was consumed without any errors and the sum was returned correctly.
The second stream thrown exception during initialization, we have caught it and printed to the console and finally empty list was returned after consuming the stream.
Of course you can use Function<Throwable, Stream<T>> in onInitializationError method if you want to specify what Stream<T> is returned in case of an exception. In this case we assume that Stream.empty() is always returned in this case. Hope it helps.