Is it possible to add logging to removeIf in java 8? - java

I am using Java 8.
The following code is working fine:
public void testMethod(List<String> prop1, EmailJson randomModel) {
prop1.stream().forEach(s -> randomModel.getSomeList()
.removeIf(model -> model.getSomeProp().equalsIgnoreCase(s)));
}
Is it possible to log a message if the condition is true?
I'm looking for something similar to:
public void testMethod(List<String> prop1, EmailJson randomModel) {
prop1.stream().forEach(s -> randomModel.getSomeList()
.removeIf(model -> model.getSomeProp().equalsIgnoreCase(s))
- > if this is true then log some action);
}

You can always replace
removeIf(model -> model.getSomeProp().equalsIgnoreCase(s))
with
removeIf(model -> {
boolean ret = model.getSomeProp().equalsIgnoreCase(s);
if (ret) {
// add logging
}
return ret;
})

If this is a recurring problem, you may create a helper method generalizing the task of decorating a predicate with another action, e.g. logging:
static <T> Predicate<T> logging(Predicate<T> p, BiConsumer<T,Boolean> log, boolean all) {
return t -> {
final boolean result = p.test(t);
if(all || result) log.accept(t, result);
return result;
};
}
which you may use like
public void testMethod(List<String> prop1, EmailJson randomModel){
prop1.forEach(s -> randomModel.getSomeList()
.removeIf(logging(model -> model.getSomeProp().equalsIgnoreCase(s),
(model,b) -> LOGGER.info(() -> "matched: "+model.getSomeProp()), false)));
}
though, in this specific case, it might be unnecessary to decorate the predicate itself, as removeIf return a boolean telling whether there were matches to remove, and the match value is still in scope:
public void testMethod(List<String> prop1, EmailJson randomModel){
prop1.stream().forEach(s -> {
if(randomModel.getSomeList()
.removeIf(model -> model.getSomeProp().equalsIgnoreCase(s)))
LOGGER.info(() -> "there were matches of: "+s);
});
}

Related

Getting some kind of representation of a Lambda Expression at runtime

I'd like to use something like this to check some conditions, but the problem is that I need to know which condition failed and log the exception, this way does achieve it but relies on knowing the position at which it was checked inside the code which isn't ideal, is there any other nicer way of doing this? (without making calling the function much longer)
matchOrThrow(
() -> 1 == 2,
() -> 1 == 1,
() -> a > b,
() -> c == null
);
public static void matchOrThrow(BooleanSupplier... conditions) {
int i = 1;
for (BooleanSupplier condition : conditions) {
if (Boolean.FALSE.equals(condition.getAsBoolean())) {
throw new CustomException("Condition check n_" + i + " failed");
}
i++;
}
}
You might be interested at looking at the Decorator design patter.
Namely, you can create a decorating implementation of the Functional interface of your choice. It seems like you Predicate is more suitable for than a BooleanSupplier, therefore the example below illustrates a throwing Predicate, which expects a predicate, producer of the target exception, message and logger as arguments and its implementation of test() delegates to the wrapped predicate to evaluate the condition.
The instances of the trowing Predicate can be used anywhere, where Predicate is expected.
public class ThrowingLoggPredicate<T> implements Predicate<T> {
private Predicate<T> predicate;
private Function<String, RuntimeException> exceptionFactory;
private String messageShort;
private String format;
private Logger logger;
public ThrowingLoggPredicate(Predicate<T> predicate,
Function<String, RuntimeException> exceptionFactory,
String messageShort, String format,
Logger logger) {
this.predicate = predicate;
this.exceptionFactory = exceptionFactory;
this.messageShort = messageShort;
this.format = format;
this.logger = logger;
}
public boolean test(T t) {
if (!predicate.test(t)) {
RuntimeException e = exceptionFactory.apply(messageShort);
String messageVerbose = String.format(format, t);
logger.log(Level.ERROR, messageVerbose, e);
throw e;
}
return true;
}
public static <T> boolean allMatch(Collection<Predicate<T>> predicates, T t) {
return predicates.stream().allMatch(p -> p.test(t));
}
}

How to force lambda type to a specific one?

Suppose I have a function with such signature:
public static <T> List<Future<T>> invokeAll(Stream<Callable<T>> tasks) {
... submit given tasks using executor ...
}
and I have a stream of data, which should be "wrapped" into callable and passed to this function. Naive mapping like below does not work:
Stream<String> ids = Stream.of("1", "2", "3");
invokeAll(ids.map((id) -> {
// Do a long computation with given ID...
return Boolean.TRUE; // Compilation error: Type mismatch: cannot convert from Boolean to Callable<Object>
}));
One solution would be to return lambda that returns lambda:
invokeAll(ids.map((id) -> {
return () -> {
// Do a long computation with given ID...
return Boolean.TRUE;
};
}));
another (in some way equivalent) is to use helper function:
public static <T> Callable<T> createCallable(T id) {
return () -> {
return id;
};
}
invokeAll(ids.map(ThisClass::createCallable));
but maybe there is better / shorter way of doing the same? E.g. somehow tell the compiler that it needs to create a Callable that returns a given value:
invokeAll(ids.map((Function<String, Callable<Boolean>>) (id) -> {
// Do a long computation with given ID
return Boolean.TRUE;
}));
Thanks for any suggestion.
Let's ignore lambdas for a moment, because I think they're the source of the confusion. Let's use good old anonymous classes:
invokeAll(
ids.map(
new Function<String, Callable<Boolean>>()
{
#Override
public Callable<Boolean> apply(String str)
{
return new Callable<Boolean>()
{
#Override
public Boolean call() throws Exception
{
return Boolean.TRUE;
}
};
}
}
)
);
What you're effectively asking is "how I can automatically do this:"
invokeAll(
ids.map(
new Function<String, Callable<Boolean>>()
{
#Override
public Callable<Boolean> apply(String str)
{
return Boolean.TRUE;
}
}
)
);
Of course, you can't. A Boolean is not a Callable<Boolean>. So the solutions are limited to what you've already identified:
1) to use a lambda to create the Callable:
() -> Boolean.TRUE
() -> { return Boolean.TRUE; }
2) to create a method which does this for you. Such as method is likely to more verbose than option #1 so it doesn't gain you anything.
Sorry, there's no way other to automagically make this any better.

How can I replace an Observable anonymous inner class by lambda, including a logger, for multiple Couchbase access?

I started to use java 8 some days ago and I want to refactor some method using lambda.
The following method is used to get many documents from Couchbase :
public List<JsonDocument> bulkGet(final Collection<Long> ids) {
return Observable
.from(ids)
.flatMap(new Func1<Long, Observable<JsonDocument>>() {
#Override
public Observable<JsonDocument> call(final Long id) {
return bucket().async().get(docId(id)).doOnError(new Action1<Throwable>(){
#Override
public void call(Throwable throwable) {
logger.error("Error while bulk fetching SenderEmailAddress with id [" + docId(id) + "] from Couchbase.");
}
}).onErrorResumeNext(new Func1<Throwable, Observable<JsonDocument>>(){
#Override
public Observable<JsonDocument> call(Throwable throwable) {
return Observable.empty();
}
} );
}
})
.toList()
.toBlocking()
.single();
}
And this is the context :
private static final Logger logger = LoggerFactory.getLogger(SenderNameRepositoryCouchbase.class);
public String docId(Long entityId) {
return CouchbaseBucketFactory.APPLI_PREFIX + DOC_PREFIX + entityId;
}
Now, this is my refactored method with lambdas :
public List<JsonDocument> bulkGet(final Collection<Long> ids) {
return Observable
.from(ids)
.flatMap((Long id) -> {
return bucket().async().get(docId(id))
.doOnError(
(Throwable throwable) -> { logger.error("Error while bulk fetching SenderEmailAddress with id [" + docId(id) + "] from Couchbase."); }
).onErrorResumeNext(
(Throwable throwable) -> { return Observable.empty(); }
);
})
.toList()
.toBlocking()
.single();
}
But I'm told by SonarLint I should replace this by a method reference. But it's impossible to use a method reference like Class::method with an argument, isn't it ?
By the way, I should not be allowed to use my logger in a lambda, right ?
How can I do that ?
Is it really possible to refactor this class with lambda like Sonar suggests ?
Method references do match functional types that accept parameters. The compiler will find a method with the specified name whose parameters and return types are compatible with the functional interface called for. For example for a static method,
Function<In,Out> op = in -> MyClass.doSomething(in);
which takes one parameter, is equivalent to
Function<In,Out> op = MyClass::doSomething;
When it sees MyClass::doSomething, the compiler will see that it needs a Function<In,Out> and look for a static method in MyClass called doSomething that takes a parameter that can accept an In, and a return type that can be assigned to an Out.

How to execute logic on Optional if not present?

I want to replace the following code using java8 Optional:
public Obj getObjectFromDB() {
Obj obj = dao.find();
if (obj != null) {
obj.setAvailable(true);
} else {
logger.fatal("Object not available");
}
return obj;
}
The following pseudocode does not work as there is no orElseRun method, but anyways it illustrates my purpose:
public Optional<Obj> getObjectFromDB() {
Optional<Obj> obj = dao.find();
return obj.ifPresent(obj.setAvailable(true)).orElseRun(logger.fatal("Object not available"));
}
With Java 9 or higher, ifPresentOrElse is most likely what you want:
Optional<> opt = dao.find();
opt.ifPresentOrElse(obj -> obj.setAvailable(true),
() -> logger.error("…"));
Currying using vavr or alike might get even neater code, but I haven't tried yet.
I don't think you can do it in a single statement. Better do:
if (!obj.isPresent()) {
logger.fatal(...);
} else {
obj.get().setAvailable(true);
}
return obj;
For Java 8 Spring Data offers ifPresentOrElse from "Utility methods to work with Optionals" to achieve what you want.
Example would be:
import static org.springframework.data.util.Optionals.ifPresentOrElse;
ifPresentOrElse(dao.find(), obj -> obj.setAvailable(true), () -> logger.fatal("Object not available"));
You will have to split this into multiple statements. Here is one way to do that:
if (!obj.isPresent()) {
logger.fatal("Object not available");
}
obj.ifPresent(o -> o.setAvailable(true));
return obj;
Another way (possibly over-engineered) is to use map:
if (!obj.isPresent()) {
logger.fatal("Object not available");
}
return obj.map(o -> {o.setAvailable(true); return o;});
If obj.setAvailable conveniently returns obj, then you can simply the second example to:
if (!obj.isPresent()) {
logger.fatal("Object not available");
}
return obj.map(o -> o.setAvailable(true));
There is an .orElseRun method, but it is called .orElseGet.
The main problem with your pseudocode is that .isPresent doesn't return an Optional<>. But .map returns an Optional<> which has the orElseGet method.
If you really want to do this in one statement this is possible:
public Optional<Obj> getObjectFromDB() {
return dao.find()
.map( obj -> {
obj.setAvailable(true);
return Optional.of(obj);
})
.orElseGet( () -> {
logger.fatal("Object not available");
return Optional.empty();
});
}
But this is even clunkier than what you had before.
First of all, your dao.find() should either return an Optional<Obj> or you will have to create one.
e.g.
Optional<Obj> = dao.find();
or you can do it yourself like:
Optional<Obj> = Optional.ofNullable(dao.find());
this one will return Optional<Obj> if present or Optional.empty() if not present.
So now let's get to the solution,
public Obj getObjectFromDB() {
return Optional.ofNullable(dao.find()).flatMap(ob -> {
ob.setAvailable(true);
return Optional.of(ob);
}).orElseGet(() -> {
logger.fatal("Object not available");
return null;
});
}
This is the one liner you're looking for :)
For those of you who want to execute a side-effect only if an optional is absent
i.e. an equivalent of ifAbsent() or ifNotPresent() here is a slight modification to the great answers already provided.
myOptional.ifPresentOrElse(x -> {}, () -> {
// logic goes here
})
Title: "How to execute logic on Optional if not present?"
Answer:
Use orElseGet() as a workaround for the missing ifNotPresent(). And since it expects us to return something just return
null.
Optional.empty().orElseGet(() -> {
System.out.println("The object is not present");
return null;
});
//output: The object is not present
or
Optional.ofNullable(null).orElseGet(() -> {
System.out.println("The object is not present");
return null;
});
//output: The object is not present
I also use it to easily implement the singleton pattern with lazy initialization.
public class Settings {
private Settings(){}
private static Settings instance;
public static synchronized Settings getInstance(){
Optional.ofNullable(instance).orElseGet(() -> instance = new Settings());
return instance;
}
}
Of course the getInstance() content can be written in one line by directly returning the first statement, but I wanted to demonstrate the use of orElseGet() as an ifNotPresent().
I was able to came up with a couple of "one line" solutions, for example:
obj.map(o -> (Runnable) () -> o.setAvailable(true))
.orElse(() -> logger.fatal("Object not available"))
.run();
or
obj.map(o -> (Consumer<Object>) c -> o.setAvailable(true))
.orElse(o -> logger.fatal("Object not available"))
.accept(null);
or
obj.map(o -> (Supplier<Object>) () -> {
o.setAvailable(true);
return null;
}).orElse(() () -> {
logger.fatal("Object not available")
return null;
}).get();
It doesn't look very nice, something like orElseRun would be much better, but I think that option with Runnable is acceptable if you really want one line solution.
With Java 8 Optional it can be done with:
Optional<Obj> obj = dao.find();
obj.map(obj.setAvailable(true)).orElseGet(() -> {
logger.fatal("Object not available");
return null;
});
In order to get the value from one call, or do an extra call if the previous returned an empty value, you can chain the commands.
public Optional<Obj> getObjectFromDB() {
return dao.find().or(() -> dao.findBySomethingElse());
}
You need Optional.isPresent() and orElse(). Your snippet won;t work because it doesn't return anything if not present.
The point of Optional is to return it from the method.
ifPresentOrElse can handle cases of nullpointers as well. Easy approach.
Optional.ofNullable(null)
.ifPresentOrElse(name -> System.out.println("my name is "+ name),
()->System.out.println("no name or was a null pointer"));
I suppose you cannot change the dao.find() method to return an instance of Optional<Obj>, so you have to create the appropriate one yourself.
The following code should help you out. I've create the class OptionalAction,
which provides the if-else mechanism for you.
public class OptionalTest
{
public static Optional<DbObject> getObjectFromDb()
{
// doa.find()
DbObject v = find();
// create appropriate Optional
Optional<DbObject> object = Optional.ofNullable(v);
// #formatter:off
OptionalAction.
ifPresent(object)
.then(o -> o.setAvailable(true))
.elseDo(o -> System.out.println("Fatal! Object not available!"));
// #formatter:on
return object;
}
public static void main(String[] args)
{
Optional<DbObject> object = getObjectFromDb();
if (object.isPresent())
System.out.println(object.get());
else
System.out.println("There is no object!");
}
// find may return null
public static DbObject find()
{
return (Math.random() > 0.5) ? null : new DbObject();
}
static class DbObject
{
private boolean available = false;
public boolean isAvailable()
{
return available;
}
public void setAvailable(boolean available)
{
this.available = available;
}
#Override
public String toString()
{
return "DbObject [available=" + available + "]";
}
}
static class OptionalAction
{
public static <T> IfAction<T> ifPresent(Optional<T> optional)
{
return new IfAction<>(optional);
}
private static class IfAction<T>
{
private final Optional<T> optional;
public IfAction(Optional<T> optional)
{
this.optional = optional;
}
public ElseAction<T> then(Consumer<? super T> consumer)
{
if (optional.isPresent())
consumer.accept(optional.get());
return new ElseAction<>(optional);
}
}
private static class ElseAction<T>
{
private final Optional<T> optional;
public ElseAction(Optional<T> optional)
{
this.optional = optional;
}
public void elseDo(Consumer<? super T> consumer)
{
if (!optional.isPresent())
consumer.accept(null);
}
}
}
}

Java 8 Collector that returns a value if there's only a single value [duplicate]

This question already has answers here:
Filter Java Stream to 1 and only 1 element
(24 answers)
Closed 5 years ago.
I'm a little green on this functional programming and streams stuff, but what little I do know has been very useful!
I've had this situation come up several times:
List<SomeProperty> distinctProperties = someList.stream()
.map(obj -> obj.getSomeProperty())
.distinct()
.collect(Collectors.toList());
if (distinctProperties.size() == 1) {
SomeProperty commonProperty = distinctProperties.get(0);
// take some action knowing that all share this common property
}
What I really want is:
Optional<SomeProperty> universalCommonProperty = someList.stream()
.map(obj -> obj.getSomeProperty())
.distinct()
.collect(Collectors.singleOrEmpty());
I think the singleOrEmpty thing can be useful in other situations besides just in combination with distinct. When I was an uber n00b I spent a lot of time reinventing the Java Collections Framework because I didn't know it was there, so I'm trying not to repeat my mistakes. Does Java come with a good way to do this singleOrEmpty thing? Am I formulating it wrong?
Thanks!
EDIT: Here's some example data for the distinct case. If you ignore the map step:
Optional<SomeProperty> universalCommonProperty = someList.stream()
.map(obj -> obj.getSomeProperty())
.distinct()
.collect(Collectors.singleOrEmpty());
[] -> Optional.empty()
[1] -> Optional.of(1)
[1, 1] -> Optional.of(1)
[2, 2] -> Optional.of(2)
[1, 2] -> Optional.empty()
I find I need this when I screw up my types, or have legacy code. It's really nice to be able to quickly say "All the elements of this collection share this property, so now I can take some action using this shared property." Another example is when a user multi-selects some diverse elements, and you're trying to see what stuff you can do (if anything) that's valid for all of them.
EDIT2: Sorry if my example is a misleading. The key is singleOrEmpty. I commonly find that I put a distinct in front, but it could just as easily be a filter of some other kind.
Optional<SomeProperty> loneSpecialItem = someList.stream()
.filter(obj -> obj.isSpecial())
.collect(Collectors.singleOrEmpty());
[special] -> Optional.of(special)
[special, special] -> Optional.empty()
[not] -> Optional.empty()
[not, special] -> Optional.of(special)
[not, special, not] -> Optional.of(special)
EDIT3: I think I screwed up by motivating the singleOrEmpty instead of just asking for it on its own.
Optional<Int> value = someList.stream().collect(Collectors.singleOrEmpty())
[] -> Optional.empty()
[1] -> Optional.of(1)
[1, 1] -> Optional.empty()
This will incur an overhead of creating a set but it's simple and will work correctly even if you forget to distinct() the stream first.
static<T> Collector<T,?,Optional<T>> singleOrEmpty() {
return Collectors.collectingAndThen(
Collectors.toSet(),
set -> set.size() == 1
? set.stream().findAny()
: Optional.empty()
);
}
"Hacky" solution that only evaluates the first two elements:
.limit(2)
.map(Optional::ofNullable)
.reduce(Optional.empty(),
(a, b) -> a.isPresent() ^ b.isPresent() ? b : Optional.empty());
Some basic explanation:
Single element [1] -> map to [Optional(1)] -> reduce does
"Empty XOR Present" yields Optional(1)
= Optional(1)
Two elements [1, 2] -> map to [Optional(1), Optional(2)] -> reduce does:
"Empty XOR Present" yields Optional(1)
"Optional(1) XOR Optional(2)" yields Optional.Empty
= Optional.Empty
Here is the complete testcase:
public static <T> Optional<T> singleOrEmpty(Stream<T> stream) {
return stream.limit(2)
.map(Optional::ofNullable)
.reduce(Optional.empty(),
(a, b) -> a.isPresent() ^ b.isPresent() ? b : Optional.empty());
}
#Test
public void test() {
testCase(Optional.empty());
testCase(Optional.of(1), 1);
testCase(Optional.empty(), 1, 1);
testCase(Optional.empty(), 1, 1, 1);
}
private void testCase(Optional<Integer> expected, Integer... values) {
Assert.assertEquals(expected, singleOrEmpty(Arrays.stream(values)));
}
Kudos to Ned (the OP) who has contributed the XOR idea and the above testcase!
If you don't mind using Guava, you can wrap your code with Iterables.getOnlyElement, so it would look something like that:
SomeProperty distinctProperty = Iterables.getOnlyElement(
someList.stream()
.map(obj -> obj.getSomeProperty())
.distinct()
.collect(Collectors.toList()));
IllegalArgumentException will be raised if there is more than one value or no value, there is also a version with default value.
A more concise way to build a Collector for this is as follows:
Collectors.reducing((a, b) -> null);
The reducing collector will store the first value, and then on successive passes, pass the current running value and the new value into the lambda expression. At this point, null can always be returned since this will not be called with the first value, which will simply be stored.
Plugging this into the code:
Optional<SomeProperty> universalCommonProperty = someList.stream()
.map(obj -> obj.getSomeProperty())
.distinct()
.collect(Collectors.reducing((a, b) -> null));
You can easily write your own Collector
public class AllOrNothing<T> implements Collector<T, Set<T>, Optional<T>>{
#Override
public Supplier<Set<T>> supplier() {
return () -> new HashSet<>();
}
#Override
public BinaryOperator<Set<T>> combiner() {
return (set1, set2)-> {
set1.addAll(set2);
return set1;
};
}
#Override
public Function<Set<T>, Optional<T>> finisher() {
return (set) -> {
if(set.size() ==1){
return Optional.of(set.iterator().next());
}
return Optional.empty();
};
}
#Override
public Set<java.util.stream.Collector.Characteristics> characteristics() {
return Collections.emptySet();
}
#Override
public BiConsumer<Set<T>, T> accumulator() {
return Set::add;
}
}
Which you can use like this:
Optional<T> result = myStream.collect( new AllOrNothing<>());
Here's your example test data
public static void main(String[] args) {
System.out.println(run());
System.out.println(run(1));
System.out.println(run(1,1));
System.out.println(run(2,2));
System.out.println(run(1,2));
}
private static Optional<Integer> run(Integer...ints){
List<Integer> asList = Arrays.asList(ints);
System.out.println(asList);
return asList
.stream()
.collect(new AllOrNothing<>());
}
which when run will print out
[]
Optional.empty
[1]
Optional[1]
[1, 1]
Optional[1]
[2, 2]
Optional[2]
It seems RxJava has similar functionality in its single() operator.
single( ) and singleOrDefault( )
if the Observable completes after emitting a single item, return that item, otherwise throw an exception (or return a default item)
I'd rather just have an Optional, and I'd rather it be a Collector.
Guava has a collector for this called MoreCollectors.toOptional()
https://google.github.io/guava/releases/snapshot/api/docs/com/google/common/collect/MoreCollectors.html#toOptional--
Another collector approach:
Collectors:
public final class SingleCollector<T> extends SingleCollectorBase<T> {
#Override
public Function<Single<T>, T> finisher() {
return a -> a.getItem();
}
}
public final class SingleOrNullCollector<T> extends SingleCollectorBase<T> {
#Override
public Function<Single<T>, T> finisher() {
return a -> a.getItemOrNull();
}
}
SingleCollectorBase:
public abstract class SingleCollectorBase<T> implements Collector<T, Single<T>, T> {
#Override
public Supplier<Single<T>> supplier() {
return () -> new Single<>();
}
#Override
public BiConsumer<Single<T>, T> accumulator() {
return (list, item) -> list.set(item);
}
#Override
public BinaryOperator<Single<T>> combiner() {
return (s1, s2) -> {
s1.set(s2);
return s1;
};
}
#Override
public Set<Characteristics> characteristics() {
return EnumSet.of(Characteristics.UNORDERED);
}
}
Single:
public final class Single<T> {
private T item;
private boolean set;
public void set(T item) {
if (set) throw new SingleException("More than one item in collection");
this.item = item;
set = true;
}
public T getItem() {
if (!set) throw new SingleException("No item in collection");
return item;
}
public void set(Single<T> other) {
if (!other.set) return;
set(other.item);
}
public T getItemOrNull() {
return set ? item : null;
}
}
public class SingleException extends RuntimeException {
public SingleException(String message) {
super(message);
}
}
Tests and example usages, albeit lacking parallel tests.
public final class SingleTests {
#Test
public void collect_single() {
ArrayList<String> list = new ArrayList<>();
list.add("ABC");
String collect = list.stream().collect(new SingleCollector<>());
assertEquals("ABC", collect);
}
#Test(expected = SingleException.class)
public void collect_multiple_entries() {
ArrayList<String> list = new ArrayList<>();
list.add("ABC");
list.add("ABCD");
list.stream().collect(new SingleCollector<>());
}
#Test(expected = SingleException.class)
public void collect_no_entries() {
ArrayList<String> list = new ArrayList<>();
list.stream().collect(new SingleCollector<>());
}
#Test
public void collect_single_or_null() {
ArrayList<String> list = new ArrayList<>();
list.add("ABC");
String collect = list.stream().collect(new SingleOrNullCollector<>());
assertEquals("ABC", collect);
}
#Test(expected = SingleException.class)
public void collect_multiple_entries_or_null() {
ArrayList<String> list = new ArrayList<>();
list.add("ABC");
list.add("ABCD");
list.stream().collect(new SingleOrNullCollector<>());
}
#Test
public void collect_no_entries_or_null() {
ArrayList<String> list = new ArrayList<>();
assertNull(list.stream().collect(new SingleOrNullCollector<>()));
}
}

Categories

Resources