I have a string:
"1, 2, 3 , -4"
it is split by ", ".
I have a function to convert a number to a enum type which works fine. I want to use java 8 to convert this string to a list of enum objects.
Pattern pattern = Pattern.compile(", ");
List<f> fList = pattern.splitAsStream(str)
.map(s -> {
try {
return this.getEnumObject(Integer.valueOf(s), f.class);
}
catch (NoEleException e) {
e.printStackTrace();
}
})
.collect(Collectors.toList());
This gives me an error:
missing return type.
How could I fix it?
Currently, if an exception occurs no result will be returned hence the compilation error. You'll need to return a value after the catch block .
Basically to ways of managing this:
catching the exception and return some value or encapsulate values in Optionals and filter accordingly
Throwing a RuntimeException which chains the original one
In the first case we use Optional to put something into the stream on error, and then manage these empty values further in the stream:
pattern.splitAsStream(str)
.map(s -> {
try {
return Optional.of(this.getEnumObject(Integer.valueOf(s), f.class));
}
catch (NoEleException e) {
e.printStackTrace();
return Optional.empty();
}
})
.filter(Optional::isPresent) // remove empty optionals
.map(Optional::get) // unwrap them
.collect(Collectors.toList());
In the second case the stream is stopped and you can then try to catch the RuntimeException and unchain the original one:
pattern.splitAsStream(str)
.map(s -> {
try {
return Optional.of(this.getEnumObject(Integer.valueOf(s), f.class));
}
catch (NoEleException e) {
e.printStackTrace();
throw new RuntimeException(e); // stop the stream
}
})
.collect(Collectors.toList());
You can create Null Object like MissingElement, return it in catch and them filter it out after map.
If you are certain that this won't happen you could return null in the catch and filter for non null before collecting:
Pattern pattern = Pattern.compile(", ");
List<f> fList = pattern.splitAsStream(str)
.map(s -> {
try {
return this.getEnumObject(Integer.valueOf(s), f.class);
}
catch (Exception e) {
return null;
}
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
Related
I have a stream like this,
List<String> test = Arrays.asList("1", "2,", "3");
test.stream().map(t -> {
try {
validate(t);
} catch (Exception e) {
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage(), e);
}
return true;
})
In case of an exception, I would like to store it somewhere, process the next element and then show all exceptions at once. Is this possible?
Well, don't rethrow the exception:
var exceptions = test.stream().map(t -> {
try {
validate(t);
} catch (Exception e) {
return e;
}
return null;
})
.filter(Objects::nonNull) // if you don't need to preserve the index
.toList();
I modified your code slightly. Your main issue is that you're re-throwing that exception when you catch it -- that will stop processing at the first exception. Then you need some way to store the inputs that cause an error (that's what invalidInputs is for. I'm assuming that your next step is to actually use the results of that input to convert, otherwise you don't need to use map(), so my "validate" method also just does the conversion too. I use a JUnit test harness for stuff like this, and I left in the assert()s; you should take them (and the #Test annotation) out for your code.
//throws NumberFormatException if input doesn't parse into an integer
public static Integer validate(String input) throws Exception{
return Integer.parseInt(input);
}
#Test
public void testStreamMap() {
List<String> test = Arrays.asList("1", "2,", "3");
List<String> invalidInputs = new ArrayList<>();
List<Integer> result= test.stream().map(t -> {
Integer localResult;
try {
localResult=validate(t);
} catch (Exception e) {
invalidInputs.add(t);
localResult=null;
}
return localResult;
}).collect(Collectors.toList());
assertTrue(invalidInputs.contains("2,"));
assertFalse(result.contains(2));
}
You can try this approach to collect all the exceptions in a list as follows:
Here,
I have iterated over the list using forEach and in case of catch , added the exception e in the listOfExceptions list.
As I have entered three invalid inputs in the list , it is giving three exceptions in the list at the end corresponding to each element which is giving exception.
For the demo purpose, I have created one more list listOfElementsWithoutExceptions showing the elements which are processed without any exceptions.
Note: You can have your own custom exception list in place of List<Exception>.
public class Test2 {
public static void main(String[] args) {
List<String> test = Arrays.asList("test1", "test2", "3","4","test5","6");
List<Exception> listOfExceptions = new ArrayList<>();
List<String> listOfElementsWithoutExceptions = new ArrayList<>();
test.forEach(t -> {
try {
validate(t);
listOfElementsWithoutExceptions.add(t);
} catch (Exception e) {
listOfExceptions.add(e);
}
});
System.out.println("list of exceptions:: " + listOfExceptions);
System.out.println("list of elements without exceptions:: "+ listOfElementsWithoutExceptions);
}
private static void validate(String t) {
Integer.parseInt(t);
}
}
Output:
list of exceptions::
[java.lang.NumberFormatException: For input string: "test1",
java.lang.NumberFormatException: For input string: "test2",
java.lang.NumberFormatException: For input string: "test5"]
list of elements without exceptions:: [3, 4, 6]
In Kotlin code, I have a list of objects and while processing it via filter and map I want to collect items of particular interest. And discard others.
For example, I am using foreach loop as below. Is it possible to make it better by using map instead of foreach?
fun main() {
val exceptionRequests = mutableListOf<String>()
listOf<String>("Name1", "Name2", "Name3")
.filter {
it.length > 2
}
.forEach {
try {
if (it == "Name2") {
throw Exception(it)
} // Throwing exception here like this for simplicity. In real case, business logic throws exception.
} catch (exception: Exception) {
exceptionRequests.add(it)
}
}
println(exceptionRequests) // This prints `Name2`.
}
You can use .mapNotNull
val exceptionResults = listOf<String>("Name1", "Name2", "Name3")
.filter {
it.length > 2
}
.mapNotNull { name ->
try {
if (name == "Name2") {
throw Exception(name)
}
null
} catch (exception: Exception) {
name
}
}
println(exceptionRequests) // This prints `Name2`.
If exception isn't thrown, try catch expression will result in null.
If exception is thrown, try catch expression will result in name.
mapNotNull will filter out nulls (cases where exception wasn't thrown).
Why do you compare it and throw an Exception and then add that in the catch block?
You can derive exceptionRequests as follow:
val exceptionRequests = listOf<String>("Name1", "Name2", "Name3")
.filter {
it.length > 2 && it == "Name2"
}
I have a product, I wanna populate products in another array with the same original order, I used parallel Stream and the result was not ordered with the original order
List<Product> products = productList.getProducts();
List<ProductModelDTOV2> productModelDTOV2s = new ArrayList<>();
products.parallelStream().forEach(p -> {
try {
ProductModelDTOV2 ProductModelDTOV2 = dtoFactoryV2.populate(p, summary);
productModelDTOV2s.add(ProductModelDTOV2);
} catch (GenericException e) {
log.debug(String.format("Unable to populate Product %s", p));
}
});
return productModelDTOV2s;
It seems like this part of the code can be unordered and be run in parallel:
ProductModelDTOV2 ProductModelDTOV2 = dtoFactoryV2.populate(p, summary);
But this part must be ordered:
productModelDTOV2s.add(ProductModelDTOV2);
What you can do is to separate those two things. Do the first part in a flatMap, and the second part in forEachOrdered:
products.parallelStream().flatMap(o -> { // this block will be done in parallel
try {
return Stream.of(dtoFactoryV2.populate(p, summary));
} catch (GenericException e) {
// don't expect this message to be printed in order
log.debug(String.format("Unable to populate Product %s", p));
return Stream.of();
}
})
.forEachOrdered(productModelDTOV2s::add); // this will be done in order, non-parallel
The correct way to do this, would be to have the Stream create the list:
List<Product> products = productList.getProducts();
return products.parallelStream()
.map(p -> {
try {
return dtoFactoryV2.populate(p, summary);
} catch (GenericException e) {
log.debug("Unable to populate Product " + p);
return null;
}
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
I have about 1000 files with a date in their name, i would like to sort them by this date in the filename and pick the latest one which has a date same or earlier than an argument.
I have wrote this:
Pattern PATTERN = Pattern.compile("^\\d{4}-\\d{2}-\\d{2}-file.csv");
try {
deviceFiles = Files.list(filesDir.toPath())
.filter(path -> PATTERN.matcher(path.getFileName().toString()).matches()
&& !getDate(path).isAfter(ARGUMENT_DATE))
.collect(Collectors.toList());
Arrays.sort(deviceFiles.toArray(), new FileNamePathDateComparator());
logger.info("All files found are " + deviceFiles.stream().map(stream -> stream.toAbsolutePath().toString()).collect(Collectors.joining("\n")));
if (deviceFiles.isEmpty())
throw new IllegalStateException("There were no device files found");
else {
String deviceFilePath = deviceFiles.get(deviceFiles.size() - 1).toAbsolutePath().toString();
logger.info("Found device file: " + deviceFilePath);
return deviceFilePath;
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
The getDate method:
private LocalDate getDate(Path path)
{
try {
String[] parts = path.getFileName().toString().split("-");
return LocalDate.of(Integer.parseInt(parts[0]), Integer.parseInt(parts[1]), Integer.parseInt(parts[2]));
} catch (NumberFormatException ex) {
throw new IllegalArgumentException("bye", ex);
}
}
The comparator:
class FileNamePathDateComparator implements Comparator{
#Override
public int compare(Object o1, Object o2)
{
return getDate((Path)o1).compareTo(getDate((Path)o2));
}
}
When i run this locally i see that the logger prints all the files correctly sorted, the comparator works just fine.
But on a kubernetes cluster the files are printed randomly, i dont understand this.
Fixed! I have put the comparator in the stream rather than in the final list, and it works fine.
If in the mean while someone can provide an explanation, i would appreciate.
deviceFiles = Files.list(filesDir.toPath())
.filter(path -> PATTERN.matcher(path.getFileName().toString()).matches()
&& !getDate(path).isAfter(executionDate))
.sorted(new FileNamePathDateComparator()::compare)
.collect(Collectors.toList());
I am trying to get a solution to the following problem.
How can I find values from "conditions" in "stream"?
At the moment I can only filter with the "line.contains method". But I want that the user can give a number of conditions which would be saved in the Array "conditions". I tried to build a for-loop in the stream.filter but I failed.^^ Maybe you know an efficient way. :)
Thanks.
private static void streamSelectedFile(String p, String[] conditions) {
try (
Stream<String> stream = Files.lines(Paths.get(p), StandardCharsets.ISO_8859_1)) {
Stream<String> filteredStream =
stream.filter(line -> line.contains("conditionValue"));
filteredStream.forEach(elem -> {
System.out.println(elem + " Path: " + p);
});
} catch (IOException e) {
...
}
}
Use allMatch
stream.filter(line -> Stream.of(conditions).allMatch(line::contains))