Let's say I want to see if an object exists in a stream and if it is not present, throw an Exception. One way I could do that would be using the orElseThrow method:
List<String> values = new ArrayList<>();
values.add("one");
//values.add("two"); // exception thrown
values.add("three");
String two = values.stream()
.filter(s -> s.equals("two"))
.findAny()
.orElseThrow(() -> new RuntimeException("not found"));
What about in the reverse? If I want to throw an exception if any match is found:
String two = values.stream()
.filter(s -> s.equals("two"))
.findAny()
.ifPresentThrow(() -> new RuntimeException("not found"));
I could just store the Optional, and do the isPresent check after:
Optional<String> two = values.stream()
.filter(s -> s.equals("two"))
.findAny();
if (two.isPresent()) {
throw new RuntimeException("not found");
}
Is there any way to achieve this ifPresentThrow sort of behavior? Is trying to do throw in this way a bad practice?
You could use the ifPresent() call to throw an exception if your filter finds anything:
values.stream()
.filter("two"::equals)
.findAny()
.ifPresent(s -> {
throw new RuntimeException("found");
});
Since you only care if a match was found, not what was actually found, you can use anyMatch for this, and you don't need to use Optional at all:
if (values.stream().anyMatch(s -> s.equals("two"))) {
throw new RuntimeException("two was found");
}
userOptional.ifPresent(user1 -> {throw new AlreadyExistsException("Email already exist");});
Here middle bracket is compulsory, else it is showing compile time exception
{throw new AlreadyExistsException("Email already exist");}
public class AlreadyExistsException extends RuntimeException
and exception class must extends runtime exception
Related
I'm trying to use Java 8 stream to check if all the distinct characters in a string are present in a map and to return their keys as a List. I am able to do it using Stream like below:
...
map.put("Apple",'a');
map.put("Ball",'b');
map.put("Cat",'c');
map.put("Doll",'d');
String format = "aabbbc";
List<String> list = format.chars().mapToObj(i -> (char) i).distinct()
.map(c -> map.entrySet().stream()
.filter(entry -> entry.getValue() == c).findFirst().get().getKey())
.collect(Collectors.toList());
So this returns me ["Apple","Ball","Cat"]. However, I would have an input where the character might not be in the map. For example: format = "aabbbczzzzz"
In this case, I want to throw an exception saying that the Character is not found in the map. So I did this
List<String> list = format.chars()
.mapToObj(i -> (char) i)
.distinct()
.map(c -> map.entrySet().stream()
.filter(entry -> entry.getValue() == c)
.findFirst()
.orElseThrow(() -> new Exception("Character not found in Map")))
.collect(Collectors.toList());
But Java doesn't let me compile. Please help me with how to handle my requirement.
https://ideone.com/Kb2WoN
The lambda expression you pass to the map is a Function which doesn't let you throw a checked exception. The contract of a Functions is:
public interface Function<T, R> {
R apply(T t);
}
It takes a value of type T and returns a value of type R. You cannot throw a checked exception from an implementation of apply.
You can change your code to throw an unchecked exception.
Also, you are missing a map call to map to the map key as stated in the other answer
List<String> list = format.chars().mapToObj(c -> (char) c).distinct()
.map(c -> map.entrySet().stream()
.filter(entry -> entry.getValue() == c)
.map(Map.Entry::getKey) //extract the map key
.findFirst()
.orElseThrow(() -> new RuntimeException("Character not found in Map")))
.collect(Collectors.toList());
You can also create a custom domain exception that extends RuntimeException and throw that.
References:
Java 8 Lambda function that throws exception?
Throwing checked exceptions in streams from Java Dev Central
Sidenote: You are looping through the map for each character in the string. To improve performance, you can create a reverse map so that you can look up (O(1)) if the character is present in the map and return the value.
List<String> list = format.chars().mapToObj(i -> (char) i).distinct()
.map(c -> {
Optional<Map.Entry<String, Character>> first = map.entrySet().stream().filter(entry -> entry.getValue() == c).findFirst();
if (first.isPresent()) {
return first.get().getKey();
} else {
throw new RuntimeException("Character not found in Map");
}
}).collect(Collectors.toList());
This should resolve your problem.
Reason why you were getting compile error is when you write the following line
.filter(entry -> entry.getValue() == c).findFirst().orElseThrow(()-> new Exception("Character not found in Map"))).collect(Collectors.toList())
You are collecting result in List<Map.Entry<String, Character>>. But in the reference variable you have used List<String> list which is the issue.
Also, you are throwing a Checked Exception which you have not handled explicitly. Better to use an UnChecked Exception like RuntimeException.class
The above answer could've been written in complete functional style in following way
List<String> list = format.chars().mapToObj(i -> (char) i).distinct()
.map(c -> map.entrySet().stream().filter(entry -> entry.getValue() == c)
.findFirst()
.map(Map.Entry::getKey)
.orElseThrow(RuntimeException::new))
.collect(Collectors.toList());
First of all I think you should throw RuntimeException instead of Exception or you should catch that in your lambda expression.
Second of all after using findFirst, you'll get an Optional<Entry> object, which means that you should map your result form findFirst to Map.Entry::getKey:
List<String> list = format.chars()
.mapToObj(i -> (char) i)
.distinct()
.map(c -> map.entrySet()
.stream()
.filter(entry -> entry.getValue() == c)
.findFirst()
.map(Map.Entry::getKey)
.orElseThrow(() -> new RuntimeException("Character not found in Map")))
.collect(Collectors.toList());
I am using a non stream way to get single element from collection.
List<MyCustomClass> list = OtherObject.getMyList();
if (list.size() != 1) {
throw new RuntimeException();
}
MyCustomClass customClass = list.get(0);
Instead of this multi liner approach, is there some way to achieve this via streams?
You can use reduce(accumulator) and orElseThrow(exceptionSupplier) to ensure the stream produces exactly one result.
MyCustomClass customClass = list.stream()
.reduce((a,b) -> { throw new RuntimeException("Too many values present"); })
.orElseThrow(() -> { throw new RuntimeException("No value present"); });
I was looking for a version with a single collect statement, although it turned out not as concise or elegant as the solution by Andreas. It uses an implementation of Collector that accumulates to a one-element list, while the combiner raises an exception if we have more than one element; the finisher raises an exception when the list is empty.
list.stream().collect(
Collector.of( ArrayList::new,
(a, t) -> { if (!a.isEmpty())
throw new RuntimeException();
a.add(t); },
(a, b) -> { throw new RuntimeException(); },
a -> { if( a.isEmpty() )
throw new RuntimeException();
return a.get(0);} );
You could try returning an optional from findFirst() or findAny().
List<String> strings = new ArrayList<>();
Optional<String> maybeFirst = strings.stream().findFirst();
// we now have an optional, lets force a value
String value = maybeFirst.orElseThrow(IllegalArgumentException::new);
// if there isn't a value, we'll throw an illegal argument exception.
This can collapsed into the following.
String value = strings.stream()
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("There must be at least one string."));
Hope that helps.
I have a piece of code like this:
return getObject()
.map(obj -> obj.getNullableField())
.orElseThrow(() -> new IllegalStateException("Object not found!"));
At the moment I'm throwing an exception when the given Object is not present.
Now I need to also check if the nullableField of Object is present.
One obvious solution could be something like this:
var fieldVal = getObject()
.map(obj -> obj.getNullableField())
.orElseThrow(() -> new IllegalStateException("Object not found!"));
return Optional.ofNullable(fieldVal)
.orElseThrow(() -> new IllegalStateException("Field is not present"));
But I'd like to implement this in the same functional chain...
What am I missing?
It could be implemented within the same chain directly, you would get different exception thrown. Now, it's less readable than your first solution of course, so you have a trade-off.
return getObject().map(obj -> Optional.ofNullable(obj.getNullableField())
.orElseThrow(() -> new IllegalStateException("Field is not present")))
.orElseThrow(() -> new IllegalStateException("Object not found!"));
Rather than nesting, I would suggest a simple sequence to solve that as:
var value = getObject()
.orElseThrow(() -> new IllegalStateException("Object not found!"));
return Optional.of(value) // ensured value check already
.map(CustomObject::getNullableField) // takes care ofNullable
.orElseThrow(() -> new IllegalStateException("Field is not present"));
I'd recommend dropping the Optional approach completly or at least use it only at the beginning (Imagining that getObject() cannot be changed):
var value = getObject()
.orElseThrow(() -> new IllegalStateException("Object not found!"));
var field = value.getNullableField();
if(field == null) {
throw new IllegalStateException("Field is not present");
}
return field;
This doesn't introduce a new Optional wrapper just so you can be "fluent" and do it all in a single line / statement.
Optional.ofNullable() checks only for null values and CollectionUtils.isNotEmpty() does not return a stream. Is there a way to combine both these features.Something like this-
Collection.isNotEmpty(entries)
.orElseThrow(() -> new Exception("exception"))
.stream()
Instead of-
Optional.ofNullable(entries)
.orElseThrow(() -> new Exception("exception"))
.stream()
For comparison, consider this:
if (entries == null || entries.isEmpty()) {
throw Exception("exception");
} else {
return entries.stream();
}
(Holger has mentioned pretty much the same thing in a couple comments.)
In my opinion, using Optional for this case isn't an improvement over a conventional if/else statement.
You can simply use filter() to check that it's not empty
Optional.ofNullable(entries)
.filter(e -> !e.isEmpty())
.orElseThrow(() -> new Exception("exception"))
.stream()
Regarding your comment that you want to eliminate null values in the stream itself you can use this:
Optional.ofNullable(entries)
.filter(e -> !e.isEmpty())
.orElseThrow(() -> new Exception("exception"))
.stream()
.filter(Objects::nonNull)
Perhaps:
Optional.ofNullable((entries == null || entries.isEmpty()) ? null : entries)
.orElseThrow(() -> new Exception("exception"))
.stream()
You can map to a stream as:
Optional.ofNullable(entries)
.filter(a -> !a.isEmpty())
.orElseThrow(() -> new Exception("exception"))
// do whatever with the stream if available
I'm trying to find a matching value in a Map and if found, I need to throw an IllegalArgumentException. My code is as follows:
final String stringToBeMatched = "someRandomString";
map.values()
.stream()
.filter(a -> stringToBeMatched == a.getField())
.findAny()
.ifPresent(a -> throw new IllegalArgumentException());
I get a syntax error on token "throw". I'm not sure where I'm going wrong.
A lambda body can be an expression or a block of statements. However,
throw new IllegalArgumentException()
is a statement, which is neither. Make it a block by surrounding it with braces.
.ifPresent(a -> {throw new IllegalArgumentException(); } );
And for your next question, compare your string values with .equals, not with ==.
Alternate cleaner solution, using anyMatch:
boolean found = map.values()
.stream()
.anyMatch(a -> stringToBeMatched.equals(a.getField()));
if(found) {
throw new IllegalArgumentException();
}
findAny return a Optional, you can use orElseThrow
map.values()
.stream()
.filter(a -> stringToBeMatched == a.getField())
.findAny()
.orElseThrow(() -> new IllegalArgumentException());