Model
public class Person {
private Car car;
public Car getCar() {
return car;
}
}
public class Car {
private Insurance insurance;
public Insurance getInsurance() {
return insurance;
}
}
Model p.2
public class Insurance {
private String name;
public String getName() {
return name;
}
}
Implementation
public interface InsuranceFinder {
String findInsuranceName(Person person);
}
public class NaiveInsuranceFinder implements InsuranceFinder {
public String findInsuranceName(Person person) {
return person.getCar().getInsurance().getName();
}
}
Person notInsured = new Person(new Car(null));
InsuranceFinder finder = new NaiveInsuranceFinder();
finder.findInsuranceName(notInsured);
Person notInsured = new Person(new Car(null));
InsuranceFinder finder = new NaiveInsuranceFinder();
finder.findInsuranceName(notInsured);
java.lang.NullPointerException
at org.insurance.finder.impl.NaiveInsuranceFinder.findInsuranceName(NaiveInsuranceFinder.java:9)
at org.insurance.finder.impl.NaiveInsuranceFinderTest.testFindInsurance(NaiveInsuranceFinderTest.java:21)
public class DeepDoubtsInsuranceFinder implements InsuranceFinder {
public String findInsuranceName(Person person) {
if (person != null) {
Car car = person.getCar();
if (car != null) {
Insurance insurance = car.getInsurance();
if (insurance != null) {
String insuranceName = insurance.getName();
if (insuranceName != null) {
return insuranceName;
}
}
}
}
return "Unknown";
}
}
public class TooManyChoicesInsuranceFinder implements InsuranceFinder {
private static final String UNKNOWN = "Unknown";
public String findInsuranceName(Person person) {
if (person == null)
return UNKNOWN;
Car car = person.getCar();
if (car == null)
return UNKNOWN;
Insurance insurance = car.getInsurance();
if (insurance == null)
return UNKNOWN;
String insuranceName = insurance.getName();
if (insuranceName == null)
return UNKNOWN;
return insuranceName;
}
}
public class Optional<T> {
private static final Optional<?> EMPTY = new Optional<>(null);
private T value;
private Optional(T value) { this.value = value; }
public static <T> Optional<T> of(T value) {
return value == null ? EMPTY : new Optional<>(value);
}
public boolean isPresent() {
return value != null;
}
public T get() {
if (value == null)
throw new NoSuchElementException("No value");
return value;
}
public T orElse(T elseValue) {
return isPresent() ? value : elseValue;
}
public <U> Optional<U> flatMap(Function<T, Optional<U>> function) {
Objects.requireNonNull(function);
if (isPresent())
return Objects.requireNonNull(function.apply(value));
return EMPTY;
}
public <U> Optional<U> map(Function<T, U> function) {
Objects.requireNonNull(function);
if (isPresent())
return of(function.apply(value));
return EMPTY;
}
}
public class Person {
private Optional<Car> car;
public Optional<Car> getCar() {
return car;
}
}
public class Car {
private Optional<Insurance> insurance;
public Optional<Insurance> getInsurance() {
return insurance;
}
}
public class Insurance {
private final String name;
public Insurance(final String name) {
Objects.requireNonNull(name);
this.name = name;
}
public String getName() {
return name;
}
}
public interface InsuranceFinder {
String findInsuranceName(Optional<Person> person);
}
public class NotExactlyCorrectInsuranceFinder implements InsuranceFinder {
@Override
public String findInsuranceName(Optional<Person> person) {
if (person.isPresent()) {
Optional<Car> car = person.get().getCar();
if (car.isPresent()) {
Optional<Insurance> insurance = car.get().getInsurance();
if (insurance.isPresent()) {
return insurance.get().getName();
}
}
}
return "Unknown";
}
}
public class MonadicInsuranceFinder implements InsuranceFinder {
public String findInsuranceName(Optional<Person> person) {
return person.flatMap(new Function<Person, Optional<Car>>() {
public Optional<Car> apply(Person person1) {
return person1.getCar();
}
}).flatMap(new Function<Car, Optional<Insurance>>() {
public Optional<Insurance> apply(Car car) {
return car.getInsurance();
}
}).map(new Function<Insurance, String>() {
public String apply(Insurance insurance) {
return insurance.getName();
}
}).orElse("Unknown");
}
}
public class MonadicInsuranceFinder implements InsuranceFinder {
@Override
public String findInsuranceName(Optional<Person> person) {
return person
.flatMap(Person::getCar)
.flatMap(Car::getInsurance)
.map(Insurance::getName)
.orElse("Unknown");
}
}
public class MonadicInsuranceFinder implements InsuranceFinder {
public String findInsuranceName(Optional<Person> person) {
return person
.flatMap(Person::getCar)
.flatMap(Car::getInsurance)
.map(Insurance::getName)
.orElse("Unknown");
}
}
public class MonadicInsuranceFinder implements InsuranceFinder {
public String findInsuranceName(Optional<Person> person) {
return person
.flatMap(Person::getCar)
.flatMap(Car::getInsurance)
.map(Insurance::getName)
.orElse("Unknown");
}
}
public class MonadicInsuranceFinder implements InsuranceFinder {
public String findInsuranceName(Optional<Person> person) {
return person
.flatMap(Person::getCar)
.flatMap(Car::getInsurance)
.map(Insurance::getName)
.orElse("Unknown");
}
}
public class MonadicInsuranceFinder implements InsuranceFinder {
public String findInsuranceName(Optional<Person> person) {
return person
.flatMap(Person::getCar)
.flatMap(Car::getInsurance)
.map(Insurance::getName)
.orElse("Unknown");
}
}
public class MonadicInsuranceFinder implements InsuranceFinder {
public String findInsuranceName(Optional<Person> person) {
return person
.flatMap(Person::getCar)
.flatMap(Car::getInsurance)
.map(Insurance::getName)
.orElse("Unknown");
}
}
public class Dish {
private int calories;
private String name;
public int getCalories() {
return calories;
}
public String getName() {
return name;
}
}
public class Java7DishFinder {
public List<String> findOrderedLowCaloriesDishesNames(List<Dish> menu) {
List<Dish> lowCaloriesDishes = new ArrayList<>();
for (Dish dish : menu) {
if (dish.getCalories() < 400)
lowCaloriesDishes.add(dish);
}
Collections.sort(lowCaloriesDishes, new Comparator<Dish>() {
public int compare(Dish d1, Dish d2) {
return Integer.compare(d1.getCalories(), d2.getCalories());
}
});
List<String> lowCaloriesDishesNames = new ArrayList<>();
for (Dish dish : lowCaloriesDishes) {
lowCaloriesDishesNames.add(dish.getName());
}
return lowCaloriesDishesNames;
}
}
public class DishFinder {
public List<String> findOrderedLowCaloriesDishes(List<Dish> menu) {
return menu
.stream()
.filter(d -> d.getCalories() < 400)
.sorted(Comparator.comparing(Dish::getCalories))
.map(Dish::getName)
.collect(Collectors.toList());
}
}
Monad is an abstract data type that has two operations: unit and bind
M<A> unit(A, a);
M<B> bind(M<A> ma, Function<A, M<B>> f);
interface M {
default M<B> map(Function<A, B> f) {
return bind(x -> unit(f.apply(x)));
}
M<B> bind(Function<A, M<B>> f)
}