Let's say I have two event types (A and B) and Fluxes that generate them somehow:
Flux<A> aFlux = ...;
Flux<B> bFlux = ...;
and also a type that holds the current state denoted by type S:
class S {
final int val;
}
I want to create the following:
final S sInitial = ...;
Flux<S> sFlux = Flux.merge(aFlux, bFlux)
.scan((a, e) -> {
if(e instanceof A) {
return mapA(a, (A)e);
} else if(e instanceof B) {
return mapB(a, (B)e);
} else {
throw new RuntimeException("invalid event");
}
})
.startWith(sInitial);
where sCurr is the instance of S that was last outputted by sFlux, starting with sInitial and mapA / mapB return the new value of type S. Both S and sInitial are immutable.
That is, I want to:
Continously output the latest state ...
... that is being generated ...
... based on the current state and the received event ...
... as prescribed by the mapper functions
Is there a way to reorganize the above stream flow in some other way, especially in order to avoid using instanceof?
You could add interface and implement it for your A and B classes
interface ToSConvertible {
S toS(S s);
}
Now you could use reactor.core.publisher.Flux#scan(A, java.util.function.BiFunction<A,? super T,A>) method:
Flux<S> sFlux = Flux.merge(aFlux, bFlux)
.scan(sInitial, (s, e) -> e.toS(s));
Related
Refer below code structure which I want to refactor:
#Builder
#Value
class ReasonAndAction {
String reason;
String action;
}
ReasonAndAction decideReasonAndAction(Input input) {
if(condition1(input)) {
return reactionAndAction1;
}
if(condition2(input)) {
return reactionAndAction2;
}
if(condition3(input)) {
return reactionAndAction3;
}
return ReasonAndAction.builder()
.reason("default")
.action("default")
.build();
}
All the if conditions are independent and may have some default behavior (else case). There may be need to add more if conditions with next versions which will make code bit ugly.
I want to remove if conditions and abstract out in separate classes and execute independently rather sequential.
Expected Behaviour :
Dont Have all If conditions at same place
If 2 or more if conditions are satisfied at the same time , then return new ReasonAndAction object in decideReasonAndAction method . Example - action : DO_SOMETHING , reason : CONDITION_1_AND_CONDITION_2_MET
Basically , execute all if conditions independently and get the result of all if conditions and then take action and reason accordingly.
What Java design pattern can be used here(if any) for meaningful abstraction such that default behavior(else condition at the end) is also maintained?
Can somebody please explain with example/pseudocode?
Your question is very interesting. And you have one condition:
If 2 or more conditions are satisfied, there are two or more actions and two or more reasons.
In my view, it can be solved by delegating of checking these conditions before the execution of class. However, the class should be very simple.
So let us start. This is a bad design as if we want to add new operation, then we need to add new else condition. So by doing this, we violate open closed principle of SOLID.
public class Calculator
{
public int Exec(int a, int b, string operation)
{
if (operation == "+")
return a + b;
else if (operation == "-")
return a - b;
else if (operation == "/")
return a / b;
return a * b;
}
}
What can we do? We can create an interface and use dependency inversion principle of SOLID.
Our interface:
public interface IOperation
{
int Exec(int a, int b);
}
and class:
public class CalculatorWithDependencyInversionPrinciple
{
public int Exec(IOperation operation, int a, int b)
{
return operation.Exec(a, b);
}
}
and extensions:
public class SumOperation : IOperation
{
public int Exec(int a, int b)
{
return a + b;
}
}
And if you want to add new functionality, then you need to add new class with implemented Operation interface. So our class CalculatorWithDependencyInversionPrinciple is closed for modification, but it is open for extension.
And this is a strategy pattern in action.
And you can call it like this:
int result = new CalculatorWithDependencyInversionPrinciple()
.Exec(new SumOperation(), 1, 2);
Output will be: 3
So far so good, but we want to have different operators ("Reasons" in your task) and our code should be simple and testable. In addition, we will try to make that our classes will have just one single responsibility. Read more about Single Responsibility Principle of SOLID.
So this is our operators:
public enum Operator // Reason
{
Plus,
Minus,
Divide,
Multiply
}
And this is mapping between Operator and its Operation:
public class OperationToOperator
{
public Dictionary<Operator, IOperation> OperationByOperator =
new Dictionary<Operator, IOperation>
{
{ Operator.Plus, new SumOperation() },
{ Operator.Minus, new MinusOperation() },
{ Operator.Divide, new DivideOperation() },
{ Operator.Multiply, new MultiplyOperation() },
};
}
Our condition class:
public class Condition
{
public Operator Operator { get; private set; }
public int A { get; private set; }
public int B { get; private set; }
public Condition(Operator operato, int a, int b)
{
Operator = operato;
A = a;
B = b;
}
}
and code would be executed like this:
List<Condition> conditions = new List<Condition>
{
new Condition(Operator.Plus, 1, 2),
new Condition(Operator.Minus, 4, 3),
new Condition(Operator.Multiply, 5, 6),
new Condition(Operator.Divide, 8, 2),
};
OperationToOperator operationToOperator = new OperationToOperator();
CalculatorWithDependencyInversionPrinciple calculatorWithDependencyInversionPrinciple
= new CalculatorWithDependencyInversionPrinciple();
foreach (Condition condition in conditions)
Console.WriteLine
(
calculatorWithDependencyInversionPrinciple.Exec
(
operationToOperator.OperationByOperator[condition.Operator],
condition.A,
condition.B
)
);
So we've created simple classes that are testable and we used Strategy pattern.
Researching this has been a little difficult due to I'm not precisely sure how the question should be worded. Here is some pseudo code summarizing my goal.
public class TestService {
Object someBigMehtod(String A, Integer I) {
{ //block A
//do some long database read
}
{ //block B
//do another long database read at the same time as block B
}
{ //block C
//get in this block when both A & B are complete
//and access result returned or pushed from A & B
//to build up some data object to push out to a class that called
//this service or has subscribed to it
return null;
}
}
}
I am thinking I can use RxJava or Spring Integration to accomplish this or maybe just instantiating multiple threads and running them. Just the layout of it though makes me think Rx has the solution because I am thinking data is pushed to block C. Thanks in advance for any advice you might have.
You can do this with CompletableFuture. In particular, its thenCombine method, which waits for two tasks to complete.
CompletableFuture<A> fa = CompletableFuture.supplyAsync(() -> {
// do some long database read
return a;
});
CompletableFuture<B> fb = CompletableFuture.supplyAsync(() -> {
// do another long database read
return b;
});
CompletableFuture<C> fc = fa.thenCombine(fb, (a, b) -> {
// use a and b to build object c
return c;
});
return fc.join();
These methods will all execute on the ForkJoinPool.commonPool(). You can control where they run if you pass in optional Executors.
You can use Zip operator from Rxjava. This operator can run in parallel multiple process and then zip the results.
Some docu http://reactivex.io/documentation/operators/zip.html
And here an example of how works https://github.com/politrons/reactive/blob/master/src/test/java/rx/observables/combining/ObservableZip.java
For now I just went with John's suggestion. This is getting the desired effect. I mix in RxJava1 and RxJava2 syntax a bit which is probably poor practice. Looks like I have some reading cut out for me on java.util.concurrent package . Time permitting I would like to do the zip solution.
#Test
public void myBigFunction(){
System.out.println("starting ");
CompletableFuture<List<String>> fa = CompletableFuture.supplyAsync( () ->
{ //block A
//do some long database read
try {
Thread.sleep(3000);
System.out.println("part A");
return asList(new String[] {"abc","def"});
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
);
CompletableFuture<List<Integer>> fb = CompletableFuture.supplyAsync( () ->
{ //block B
//do some long database read
try {
Thread.sleep(6000);
System.out.println("Part B");
return asList(new Integer[] {123,456});
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
);
CompletableFuture<List<String>> fc = fa.thenCombine(fb,(a,b) ->{
//block C
//get in this block when both A & B are complete
int sum = b.stream().mapToInt(i -> i.intValue()).sum();
return a.stream().map(new Function<String, String>() {
#Override
public String apply(String s) {
return s+sum;
}
}).collect(Collectors.toList());
});
System.out.println(fc.join());
}
It does only take 6 seconds to run.
private List getEnumFromType(List vars, List enums) {
List enumList = new ArrayList<>();
for (Bean.Var var : vars) {
String typeWithoutTypeIdentifierPrefix = var.getType().substring(1,var.getType().length());
for (Enum enumVal : enums) {
if (typeWithoutTypeIdentifierPrefix.equals(enumVal.getName())) {
if (!enumList.contains(enumVal)) {
enumList.add(enumVal);
}
}
}
}
return enumList;
}
You have chained two terminal stream operators.
.forEach() returns void, hence the second .forEach() complains that it can't find a stream to work with.
You may want to read some of the Java 8 Stream documentation before continuing.
Don't do this.
Don't get the idea that the Java 8 Stream API should be used every time you are looping through a collection. It's not a wildcard that you can use to replace all enhanced for loops, especially nested ones.
Your error occurs because you are trying to call forEach on the return value of forEach. Since your for loops are nested, the calls to forEach should also be nested in the stream version. The second for loop should be put in a place like this:
.forEach(countries -> countries.getFromZone().getCountries().stream().filter(country ->country.getCode().equals(selectedCountry).forEach(...))
But seriously, Don't do this.
Your code is very messy in the stream version. It is far less readable than the for loops, mainly because you have a nested for loop. Instead of trying to rewrite your code using streams, you should try to abstract out the logic of your current code. Extract some methods for example:
for (Rate rate : product.getrates()) {
if (rateMatches(value)) { // I tried to guess what you are trying to do here. If you have better names please use yours
for (Countrys countrys : rate.getFromCountry().getCountries()) {
if (countrys.getCode().equals(selectedCountry)) {
updateDisplay(value);
break;
}
}
}
}
This way it's much more clearer.
Don't complicate too much, think of it on simple terms. Keep in mind streams are also about making easier to follow code:
find all Rate/Countrys pairs that match your criteria
For each of them, update value accordingly.
Java streams approach (there are more alternatives):
public void yourMethod() {
X product = ...;
Y value = ...;
Z selectedCountry = ...;
if (product.getRates() == null || product.getRates().isEmpty()) {
return;
}
product.getRates().stream()
.filter(r -> matchesValueRate(r, value))
.flatMap(this::rateCountrysPairStream)
.filter(p -> matchesSelectedCountry(p, selectedCountry))
.forEach(p -> updateValue(p, v));
}
public boolean matchesValueRate(Rate candidate, Y value) {
return value.getAtrribute().getRateType().getCode().equalsIgnoreCase(candidate.getRateType().getCode()) && ...; // add your tzone filter also
}
public Stream<Pair<Rate, Countrys>> rateCountrysPairStream(Rate rate) {
return rate.getFromCountry().getCountries().stream().map(c -> Pair.of(rate, c));
}
public boolean matchesSelectedCountry(Pair<Rate, Countrys> candidate, Z selectedCountry) {
return selectedCountry.equals(candidate.second().getCode());
}
public void updateValue(Pair<Rate, Countrys> rateCountry, Y value) {
Rate rate = rateCountry.first();
Countrys country = rateCountry.second();
// do your display stuff here
}
public static class Pair<K, V> {
private final K first;
private final V second;
private Pair(K first, V second) {
this.first = first;
this.second = second;
}
public static <K, V> Pair<K, V> of(K first, V second) {
return new Pair<>(first, second);
}
public K first() {
return first;
}
public V second() {
return second;
}
}
Suppose I have two proto buffer types:
message MessageType1 {
SomeType1 field1 = 1;
SomeType2 field2 = 2;
SomeType3 field3 = 3;
}
message MessageType2 {
SomeType1 field1 = 1;
SomeType2 field2 = 2;
SomeType4 field4 = 3;
}
Then in Java I would like to be able to use one object as a template to another:
MessageType1 message1 = ...;
MessageType2 message2 = MessageType2.newBuilder()
.usingTemplate(message1) // sets field1 & field2 only
.setField4(someValue)
.build()
instead of
MessageType1 message1 = ...;
MessageType2 message2 = MessageType2.newBuilder()
.setField1(message1.getField1())
.setField2(message1.getField2())
.setField4(someValue)
.build()
Why do I need this? My gRPC service is designed to take incoming data of one type (message1) which is almost identical to another message of a different type (message2) -- which needs to be sent out. The amount of identical fields is huge and copy code is mundane. Manual solution also has a disadvantage of a miss if a new field gets added.
There exists a template method (object.newBuilder(template)) which allows templating object of the same type, but how about templating between different types?
I could, of course, write a small reflection utility which inspects all members (methods?) and manually copies data over, but generated code looks discouraging and ugly for this sort of quest.
Is there any good approach to tackle this?
It turned out to be not so complicated. I wrote a small utility which would evaluate and match FieldDescriptors (something that gRPC generates). In my world it is enough to match them by name and type. Full solution here:
/**
* Copies fields from source to dest. Only copies fields if they are set, have matching name and type as their counterparts in dest.
*/
public static void copyCommonFields(#Nonnull GeneratedMessageV3 source, #Nonnull com.google.protobuf.GeneratedMessageV3.Builder<?> destBuilder) {
Map<FieldDescriptorKeyElements, Descriptors.FieldDescriptor> elementsInSource = Maps.uniqueIndex(source.getDescriptorForType().getFields(), FieldDescriptorKeyElements::new);
Map<FieldDescriptorKeyElements, Descriptors.FieldDescriptor> elementsInDest = Maps.uniqueIndex(destBuilder.getDescriptorForType().getFields(), FieldDescriptorKeyElements::new);
// those two above could even be cached if necessary as this is static info
Set<FieldDescriptorKeyElements> elementsInBoth = Sets.intersection(elementsInSource.keySet(), elementsInDest.keySet());
for (Map.Entry<Descriptors.FieldDescriptor, Object> entry : source.getAllFields().entrySet()) {
Descriptors.FieldDescriptor descriptor = entry.getKey();
FieldDescriptorKeyElements keyElements = new FieldDescriptorKeyElements(descriptor);
if (entry.getValue() != null && elementsInBoth.contains(keyElements)) {
destBuilder.setField(elementsInDest.get(keyElements), entry.getValue());
}
}
}
// used for convenient/quick lookups in a Set
private static final class FieldDescriptorKeyElements {
final String fieldName;
final Descriptors.FieldDescriptor.JavaType javaType;
final boolean isRepeated;
private FieldDescriptorKeyElements(Descriptors.FieldDescriptor fieldDescriptor) {
this.fieldName = fieldDescriptor.getName();
this.javaType = fieldDescriptor.getJavaType();
this.isRepeated = fieldDescriptor.isRepeated();
}
#Override
public int hashCode() {
return Objects.hash(fieldName, javaType, isRepeated);
}
#Override
public boolean equals(Object obj) {
if (obj == null || !(obj instanceof FieldDescriptorKeyElements)) {
return false;
}
FieldDescriptorKeyElements other = (FieldDescriptorKeyElements) obj;
return Objects.equals(this.fieldName, other.fieldName) &&
Objects.equals(this.javaType, other.javaType) &&
Objects.equals(this.isRepeated, other.isRepeated);
}
}
Answering your specific question: no, there is no template based way to do this. However, there are some other ways to get the same effect:
If you don't care about performance and the field numbers are the same between the messages, you can serialize the first message to bytes and deserialize them back as the new message. This requires that all the fields in the first message must match the type and id number of those in the second message (though, the second message can have other fields). This is probably not a good idea.
Extract the common fields to another message, and share that message. For example:
proto:
message Common {
SomeType1 field1 = 1;
SomeType2 field2 = 2;
SomeType3 field3 = 3;
}
message MessageType1 {
Common common = 1;
// ...
}
message MessageType2 {
Common common = 1;
// ...
}
Then, you can share the messages in code:
MessageType1 message1 = ...;
MessageType2 message2 = MessageType2.newBuilder()
.setCommon(message1.getCommon())
.build();
This is the probably the better solution.
Lastly, as you mentioned, you could resort to reflection. This is probably the most verbose and slowest way, but it would allow you the most control (aside from manually copying over the fields). Not recommended.
Imagine a Person class with a boolean flag indicating whether or not the person is employable - set to false by default.
public class Person{
boolean employable = false;
...
}
Now imagine having some external boolean methods which act on Person objects. For example, consider static boolean methods in a utility class.
public class PersonUtil{
public static boolean ofWorkingAge(Person p){
if(p.getAge() > 16) return true;
return false;
}
...
}
Boolean static methods are in essence analogous to boolean valued functions i.e. predicates.
We can construct a 2^(#predicates)-by-#predicates truth table out of predicates. For example, given three predicates: ofWorkingAge, ofGoodCharacter, isQualified we can construct the following 8-by-3 truth table:
T T T
T T F
T F T
T F F
F T T
F T F
F F T
F F F
We now want to employ people with desirable qualities. Let + indicate that we wish to consider somebody employable (i.e. set their employability flag to true) and - the opposite.
T T T | +
T T F | +
T F T | +
T F F | -
F T T | +
F T F | -
F F T | -
F F F | -
Now imagine having a collection of Person objects. For each person we adjust their employability flag according to the three predicates. We also update a count (this forces us to use the entire truth table instead of just the positives), so that given 1,000 people we want to end up with something like:
T T T | + 100
T T F | + 200
T F T | + 50
T F F | - 450
F T T | + 50
F T F | - 50
F F T | - 50
F F F | - 50
Presumably this can be thought of as filtering with truth tables. Setting employability flags and updating counts is a rather contrived example but you can easily see how we might instead want to set and update much more complicated things.
QUESTION
Is there a way of elegantly doing this? I can think of two solutions:
Clunky solution
Have a giant hand coded if, else if, else chain.
if(ofWorkingAge && ofGoodCharacter && isQualified){
c1++;
p.setEmployable(true)
}
else if(ofWorkingAge && ofGoodCharacter && !isQualified){
c2++;
p.setEmployable(true)
}
...
else if(!ofWorkingAge && !ofGoodCharacter && isQualified){
c7++;
}
else{
c8++;
}
This is just bad.
Slightly smarter solution
Pass predicates (perhaps in an array) and a collection of sentences to a method. Let the method generate the corresponding truth table. Loop over the people, set their employability, and return an array of counts.
I can see how things could be done with functional interfaces. This SO answer is potentially relevant. You could change PrintCommand to IsQualified and pass callCommand a Person instead of a string. But this also seems kindah clunky because we'd then have to have a new interface file for every predicate we come up with.
Is there any other Java 8-ish way of doing this?
Let's start with the list of predicates you have:
List<Predicate<Person>> predicates = Arrays.<Predicate<Person>> asList(
PersonUtil::ofWorkingAge, PersonUtil::ofGoodCharacter,
PersonUtil::isQualified);
To track which predicate is true or false, let's attach names to them creating NamedPredicate class:
public static class NamedPredicate<T> implements Predicate<T> {
final Predicate<T> predicate;
final String name;
public NamedPredicate(Predicate<T> predicate, String name) {
this.predicate = predicate;
this.name = name;
}
#Override
public String toString() {
return name;
}
#Override
public boolean test(T t) {
return predicate.test(t);
}
}
(one may attach BitSet or something like this for efficiency, but String names are also fine).
Now we need to generate a truth table which is a new list of predicates having names like "T T F" and able to apply the given combination of source predicates, negated or not. This can be generated easily with a bit of functional programming magic:
Supplier<Stream<NamedPredicate<Person>>> truthTable
= predicates.stream() // start with plain predicates
.<Supplier<Stream<NamedPredicate<Person>>>>map(
// generate a supplier which creates a stream of
// true-predicate and false-predicate
p -> () -> Stream.of(
new NamedPredicate<>(p, "T"),
new NamedPredicate<>(p.negate(), "F")))
.reduce(
// reduce each pair of suppliers to the single supplier
// which produces a Cartesian product stream
(s1, s2) -> () -> s1.get().flatMap(np1 -> s2.get()
.map(np2 -> new NamedPredicate<>(np1.and(np2), np1+" "+np2))))
// no input predicates? Fine, produce empty stream then
.orElse(Stream::empty);
as truthTable is a Supplier<Stream>, you can reuse it as many times as you want. Also note that all the NamedPredicate objects are generated on the fly by demand, we don't store them anywhere. Let's try to use this supplier:
truthTable.get().forEach(System.out::println);
The output is:
T T T
T T F
T F T
T F F
F T T
F T F
F F T
F F F
Now you can classify the persons collection by the truth table, for example, in the following way:
Map<String,List<Person>> map = truthTable.get().collect(
Collectors.toMap(np -> np.toString(), // Key is string like "T T F"
// Value is the list of persons for which given combination is true
np -> persons.stream().filter(np).collect(Collectors.toList()),
// Merge function: actually should never happen;
// you may throw assertion error here instead
(a, b) -> a,
// Use LinkedHashMap to preserve an order
LinkedHashMap::new));
Now you can easily get the counts:
map.forEach((k, v) -> System.out.println(k+" | "+v.size()));
To update the employable field we need to know how the desired truth table is specified. Let it be the collection of truth strings like this:
Collection<String> desired = Arrays.asList("T T T", "T T F", "T F T", "F T T");
In this case you may use the previously generated map:
desired.stream()
.flatMap(k -> map.get(k).stream())
.forEach(person -> person.setEmployable(true));
Basically, a truth value is a single bit and you can always use an integer value of n bits to encode n truth value. Then, interpreting the integer value as a number allows you to associate values with the combination of truth values using a linear table.
So using an int a encoded truth value/ table index, a generic truth table class may look like this:
public class TruthTable<O,V> {
final List<? extends Predicate<? super O>> predicates;
final ArrayList<V> values;
#SafeVarargs
public TruthTable(Predicate<? super O>... predicates) {
int size=predicates.length;
if(size==0 || size>31) throw new UnsupportedOperationException();
this.predicates=Arrays.stream(predicates)
.map(Objects::requireNonNull).collect(Collectors.toList());
values=new ArrayList<>(Collections.nCopies(1<<size, null));
}
public V get(O testable) {
return values.get(index(testable, predicates));
}
public V get(boolean... constant) {
if(constant.length!=predicates.size())
throw new IllegalArgumentException();
return values.get(index(constant));
}
public V set(V value, boolean... constant) {
if(constant.length!=predicates.size())
throw new IllegalArgumentException();
return values.set(index(constant), value);
}
public static <T> int index(T object, List<? extends Predicate<? super T>> p) {
int size=p.size();
if(size==0 || size>31) throw new UnsupportedOperationException();
return IntStream.range(0, size).map(i->p.get(i).test(object)? 1<<i: 0)
.reduce((a,b) -> a|b).getAsInt();
}
public static <T> int index(boolean... values) {
int size=values.length;
if(size==0 || size>31) throw new UnsupportedOperationException();
return IntStream.range(0, size).map(i->values[i]? 1<<i: 0)
.reduce((a,b) -> a|b).getAsInt();
}
}
The key point is the calculation of the int index from truth values. There are two versions. First, calculate from explicit boolean values for initializing the table or querying its state, second, for an actual test object and the list of applicable predicates. Note that these two methods are factored out into public static methods so that they can be used for alternative table types, e.g. an array of primitive values. The only thing to do is to create a linear storage for 2ⁿ values when you have n predicates, e.g. new int[1<<n] and then using these index methods for determining the entry to access for given values or an actual test candidate.
Instances of the generic TruthTable can be used as follows:
TruthTable<Person,Integer> scoreTable=new TruthTable<>(
PersonUtil::ofWorkingAge, PersonUtil::ofGoodCharacter, PersonUtil::isQualified);
scoreTable.set(+100, true, true, true);
scoreTable.set(+200, true, true, false);
scoreTable.set(+50, true, false, true);
scoreTable.set(-450, true, false, false);
scoreTable.set(+50, false, true, true);
scoreTable.set(-50, false, true, false);
scoreTable.set(-50, false, false, true);
scoreTable.set(-50, false, false, false);
Person p = …
int score = scoreTable.get(p);
I'm not sure if this is what you're looking for, but you could use a bitwise operators on your variables..
if(ofWorkingAge && ofGoodCharacter && isQualified){
c1++;
p.setEmployable(true)
}
might become
int combined = 0b00000000;
combined |= ofWorkingAge ? 0b00000100 : 0b00000000;
combined |= ofGoodCharacter ? 0b00000010 : 0b00000000;
combined |= isQualified ? 0b00000001 : 0b00000000;
switch (combined){
case 0b00000111:
c1++;
p.setEmployable(true)
break;
case 0b00000110:
// etc
where the last bits represent ofWorkingAge/ofGoodCharacter/isQualified.