Observables only emit one object, so doOnNext() is always called with an Action1. How can I use Action2 in a similar fashion?
Can I combine 2 observables call an Action2?
EDIT: Why would I want to do this? I am working on a checkout app. I have a view that in order to display correctly, it needs two pieces of data (1: tip% and 2: total cost). So if this view could react to an observable sequence as an Action2, I would be happy.
EDIT2: Here's a method on the view mentioned previously. If this were an Action1, I could easily call it like I do with .doOnNext(). Are there operators that can operate similarly to .doOnNext() but take in an Action2 as a parameter? Maybe something like withLatestFrom() that takes in an Action2 instead of a Func2?
public Action2<Money, List<Integer>> displayGratuityOptions() {
return (subtotal, gratuityPercents) -> {
removeAllTabs();
for (final Integer percent : gratuityPercents) {
addTab(createTab(subtotal, percent));
}
addTab(createCustomGratuityTab());
};
}
Operators like withLatestFrom are there to combine multiple sequences into a single sequence. I think you will be better placed to work with Rx if you can adopt this way of thinking i.e. single data type sequences.
To this end I would suggest creating a type that has both the data types you want. You can then merge your data and then pass the single value to your doOnNext handler*.
This is simple stuff in most languages that Rx is used in (C#, F#, JS, Scala) but in Java, you may have to actually declare/define a type to do this. See - A Java collection of value pairs? (tuples?)
*Please try to avoid using the Do side-effect operators. There is almost always a better way. In you example it looks like you are doing some significant work in that handler (Creating, Adding and Removing tabs which I assume are Visual Controls)
Related
I would like to know how to obtain the value contained in a Single and contain it in a variable? (In the example that I am going to add, capturing it is a String, but I would like its proposals to be indifferent to the type since it could be an object created by oneself or another type whatever), mention that in this case it would no longer accept a blockingGet() which for concepts I would like to keep the detail async.
In the current context it is shown that the map still gets a Single, but my goal is still to get just String, its support with the fundamentals to be able to understand this detail that has emerged when researching and practicing rxJava.
enter image description here
You can try something like this which is asynchronous:
String variableString="";
a.subscribe( result -> {
variableString = result.toString();
});
System.out.println(convertToSentence(variableString));
I have the following code
//assume we have a list of custom type "details" already constructed
for(int i = 0; i < details.size(); ++i) {
CallerID number = details.get(i).getNextNumber();
ClientData.addToClient(number);
}
I have oversimplified the code. The enum CallerID and the ClientData object work as intended. I am asking for help converting this loop to a lambda function so I can understand the logic of how to do so, then fill in the appropriate code as needed.
Let's first write it as a modern basic for loop and golf it a bit, just so we're comparing apples to apples:
for (var detail : details) clientData.addToClient(detail.getNextNumber());
And this is probably the right answer. It is local var, exception, and control flow transparent (which is what you want), and short.
The lambda form is this, but it's got downsides (mostly, those transparencies). It also isn't any shorter. You shouldn't write it this way.
details.stream().forEach(d -> clientData.addToClient(detail.getNextNumber());
You may be able to just remove stream() from that. But probably not.
Generally when people say "I want it in lambda form", that's not because someone is holding a gun to your head - you are saying that because somebody peddling a religion of sorts to you told you that 'it was better' and that this 'will scale'. Realize that they are full of it. There can be advantages to 'functional style', but none of these snippets are functional. A true functional style would involve a bunch of side-effect-free transformations, and then returning something.
.addToClient? You've lost the functional game there - you would want to instead convert each detail to something (presumably a ClientID), and from there construct an immutable object from that stream. You'd 'collect' your ClientIDs into a clientData object.
Let's say for example that clientData is just a 'list of ClientIDs' and nothing more. Then you'd write something like this:
var clientData = details.stream()
.map(MyDetailClass::getNextNumber)
.collect(Collectors.toList());
Is this better? No. However, if you're looking for 'a stream-style, lambda-based functional take on things', that qualifies. The output is constructed by way of collection (and not forEach that does a side-effect operation), and all elements involved are (or can be) immutable.
There's no particular reason why you'd want this, but if for some reason you're convinced this is better, now you know what you want to do. "Just replace it with a lambda" doesn't make it 'functional'.
I am asking for help converting this loop to a lambda function so I can understand the logic of how to do so, then fill in the appropriate code as needed.
A Function returns a value. As you are just updating something what you need is a Consumer which accepts a single argument of a list of some detail. Assuming those are in a Class named SomeDetails, here is how you would do it.
As you iterating over some structure limited by size and using get(i) I am presuming a list is required here.
List<SomeDetails> details = new ArrayList<>(); // then populated
// lambda definition
Consumer<List<SomeDetails>> update = (lst)-> {
for(SomeDetails detail : lst) {
CallerID number = detail.getNextNumber();
ClientData.addToClient(number);
}
};
And then invoke it like this, passing the List.
update.accept(details);
All the above does is encapsulate the for loop (using the enhanced version for simplicity) and perform the operation.
If this is all you wanted, I would recommend just doing it as you were doing it sans the lambda.
Vavr's Either seems to solve one of my problems were some method does a lot of checks and returns either CalculationError or CalculationResult.
Either<CalculationError, CalculationResult> calculate (CalculationData calculationData) {
// either returns Either.left(new CalculationError()) or Either.right(new CalculationResult())
}
I have a wrapper which stores both errors and results
class Calculation {
List<CalculationResult> calculationResults;
List<CalculationError> calculationErrors;
}
Is there any neat solution to transform stream from Collection<CalculationData> data to Calculation?
This can be easily done using a custom collector. With a bit of pseudo code representing the Either:
Collector<Either<CalculationError, CalculationResult>, ?, Calculation> collector = Collector.of(
Calculation::new,
(calc, either) -> {
if (either has error) {
calc.calculationErrors.add(either.error);
} else {
calc.calculationResults.add(either.result);
}
},
(calc1, calc2) -> {
calc1.calculationErrors.addAll(calc2.calculationErrors);
calc1.calculationResults.addAll(calc2.calculationResults);
return calc1;
}
);
Calculation calc = data.stream()
.map(this::calculate)
.collect(collector);
Note that Calculation should initialize its two lists (in the declaration or a new constructor).
Well, you're using vavr, so 'neat' is right out. Tends to happen when you use tools that are hostile to the idiomatic form of the language. But, then again, 'neat' is a nebulous term with no clear defined meaning, so, I guess, whatever you think is 'neat', is therefore 'neat'. Neat, huh?
Either itself has the sequence method - but both of them work the way Either is supposed to work: They are left-biased in the sense that any Lefts present is treated as erroneous conditions, and that means all the Right values are discarded if even one of your Eithers is a Left. Thus, you cannot use either of the sequence methods to let Either itself bake you a list of the Right values. Even sequenceRight won't do this for you (it stops on the first Left in the list and returns that instead). The filter stuff similarly doesn't work like that - Either very much isn't really an Either in the sense of what that word means if you open a dictionary: It does not mean: A homogenous mix of 2 types. It's solely a non-java-like take on exception management: Right contains the 'answer', left contains the 'error' (you're using it correctly), but as a consequence there's nothing in the Either API to help with this task - which in effect involves 'please filter out the errors and then do something' ("Silently ignore errors" is rarely the right move. It is what is needed here, but it makes sense that the Either API isn't going to hand you a footgun. Even if you need it here).
Thus, we just write it plain jane java:
var calculation = new Calculation();
for (var e : mix) {
if (e.isLeft()) calculation.calculationErrors.add(e.getLeft());
if (e.isRight()) calculation.calculationResult.add(e.getRight());
}
(This presumes your Calculation constructor at least initializes those lists to empty mutables).
NB: Rob Spoor's answer also assumes this and is much, much longer. Sometimes the functional way is the silly, slow, unwieldy, hard to read, way.
NB2: Either.sequence(mix).orElseRun(s -> calculation.errors = s.asJava()); is a rather 'neat' way (perhaps - it's in the eye of the beholder) of setting up the errors field of your Calculation class. No joy for such a 'neat' trick to fill the 'results' part of it all, however. That's what the bulk of my answer is trying to explain: There is no nice API for that in Either, and it's probably by design, as that involves intentionally ignoring the errors in the list of Eithers.
Since you are using VAVr, you may consider using Traversable instead of Collection. This will give you the method partition, which can be used to classify your list of Eithers into two groups like so:
Traversable<Either<CalculationError, CalculationResult>> calculations = ...;
var partitionedCalcs = calculations.partition(Either::isRight);
var results = partitionedCalcs._1.map(Either::getRight);
var errors = partitionedCalcs._2.map(Either::getLeft);
Calculation calcs = new Calculation(results, errors);
If you don't want to change your existing use of Collection to use a Traversable, then you can easily convert between them by using, for example, List.ofAll(Iterator) and Value.toJavaCollection(Function).
I'm still learning Javaslang/Vavr, so excuse the ignorance. The project I'm working on is stuck on Javaslang 2.1.0.
My question: is there a more "Functional" way (as opposed to imperative style) to structure my code to join multiple Trys only once they are successful?
I want to Try each input independently, the idea being to get as much as possible error information - I do not want to stop on the first error encountered (so orElse() etc. won't do the trick). But once no errors are found any more, I want to do something further involving all of the inputs.
My current code looks like this (suitably anonymized):
Try<BigDecimal> amountTry = Try.of(this::readNumber)
.map(BigDecimal::valueOf)
.onFailure(this::collectError);
Try<Currency> currencyTry = Try.of(this::readString)
.map(currency -> currencyLookup(Currency.class, currency))
.onFailure(this::collectError);
if (amountTry.isSuccess() && currencyTry.isSuccess()) {
sale.setAmount(Amount.of(amountTry.get(), currencyTry.get()));
}
Can you suggest a pattern to replace the if() with something more in the functional style of programming?
The Javaslang/Vavr construct that you are looking for is the for comprehension construct, which is accessible through the API.For methods.
import javaslang.control.Try;
import static javaslang.API.For;
...
For(amountTry, currencyTry)
.yield(Amount::of)
.forEach(sale::setAmount);
That is, if both amountTry and currencyTry are non-empty, it creates an Iterable by yielding a result value on the cross-product of the two iterables, and performing an action on each of the resulting elements by invoking a Consumer. Here is the same in lambda form with explicit input types, if it helps you better understand it:
For(amountTry, currencyTry)
.yield((BigDecimal amount, Currency currency) -> Amount.of(amount, currency))
.forEach((Amount amount) -> sale.setAmount(amount));
Later versions of the library have overloads of the for comprehension for Try which will return a Try instance instead of Iterable, which makes the API a little bit nicer if you want to stay in Try domain.
I have seen in some projects that people use Predicates instead of pure if statements, as illustrated with a simple example below:
int i = 5;
// Option 1
if (i == 5) {
// Do something
System.out.println("if statement");
}
// Option 2
Predicate<Integer> predicate = integer -> integer == 5;
if (predicate.test(i)) {
// Do something
System.out.println("predicate");
}
What's the point of preferring Predicates over if statements?
Using a predicate makes your code more flexible.
Instead of writing a condition that always checks if i == 5, you can write a condition that evaluates a Predicate, which allows you to pass different Predicates implementing different conditions.
For example, the Predicate can be passed as an argument to a method :
public void someMethod (Predicate<Integer> predicate) {
if(predicate.test(i)) {
// do something
System.out.println("predicate");
}
...
}
This is how the filter method of Stream works.
For the exact example that you provided, using a Predicate is a big over-kill. The compiler and then the runtime will create:
a method (de-sugared predicate)
a .class that will implement java.util.Predicate
an instance of the class created at 2
all this versus a simple if statement.
And all this for a stateless Predicate. If your predicate is statefull, like:
Predicate<Integer> p = (Integer j) -> this.isJGood(j); // you are capturing "this"
then every time you will use this Predicate, a new instance will be created (at least under the current JVM).
The only viable option IMO to create such a Predicate is, of course, to re-use it in multiple places (like passing as arguments to methods).
Using if statements is the best (read: most performant) way to check binary conditions.
The switch statement may be faster for more complex situations.
A Predicate are a special form of Function. In fact the java language architect work on a way to allow generic primitive types. This will make Predicate<T> roughly equivalent to Function<T, boolean> (modulo the test vs apply method name).
If a function (resp. method) takes one or more functions as argument(s), we call it higher-order function. We say that we are passing behaviour to a function. This allows us to create powerful APIs.
String result = Match(arg).of(
Case(isIn("-h", "--help"), help()),
Case(isIn("-v", "--version"), version()),
Case($(), cmd -> "unknown command: " + cmd)
);
This example is taken from Javaslang, a library for object-functional programming in Java 8+.
Disclaimer: I'm the creator of Javaslang.
Thi is an old question, but I'll give it a try, since I am battling with it myself...
In my attempt to excuse my own usage of predicates I have made a self-rule.
I believe Predicates are useful where the "logic point" - is NOT the: leaf | corner | the end - of a: graph | tree | straight line, which would make the logic point effectively a "logic joint".
By it being a joint (aka node) it has a state, a re-usable and mutable state, that serves as a means towards an end.
In a stream, where the data is supposed to traverse a path, predicates are useful since they grant a degree of access while keeping the integrity of the stream, this is why the best predicates IMO are only method references minimizing side effects.
Even though the most common form of Predicate is newObject.equal(old), which is in itself a BiPredicate, but CAN be used with a single Predicate with side effect lambda -> lambda.equal(localCache) (so this may be an exception to the Only Method References rule).
IF, the logic serves as the output/exit point towards a different architectural design, or component, or a code that is not written by you, or even if it is written by you, one that differs on its functionality, then an if-else is my way to go.
Another benefit of predicates in the case of reactive programming is that multiple subscribers can make use of the same defined logic gate.
But if the end point of a publisher will be a single lone subscriber (which would be a case similar to your example if I'm reaching), then the logic is better done with an if-else.