Collect conditional items while streaming in kotlin - java

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"
}

Related

How do I continue with next element in the Java Stream in case of exception?

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]

org.springframework.dao.EmptyResultDataAccessException -->Help me fix this

public String deleteCounterParty(List<CounterParty>counterParties)
{
String message = "";
for(CounterParty counterParty:counterParties) {
if (counterParty.getId() != null && counterPartyRepository.getById(counterParty.getId()) != null) {
counterPartyRepository.deleteById(counterParty.getId());
message="deleted successfully";
}
else {
message="id not found";
}
}
return message;
}
I'm using this method to delete rows by giving list of ids if the given id is found it is deleted,if not it throws this EmptyResultDataAccessException help me fix this
Data access exception thrown when a result was expected to have at least one row (or element) but zero rows (or elements) were actually returned.
Use a try-catch block to catch the exception if thrown and alter your logic accordingly so that when the code follows a happy path, at least one row is returned.
try { //code to delete rows } catch(final
EmptyResultDataAccessException e) { //exception message }

handle exceptions in stream java 8

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());

Pig UDF Throwing NullPointerException When Generating New Tuple

I have a Pig UDF which ingests some data and then attempts to transform that data in a minimal manner.
my_data = LOAD 'path/to/data' USING SomeCustomLoader();
my_other_data = FOREACH my_data GENERATE MyUDF(COL_1, COL_2, $param1, $param2) as output;
my_final_data = FOREACH my_other_data GENERATE output.NEW_COL1, output.NEW_COL2, output.NEW_COL3;
However, I keep getting the following error:
ERROR 0: Exception while executing [POUserFunc (Name: POUserFUnc(udf.MyUDF)[tuple] - scope-38 Operator Key: scope-38) children: null at []]: java.lang.NullPointerException
My UDF takes the data and transforms it:
public class MyUDF extends EvalFunc<Tuple> {
public Tuple exec(Tuple input) throws IOException {
if (input == null || input.size() == 0)
return null;
TupleFactory _factory;
Long fieldOne;
String fieldTwo;
String fieldThree;
_factory.getInstance();
try {
fieldOne = Long.valueOf(input.get(0).toString());
fieldTwo = input.get(1).toString();
fieldThree = input.get(2).toString();
fieldOne = doSomething(fieldOne);
fieldTwo = doSomething(fieldTwo);
fieldThree = doSomething(fieldThree);
return _factory.newTuple(Arrays.asList(fieldOne, fieldTwo, fieldThree));
} catch (Exception ex) {
return _factory.newTuple(Arrays.asList("ParseException", "", "", ""));
}
}
}
I have debugged and confirmed that fieldOne, fieldTwo, and fieldThree do exist prior to calling the tuple factory. It's also clear that the exception is being thrown because the code reaches the catch block and then throws this NullPointerException error.
What is not clear is why on earth this is happening.
According to the Pig docs (Pig 0.14.0 API), I should be able to call newTuple(java.util.List c) with the relevant items.
I have also defined my own Schema to ensure the types are correct when going back to the pig script.
The code in question has not instantiated your tuple instance, thus you cannot call the method on an object that does not exist.
public class ... {
TupleFactory _factory;
public Tuple exec(Tuple input) {
_factory = TupleFactory.getInstance();
...
}
}

Handling multiple exceptions in java

My abandon() may throw AbandonException.
While handling the exception I have to recall the same method if there some element left in the Vector.
How should I proceed? And if I am not thinking straight, what would be the best solution?
if (i + 1 < lc.size()) {
try {
lc.get(i + 1).abondon();
}
catch (AbandonException e1) {
lc.get(i+2).abandon();}}
following is some pseudo-code:
List errorIndexList = new ArrayList();
for(...) {
if (i + 1 < lc.size()) {
try {
lc.get(i + 1).abondon();
} catch (AbandonException e1) {
errorIndexList.add(i+1);
// do some error handle work ..
// print error log/info if need,
continue; // this is optional, in case it's the last statement,
}
}
}
// use errorIndexList to handle your errors, if need,
You could use finally here.
try {
lc.get(i + 1).abondon();
}
catch (AbandonException e1) {
} finally {
your code
}

Categories