Mono<T> and Flux<T> as a parameter in function - java

What is the use case for Mono<T> and Flux<T> as parameter in function.
Code
Flux<String> findByLastName(Mono<String> lastname) {
//implementation
}
When I invoke above method from rest, what will be difference from not using String.class as parameter?

To answer your first comment question:
#ErwinBolwidt i know use case for Mono/Flux in computation but i dont understand specifically using it as method parameter – Bibek Shakya
When you use it as a parameter you have to deal with it as a stream (meaning you don't have it yet) so for example you should never say lastname.block(), because this means you've just blocked the thread until this value is available.
Disclaimer Extra information
If you're asking whether you should wrap anything from now on in a Mono or a flux, then of course not, because it adds unnecessary complexity to the method and the caller.
And for a design perspective, answer is simple, by asking basic questions:
When to use a Mono in general ?
Well, when you still don't have the value.
When to use Flux in general ?
Well, when you have a stream of data coming or not.
So we should not think of who is using the method and try to make the method convenient for him, but actually we should think of the method needs.
And a use case for that is when the method actually needs argument in this way; meaning you actually do stream processing inside, for example your method accepts an infinite stream of sensor data, and the method inside is going crazy like:
Flux<Point> processSensor(Flux<Double> data){
return data.filter(blabla).zipWith(blabla).map(...);
}

Only use cases I can think of why a method parameter is Mono<String> lastname
Was retrieved from a WebClient/Router type function
#Secured("ROLE_EVERYONE") was used in a previous method to retrieve the lastname
For this to work the return type of the method must be a
org.reactivestreams.Publisher (i.e. Mono/Flux).

Related

Could be in Optional really anything

I found implemented this code (method where this part of code is used is returning Optional<File>, this part of code had to be added for verification if values are correct and case can be saved):
if (!CaseChecker.checkValues(case)) {
return Optional.of(new File("FALSE"));
}
When I asked the person, why he is returning something like this. The answer was "Optional can contain any value". To be honest I don't agree with this, because type of Optional is for some reason. So I wanted to confirm if Optional can be really anything and if yes, then what's the reason to write Optional type.
The whole point of Optional is to avoid the situation where you return a bogus value (like null, or like returning -1 from String.indexOf in order to indicate it didn't find anything), putting the responsibility on the caller to know what is bogus and to know to check for it. Returning Optional lets the caller know it needs to check whether a valid result came back, and it takes away the burden of the caller code needing to know what return values aren't valid.
Optional was never meant as a wrapper for a bogus value.
And yes you can return anything. The api doesn't stop you from doing nonsensical things.
Also consider that flatMap doesn't know what to do with this weird thing, it will treat the contents as nonempty. So now how you can use this value is limited. You have a multistage validation process where it might be something you can handle with operations chained together using flatMap, but this fake file has made that harder. It's limited your options.
Return Optional.empty() if you don't have a valid value to return.

Collect results of forEach in Java

I want to collect the values returned by a method called inside a forEach:
#PostMapping(value="insert-ppl")
public String insertPeople(#RequestBody #Valid #NotNull List<Person> people){
people.forEach(this::insertPerson);
}
the insertPerson method returns a string signaling whether the insert in the database was successfull or not. I want to take the strings returned from each call to the insertPerson. But I can't use the .collect because is not a stream.
How can I do that?
The forEach is supposed to be used to execute a consuming operation on each element. It's not supposed to be used to collect any results.
For this purpose you need to do it differently. I think best option would be to just use a standard for loop and add result of each insertPerson call into a list that you then return at the end.
Theoretically, you could use something like people.stream().map(this::insertPerson).toList() but that's in my opinion not great idea, because map() is supposed to just map input to output without any side effects, however your insertPerson obviously has side effects, which may make it more "problematic" for a reader to understand what is really happening.
There's a couple of reasons why this code isn't suitable for streams.
Firstly, your goal is to operate via side-effects (because you need to update the database), the only operations which are intended for such cases are forEach() and forEachOrdered(). And as API documentation worns these methods should be used with great care.
Note that map() isn't suitable for that purpose, it wasn't designed to operate via side-effects. And intermediate operations like map() in some cases could be optimized away from the stream. It's not likely to happen in a pipeline build like that: stream().map().collect(), but the key point is that intermediate operations semantically are not intended to perform resulting actions, in your case call insertPerson() is a resulting action and accumulated string is only a byproduct.
For your purposes, you can still use Iterable.forEach().
#PostMapping(value = "insert-ppl")
public String insertPeople(#RequestBody #Valid #NotNull List<Person> people) {
StringJoiner result = new StringJoiner("\n"); // provide the required delimiter instead of "\n"
people.forEach(person -> result.add(insertPerson(person)));
return result.toString();
}

Does the JDK provide a dummy consumer?

I have a need in a block of code to consume 'n' items from a stream then finish, in essence:
public static <T> void eat(Stream<T> stream, int n)
// consume n items of the stream (and throw them away)
}
In my situation, I can't change the signature to return Stream<T> and simply return stream.skip(n); I have to actually throw away some elements from the stream (not simple logic) - to be ready for a down stream consumer which doesn't need to know how, or even that, this has happened.
The simplest way to do this is to use limit(n), but I have to call a stream terminating method to activate the stream, so in essence I have:
public static <T> void skip(Stream<T> stream, int n) {
stream.limit(n).forEach(t -> {});
}
Note: This code is a gross over simplification of the actual code and is for illustrative purposes only. Actually, limit won't work because there is logic around what/how to consume elements. Think of it like consuming "header" elements from a stream, then having a consumer consume the "body" elements.
This question is about the "do nothing" lambda t -> {}.
Is there a "do nothing" consumer somewhere in the JDK, like the "do nothing" function Function.identity()?
No, JDK does not provide dummy consumer as well as other predefined functions like dummy runnable, always-true predicate or supplier which always returns zero. Just write t -> {}, it's anyways shorter than calling any possible ready method which will do the same.
Introducing the dummy (empty) consumer was considered in the scope of the ticket:
[JDK-8182978] Add default empty consumer - Java Bug System.
Archived: [JDK-8182978] Add default empty consumer - Java Bug System.
According to the ticket, it was decided not to introduce it.
Therefore, there is no dummy (empty) consumer in the JDK.
Yes. Well, more or less yes...
Since a Function is also a Consumer, you can use Function.identity() as a "do nothing" Consumer.
However, the compiler needs a little help to make the leap:
someStream.forEach(identity()::apply);

How do i correctly match a List of Strings?

I am attempting to set up a when statement for a method used inside another method I am testing. Inside the method I am testing I am creating a list which I have no reference to, therefore I cannot mock it. I would like to validate the contents of this list when it is used in the above mentioned method inside. I have used the following as part of the when method, but ended up with an "InvalidUseOfMatchersException" in every case. What am I missing?
Matchers.eq(mockKeys) //mockKeys is a List<String> with expected contents
Matchers.anyListOf(String.class)
Mockito.when(myDaoImpl.getRecords([either of the above])).thenReturn(mockResult);
I must refuse to provide exact code.
List<String> mockKeys = createMockKeys(); // defined elsewhere
when(myDaoImpl.getRecords(Matchers.eq(mockKeys))).thenReturn(mockResult);
when(myDaoImpl.getRecords(mockKeys)).thenReturn(mockResult); // implicitly equal
when(myDaoImpl.getRecords(Matchers.anyListOf(String.class)))
.thenReturn(mockResult);
All of the above are fine. Nothing you've posted looks inherently wrong; it's more likely a problem we can't see, such as if getRecords is final, or in a use of Mockito or Matchers surrounding your code. Though it is understandable not to be able to post more code than you can, it may make it hard to provide a more-specific answer.
For the sake of debugging, place a call to Mockito.validateMockitoUsage() before and after your stub. This will help ensure that the problem is actually on the line you think it is, and not pollution from calls before or after.
Your problem is the two lines Matchers.eq(mockKeys); and Matchers.anyListOf(String.class). As the message says, you're using them invalidly.
Mockito uses its own data structure to store a matcher when you call such a method, but returns a different value from the actual call. That additional value must be passed to the method that you're stubbing (getRecords in this case), and when you stub, Mockito retrieves the actual matchers from the data structure.
Unless you completely understand how the data structure works, and know exactly what you're doing, you really need to put the calls to the two Matchers methods inside the call to getRecords. For example,
when(myDaoImpl.getRecords(eq(mockKeys), anyListOf(String.class))).thenReturn(mockResult);

Is NULL arguments a bad practice?

Is it a bad practice to pass NULL argument to methods or in other words should we have method definitions which allow NULL argument as valid argument.
Suppose i want two method
1. to retrieve list of all of companies
2. to retrieve list of companies based upon filter.
We can either have two methods like as below
List<Company> getAllCompaniesList();
List<Company> getCompaniesList(Company companyFilter);
or we can have one single method
List<Company> getCompaniesList(Company companyFilter);
here in second case, if argument is NULL then method return list of all of companies.
Beside question of good practice practically i see one more issue with later approach which is explained below.
I am implementing Spring AOP, in which i want to have some checks on arguments like
1. Is argument NULL ?
2. is size of collection 0?
There are some scenarios where we can not have null argument at all like for method
void addBranches(int companyId, List<Branch>);
This check can be performed very well by using Spring AOP by defining method like following
#Before(argNames="args", value="execution(* *)")
void beforeCall(JoinPoint joinPoint ,Object[] args )
{
foreach(Object obj in args)
{
if(obj == NULL)
{
throw new Exception("Argument NULL");
}
}
}
But problem i am facing is since i have defined some of methods which should accept NULL argument for multiple functionality of one single method as mentioned above for method List getCompaniesList(Company companyFilter);
So i can not apply AOP uniformly for all of methods and neither some expression for methods name match will be useful here.
Please let me know if more information is required or problem is not descriptive enough.
Thanks for reading my problem and giving thought upon it.
It's fine, in cases when there are too many overloaded methods. So instead of having all combinations of parameters, you allow some of them to be null. But if you do so, document this explicitly with
#param foo foo description. Can be null
In your case I'd have the two methods, where the first one invokes the second with a null argument. It makes the API more usable.
There is no strict line where to stop overloading and where to start relying on nullable parameters. It's a matter of preference. But note that thus your method with the most params will allow some of them to be nullable, so document this as well.
Also note that a preferred way to cope with multiple constructor parameters is via a Builder. So instead of:
public Foo(String bar, String baz, int fooo, double barr, String asd);
where each of the arguments is optional, you can have:
Foo foo = new FooBuilder().setBar(bar).setFooo(fooo).build();
I use a very simple rule:
Never allow null as an argument or return value on a public method.
I make use of Optional and Preconditions or AOP to enforce that rule.
This decision already saved me tons of hours bugfixing after NPE's or strange behaviour.
It's common practice, but there are ways of making your code clearer - avoiding null checks in sometimes, or moving them elsewhere. Look up the null object pattern - it may well be exactly what you need: http://en.m.wikipedia.org/wiki/Null_Object_pattern?wasRedirected=true
The rule is: simple interface, complicated implementation.
Design decisions about your API should be made by considering how the client code is likely to use it. If you expect to see either
getAllCompaniesList(null);
or
if (companyFilter == null) {
getAllCompaniesList();
} else {
getAllCompaniesList(companyFilter);
}
then you're doing it wrong. If the likely use-case is that the client code will, at the time it is written, either have or not have a filter, you should supply two entry points; if that decision is likely not made until run-time, allow a null argument.
Another approach that may be workable may be to have a CompanyFilter interface with an companyIsIncluded(Company) method that accepts a Company and returns true or false to say whether any company should be included. Company could implement the interface so that companyIsIncluded method's behavior mirrored equals(), but one could easily have a singleton CompanyFilter.AllCompanies whose companyIsIncluded() method would always return true. Using that approach, there's no need to pass a null value--just pass a reference to the AllComapnies singleton.

Categories

Resources