I have multiple Optionals that must be mapped to a POJO. Is there a better alternative than the following?
class SimplePojo {
private String stringField;
private Integer integerField;
// All args. constructor, getter, setter
}
Optional<String> stringOptional = ...
Optional<Integer> integerOptional = ...
Optional<SimplePojo> simplePojoOptional = stringOptional.flatMap(
string -> integerOptional.map(integer -> new SimplePojo(string, integer)))
I have reduced the problem to 2 Optionals in the above example to keep it short. But I actually have 3 Optionals with more on the way. I am afraid the last line can easily become unwieldy soon.
Please note: Use of functional frameworks like Vavr or Functional Java is not an option for me.
How about using a Builder ?
class SimplePojo {
public static class Builder {
private String stringField;
public Builder withStringField(String str) {
this.stringField = str;
return this;
}
// and other "with" methods...
public Optional<SimplePojo> build() {
if (stringField == null || anotherField == null /* and so forth */) {
return Optional.empty();
} else {
return Optional.of(new SimplePojo(this));
}
}
}
private final String stringField;
/* private constructor, so client code has to go through the Builder */
private SimplePojo(Builder builder) {
this.stringField = builder.stringField;
// etc.
}
}
Then you could use it as follows:
SimplePojo.Builder builder = new SimplePojo.builder();
optionalStringField.ifPresent(builder::withStringField);
// etc.
return builder.build();
I do not see any advantage from pursuing the functional style this way here. see three options:
ONE: If you can alter the SimplePojo class and if this scenario is a common one, you might consider to add a factory method to the SimplePojo:
class SimplePojo {
public static Optional<SimplePojo> of(final Optional<String> stringField, final Optional<Integer> integerField) {
if (stringField.isPresent() && integerField.isPresent()) {
return new SimplePojo(stringField.get(), integerField.get());
else
return Optional.empty();
}
}
TWO: If you cannot alter the SimplePojo, you might want to create this as a utility method somewhere else. If you need this pattern only in one class, make the method private in this class!
THREE: If you need to do this only once or twice, I would prefer the if...then construction from the first option over the functional notation you used for the sake of readability:
final Optional<SimplePojo> simplePojoOptional;
if (stringField.isPresent() && integerField.isPresent()) {
simplePojoOptional = new SimplePojo(stringField.get(), integerField.get());
else
simplePojoOptional = Optional.empty();
Related
I have an OOP approach to calculating a special code. There is a list of strategies that uses the chain of responsibility approach to calculate my value;
interface ChainStrategy {
Strategy getNext();
String getCode(SomeDto dto);
default String getDefaultVlue() {
return "";
};
}
class StrategyA implements ChainStrategy {
Strategy next;
StrategyA() {}
StrategyA(Strategy next) {
this.next = next;
}
Strategy getNext() {
return next;
}
public String getCode(SomeDto dto) {
if(dto.isA()) {
String result = dto.getA();
//this code could be placed in the abstract class to fulfill DRY
if(result == null) {
if(next!=null) {
result = next.getCode(dto);
}
else {
result = getDefaultVlue();
}
}
return result;
}
}
class StrategyB implements ChainStrategy {
// mostly the same code with different result calculation logic
}
class Client {
ChainStrategy strategy = new StrategyA(new StrategyB());
System.out.println(strategy.getCode())
}
}
This is "Java < 8" code that meets SOLID principles and can be easily tested. Usually, the real logic is more complicated than just dto.getA()
But it is just a chain of functions so I rewrite it:
interface ChainStrategy {
String getCode(SomeDto dto);
}
class CombineStrategy implements ChainStrategy {
private static final Function<SomeDto, Optional<String>> STRATEGY_A = dto -> Optional.of(dto).filter(SomeDto::isA).map(SomeDto::getA());
private static final Function<SomeDto, Optional<String>> STRATEGY_B = dto -> Optional.of(dto).filter(SomeDto::isB).map(SomeDto::getB());
private static final Function<SomeDto, String> STRATEGY_DEFAULT = dto -> "";
String getCode(SomeDto dto) {
Stream.of(STRATEGY_A, STRATEGY_B).map(st->st.apply(dto))
.filter(Optional::isPresent)
.map(Optional::get)
.findFirst()
.orElseGet(() -> STRATEGY_DEFAULT.apply(dto));
}
}
And my questions:
This code has problems with a single responsibility and "open-close" principles. And I can't test my functions individually. But creating separate classes for my functions looks like an overhead. Do we need these principles in functional programming?
I can rewrite "String getCode" to another static function. And store all these functions as a static Util class. But I don't want to lose ability to dynamically substitute my ChainFunction in the runtime. How do people combine static functions and dynamic binding in functional languages?
Let's assume I have a class Person
public class Person {
private final String name;
private final int age;
private boolean rejected;
private String rejectionComment;
public void reject(String comment) {
this.rejected = true;
this.rejectionComment = comment;
}
// constructor & getters are ommited
}
and my app is something like that
class App {
public static void main(String[] args) {
List<Person> persons = Arrays.asList(
new Person("John", 10),
new Person("Sarah", 20),
new Person("Daniel", 30)
)
persons.forEach(p -> {
rejectIfYoungerThan15(p);
rejectIfNameStartsWithD(p);
// other rejection functions
}
}
private static void rejectIfYoungerThan15(Person p) {
if (!p.isRejected() && p.getAge() < 15) {
p.reject("Too young")
}
}
private static void rejectIfNameStartsWithD(Person p) {
if (!p.isRejected() && p.getName().startsWith("D")) {
p.reject("Name starts with 'D'")
}
}
// other rejection functions
}
The thing is I don't like that I have to perform !p.isRejected() check in every rejection function. Moreover, it doesn't make sense to pass an already rejected person to next filters.
So my idea is to use a mechanism of Stream.filter and make something like
persons.stream().filter(this::rejectIfYoungerThan15).filter(this::rejectIfNameStartsWithD)...
And change signature for these methods to return true if a passed Person has not been rejected and false otherwise.
But it seems to me that it's a very bad idea to use filter with non-pure functions.
Do you have any ideas of how to make it in more elegant way?
When you change the check functions to only check the condition (i.e. not to call p.isRejected()) and return boolean, you already made the necessary steps to short-circuit:
private static boolean rejectIfYoungerThan15(Person p) {
if(p.getAge() < 15) {
p.reject("Too young");
return true;
}
return false;
}
private static boolean rejectIfNameStartsWithD(Person p) {
if(p.getName().startsWith("D")) {
p.reject("Name starts with 'D'");
return true;
}
return false;
}
usable as
persons.forEach(p -> {
if(rejectIfYoungerThan15(p)) return;
if(rejectIfNameStartsWithD(p)) return;
// other rejection functions
}
}
A Stream’s filter operation wouldn’t do anything other than checking the returned boolean value and bail out. But depending on the Stream’s actual terminal operation the short-circuiting could go even farther and end up in not checking all elements, so you should not bring in a Stream operation here.
Calling these methods from lambda is fine, however, for better readability, you can rename these methods to show what they are doing and return boolean, e.g.:
private boolean hasEligibleAge(Person p){..}
private boolean hasValidName(Person p){..}
Another approach would be to wrap these methods into another method (to reflect the business logic/flow), e.g.:
private boolean isEligible(Person p){
//check age
//check name
}
You should make Person immutable, and let the reject-methods return a new Person. That will allow you to chain map-calls. Something like this:
public class Person {
private final String name;
private final int age;
private final boolean rejected;
private final String rejectionComment;
public Person reject(String comment) {
return new Person(name, age, true, comment);
}
// ...
}
class App {
// ...
private static Person rejectIfYoungerThan15(Person p) {
if (!p.isRejected() && p.getAge() < 15) {
return p.reject("Too young");
}
return p;
}
}
Now you can do this:
persons.stream()
.map(App::rejectIfYoungerThan15)
.map(App::rejectIfNameStartsWithD)
.collect(Collectors.toList());
If you want to remove rejected persons, you can add a filter after the mapping:
.filter(person -> !person.isRejected())
EDIT:
If you need to short circuit the rejections, you could compose your rejection functions into a new function and make it stop after the first rejection. Something like this:
/* Remember that the stream is lazy, so it will only call new rejections
* while the person isn't rejected.
*/
public Function<Person, Person> shortCircuitReject(List<Function<Person, Person>> rejections) {
return person -> rejections.stream()
.map(rejection -> rejection.apply(person))
.filter(Person::isRejected)
.findFirst()
.orElse(person);
}
Now your stream can look like this:
List<Function<Person, Person>> rejections = Arrays.asList(
App::rejectIfYoungerThan15,
App::rejectIfNameStartsWithD);
List<Person> persons1 = persons.stream()
.map(shortCircuitReject(rejections))
.collect(Collectors.toList());
We are using the builder pattern to create some input for service, and it looks like something like this (simplified):
final SomeInput input = SomeInput.builder()
.withSomeId(....)
.withSomeState(....)
...
.build();
There's some attribute that we want to set in SomeInput, but only if it is present. So after creating the object, I do something like this:
Optional<String> secondaryId = infoProvider.getSecondaryId();
if (secondaryId.isPresent()) {
input.setSecondaryId(secondaryId.get());
}
I was wondering:
a) Is there a better/cleaner way to do this?
b) If I do need to do it this way, can I avoid the "if" statement and utilize some functionality with Optional?
(Note: I cannot change the builder itself, and I cannot that the secondaryId is a String, but that what we retrieve from infoProvider is an optional)
A little bit cleaner would be to use ifPresent
secondaryId.ifPresent(input::setSecondaryId);
but that's pretty much the best you can get with these requirements.
I was just facing the same problem as the OP and came up with this abstraction, which integrates directly with the builder instead of later modifying the object via setters. It would work the same with a model that instead of builders just offers "wither" methods.
(using lombok)
#RequiredArgsConstructor(access = AccessLevel.PRIVATE)
class Modifier<T> {
private final T value;
public static <T> Modifier<T> modify(T initialValue) {
return new Modifier<>(initialValue);
}
public <U> Modifier<T> ifPresent(Optional<U> optional, BiFunction<T, U, T> modifier) {
return modify(optional.map(input -> modifier.apply(value, input)).orElse(value));
}
public T get() {
return value;
}
}
Applied to the OP's example this would be used like this (again using lombok for generating the builder):
import static Modifier.modify;
import static org.junit.Assert.assertEquals;
class ModifierTest {
#Value
#Builder
static class SomeInput {
String id;
String secondaryId;
String state;
}
SomeInput constructSomeInput(Optional<String> maybeSecondaryId, Optional<String> maybeState) {
final SomeInput result = modify(SomeInput.builder().id("myId"))
.ifPresent(maybeSecondaryId, (builder, secondaryId) -> builder.secondaryId(secondaryId))
.ifPresent(maybeState, (builder, state) -> builder.state(state))
.get()
.build();
return result;
}
#Test
public void shouldBuildSomeInputWithSecondaryId() {
final Optional<String> maybeSecondaryId = Optional.of("mySecondaryId");
final Optional<String> maybeState = Optional.of("myState");
final SomeInput result = constructSomeInput(maybeSecondaryId, maybeState);
assertEquals("mySecondaryId", result.getSecondaryId());
assertEquals("myState", result.getState());
}
#Test
public void shouldBuildSomeInputWithoutSecondaryId() {
final Optional<String> maybeSecondaryId = Optional.empty();
final Optional<String> maybeState = Optional.of("myState");
final SomeInput result = constructSomeInput(maybeSecondaryId, maybeState);
assertEquals(null, result.getSecondaryId());
assertEquals("myState", result.getState());
}
}
I have the following classes:
class ServiceSnapshot {
List<ExchangeSnapshot> exchangeSnapshots = ...
...
}
class ExchangeSnapshot{
Map<String, String> properties = ...
...
}
SayI have a collection of ServiceSnapshots, like so:
Collection<ServiceSnapshot> serviceSnapshots = ...
I'd like to filter the collection so that the resulting collection of ServiceSnapshots only contains ServiceSnapshots that contain ExchangeSnapshots where a property on the ExchangeSnapshots matches a given String.
I have the following untested code, just wondering is there a cleaner/more readable way to do this, using Java 7, and maybe Google Guava if necessary?
Updtae: Note also that the code sample I've provided below isn't suitable for my purposes, since I'm using iterator.remove() to filter the collection. It turns out I cannot do this as it is modifying the underlying collection , meaning subsequent calls to my method below result in fewer and fewer snashots due to previous calls removing them from the collection - this is not what I want.
public Collection<ServiceSnapshot> getServiceSnapshotsForComponent(final String serviceId, final String componentInstanceId) {
final Collection<ServiceSnapshot> serviceSnapshots = getServiceSnapshots(serviceId);
final Iterator<ServiceSnapshot> serviceSnapshotIterator = serviceSnapshots.iterator();
while (serviceSnapshotIterator.hasNext()) {
final ServiceSnapshot serviceSnapshot = (ServiceSnapshot) serviceSnapshotIterator.next();
final Iterator<ExchangeSnapshot> exchangeSnapshotIterator = serviceSnapshot.getExchangeSnapshots().iterator();
while (exchangeSnapshotIterator.hasNext()) {
final ExchangeSnapshot exchangeSnapshot = (ExchangeSnapshot) exchangeSnapshotIterator.next();
final String foundComponentInstanceId = exchangeSnapshot.getProperties().get("ComponentInstanceId");
if (foundComponentInstanceId == null || !foundComponentInstanceId.equals(componentInstanceId)) {
exchangeSnapshotIterator.remove();
}
}
if (serviceSnapshot.getExchangeSnapshots().isEmpty()) {
serviceSnapshotIterator.remove();
}
}
return serviceSnapshots;
}
Using Guava:
Iterables.removeIf(serviceSnapshots, new Predicate<ServiceSnapshot>() {
#Override
public boolean apply(ServiceSnapshot serviceSnapshot) {
return !Iterables.any(serviceSnapshot.getExchangeSnapshots(), new Predicate<ExchangeSnapshot>() {
#Override
public boolean apply(ExchangeSnapshot exchangeSnapshot) {
String foundComponentInstanceId = exchangeSnapshot.getProperties().get("ComponentInstanceId");
return foundComponentInstanceId != null && foundComponentInstanceId.equals(componentInstanceId);
}
});
}
});
I may have a ! missing or inverted somewhere, but the basic strategy is to remove any ServiceSnapshot objects that do not have any ExchangeSnapshot whose ID matches.
Can someone get me out of LambdaJ pit I fell into please?
let's assume I have a list of objects of this class:
private class TestObject {
private String A;
private String B;
//gettters and setters
}
Let's say I want to select the objects from the list where A.equals(B)
I tried this:
List<TestObject> theSameList = select(testList, having(on(TestObject.class).getA(), equalTo(on(TestObject.class).getB())));
but this returns an empty list
And this:
List<TestObject> theSameList = select(testList, having(on(TestObject.class).getA().equals(on(TestObject.class).getB())));
but that throws an exception [EDIT: due to known limitations of proxying final classes]
Note, One way of getting around this is to have a method that compares the two fields inside the TestObject, but let's assume I cannot do this for a reason of your choice.
What am I missing?
After poking and fiddling with LambdaJ to match on the fields of the same object, the only solution that is working for me is writing a custom matcher. Here's quick and dirty implementation of one that would do the job:
private Matcher<Object> hasPropertiesEqual(final String propA, final String propB) {
return new TypeSafeMatcher<Object>() {
public void describeTo(final Description description) {
description.appendText("The propeties are not equal");
}
#Override
protected boolean matchesSafely(final Object object) {
Object propAValue, propBValue;
try {
propAValue = PropertyUtils.getProperty(object, propA);
propBValue = PropertyUtils.getProperty(object, propB);
} catch(Exception e) {
return false;
}
return propAValue.equals(propBValue);
}
};
}
The PropertyUtils is the class from org.apache.commons.beanutils
The way to use this matcher:
List<TestObject> theSameList = select(testList, having(on(TestObject.class), hasPropertiesEqual("a", "b")));