All Downloads are FREE. Search and download functionalities are using the official Maven repository.

griffon.javafx.beans.binding.MappingBindings Maven / Gradle / Ivy

/*
 * Copyright 2008-2017 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package griffon.javafx.beans.binding;

import javafx.beans.binding.BooleanBinding;
import javafx.beans.binding.DoubleBinding;
import javafx.beans.binding.FloatBinding;
import javafx.beans.binding.IntegerBinding;
import javafx.beans.binding.LongBinding;
import javafx.beans.binding.ObjectBinding;
import javafx.beans.binding.StringBinding;
import javafx.beans.value.ObservableBooleanValue;
import javafx.beans.value.ObservableDoubleValue;
import javafx.beans.value.ObservableFloatValue;
import javafx.beans.value.ObservableIntegerValue;
import javafx.beans.value.ObservableLongValue;
import javafx.beans.value.ObservableObjectValue;
import javafx.beans.value.ObservableStringValue;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;

import static java.util.Objects.requireNonNull;
import static javafx.beans.binding.Bindings.createBooleanBinding;
import static javafx.beans.binding.Bindings.createDoubleBinding;
import static javafx.beans.binding.Bindings.createFloatBinding;
import static javafx.beans.binding.Bindings.createIntegerBinding;
import static javafx.beans.binding.Bindings.createLongBinding;
import static javafx.beans.binding.Bindings.createObjectBinding;
import static javafx.beans.binding.Bindings.createStringBinding;

/**
 * @author Andres Almiray
 * @since 2.10.0
 */
public final class MappingBindings {
    private static final String ERROR_MAPPER_NULL = "Argument 'mapper' must not be null";
    private static final String ERROR_SUPPLIER_NULL = "Argument 'supplier' must not be null";
    private static final String ERROR_OBSERVABLE_NULL = "Argument 'observable' must not be null";
    private static final String ERROR_OBSERVABLE1_NULL = "Argument 'observable1' must not be null";
    private static final String ERROR_OBSERVABLE2_NULL = "Argument 'observable2' must not be null";
    private static final String ERROR_DEFAULT_VALUE_NULL = "Argument 'defaultValue' must not be null";

    private MappingBindings() {
        // prevent instantiation
    }

    /**
     * Converts an observable into an object binding.
     *
     * @param observable the observable to be converted.
     * @param mapper     a non-interfering, stateless function to apply to the observable value.
     *
     * @return an object binding.
     *
     * @since 2.11.0
     */
    @Nonnull
    public static  ObjectBinding mapAsObject(@Nonnull final ObservableValue observable, @Nonnull final Function mapper) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createObjectBinding(() -> mapper.apply(observable.getValue()), observable);
    }

    /**
     * Converts an observable into an object binding.
     *
     * @param observable the observable to be converted.
     * @param mapper     a non-interfering, stateless function to apply to the observable value.
     *
     * @return an object binding.
     *
     * @since 2.11.0
     */
    @Nonnull
    public static  ObjectBinding mapAsObject(@Nonnull final ObservableValue observable, @Nonnull final ObservableValue> mapper) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createObjectBinding(() -> {
            Function mapperValue = mapper.getValue();
            requireNonNull(mapperValue, ERROR_MAPPER_NULL);
            return mapperValue.apply(observable.getValue());
        }, observable);
    }

    /**
     * Converts an observable into a boolean binding.
     *
     * @param observable the observable to be converted.
     * @param mapper     a non-interfering, stateless function to apply to the observable value.
     *
     * @return a boolean binding.
     *
     * @since 2.11.0
     */
    @Nonnull
    public static  BooleanBinding mapAsBoolean(@Nonnull final ObservableValue observable, @Nonnull final Function mapper) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createBooleanBinding(() -> mapper.apply(observable.getValue()), observable);
    }

    /**
     * Converts an observable into a boolean binding.
     *
     * @param observable the observable to be converted.
     * @param mapper     a non-interfering, stateless function to apply to the observable value.
     *
     * @return a boolean binding.
     *
     * @since 2.11.0
     */
    @Nonnull
    public static  BooleanBinding mapAsBoolean(@Nonnull final ObservableValue observable, @Nonnull final ObservableValue> mapper) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createBooleanBinding(() -> {
            Function mapperValue = mapper.getValue();
            requireNonNull(mapperValue, ERROR_MAPPER_NULL);
            return mapperValue.apply(observable.getValue());
        }, observable);
    }

    /**
     * Converts an observable into an integer binding.
     *
     * @param observable the observable to be converted.
     * @param mapper     a non-interfering, stateless function to apply to the observable value.
     *
     * @return an integer binding.
     *
     * @since 2.11.0
     */
    @Nonnull
    public static  IntegerBinding mapAsInteger(@Nonnull final ObservableValue observable, @Nonnull final Function mapper) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createIntegerBinding(() -> mapper.apply(observable.getValue()), observable);
    }

    /**
     * Converts an observable into an integer binding.
     *
     * @param observable the observable to be converted.
     * @param mapper     a non-interfering, stateless function to apply to the observable value.
     *
     * @return an integer binding.
     *
     * @since 2.11.0
     */
    @Nonnull
    public static  IntegerBinding mapAsInteger(@Nonnull final ObservableValue observable, @Nonnull final ObservableValue> mapper) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createIntegerBinding(() -> {
            Function mapperValue = mapper.getValue();
            requireNonNull(mapperValue, ERROR_MAPPER_NULL);
            return mapperValue.apply(observable.getValue());
        }, observable);
    }

    /**
     * Converts an observable into a long binding.
     *
     * @param observable the observable to be converted.
     * @param mapper     a non-interfering, stateless function to apply to the observable value.
     *
     * @return a long binding.
     *
     * @since 2.11.0
     */
    @Nonnull
    public static  LongBinding mapAsLong(@Nonnull final ObservableValue observable, @Nonnull final Function mapper) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createLongBinding(() -> mapper.apply(observable.getValue()), observable);
    }

    /**
     * Converts an observable into a long binding.
     *
     * @param observable the observable to be converted.
     * @param mapper     a non-interfering, stateless function to apply to the observable value.
     *
     * @return a long binding.
     *
     * @since 2.11.0
     */
    @Nonnull
    public static  LongBinding mapAsLong(@Nonnull final ObservableValue observable, @Nonnull final ObservableValue> mapper) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createLongBinding(() -> {
            Function mapperValue = mapper.getValue();
            requireNonNull(mapperValue, ERROR_MAPPER_NULL);
            return mapperValue.apply(observable.getValue());
        }, observable);
    }

    /**
     * Converts an observable into a float binding.
     *
     * @param observable the observable to be converted.
     * @param mapper     a non-interfering, stateless function to apply to the observable value.
     *
     * @return a float binding.
     *
     * @since 2.11.0
     */
    @Nonnull
    public static  FloatBinding mapAsFloat(@Nonnull final ObservableValue observable, @Nonnull final Function mapper) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createFloatBinding(() -> mapper.apply(observable.getValue()), observable);
    }

    /**
     * Converts an observable into a float binding.
     *
     * @param observable the observable to be converted.
     * @param mapper     a non-interfering, stateless function to apply to the observable value.
     *
     * @return a float binding.
     *
     * @since 2.11.0
     */
    @Nonnull
    public static  FloatBinding mapAsFloat(@Nonnull final ObservableValue observable, @Nonnull final ObservableValue> mapper) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createFloatBinding(() -> {
            Function mapperValue = mapper.getValue();
            requireNonNull(mapperValue, ERROR_MAPPER_NULL);
            return mapperValue.apply(observable.getValue());
        }, observable);
    }

    /**
     * Converts an observable into a double binding.
     *
     * @param observable the observable to be converted.
     * @param mapper     a non-interfering, stateless function to apply to the observable value.
     *
     * @return a double binding.
     *
     * @since 2.11.0
     */
    @Nonnull
    public static  DoubleBinding mapAsDouble(@Nonnull final ObservableValue observable, @Nonnull final Function mapper) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createDoubleBinding(() -> mapper.apply(observable.getValue()), observable);
    }

    /**
     * Converts an observable into a double binding.
     *
     * @param observable the observable to be converted.
     * @param mapper     a non-interfering, stateless function to apply to the observable value.
     *
     * @return a double binding.
     *
     * @since 2.11.0
     */
    @Nonnull
    public static  DoubleBinding mapAsDouble(@Nonnull final ObservableValue observable, @Nonnull final ObservableValue> mapper) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createDoubleBinding(() -> {
            Function mapperValue = mapper.getValue();
            requireNonNull(mapperValue, ERROR_MAPPER_NULL);
            return mapperValue.apply(observable.getValue());
        }, observable);
    }

    /**
     * Converts an observable into a string binding.
     *
     * @param observable the observable to be converted.
     * @param mapper     a non-interfering, stateless function to apply to the observable value.
     *
     * @return a string binding.
     *
     * @since 2.11.0
     */
    @Nonnull
    public static  StringBinding mapAsString(@Nonnull final ObservableValue observable, @Nonnull final Function mapper) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createStringBinding(() -> mapper.apply(observable.getValue()), observable);
    }

    /**
     * Converts an observable into a string binding.
     *
     * @param observable the observable to be converted.
     * @param mapper     a non-interfering, stateless function to apply to the observable value.
     *
     * @return a string binding.
     *
     * @since 2.11.0
     */
    @Nonnull
    public static  StringBinding mapAsString(@Nonnull final ObservableValue observable, @Nonnull final ObservableValue> mapper) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createStringBinding(() -> {
            Function mapperValue = mapper.getValue();
            requireNonNull(mapperValue, ERROR_MAPPER_NULL);
            return mapperValue.apply(observable.getValue());
        }, observable);
    }

    /**
     * Converts a string object observable value into an object binding.
     *
     * @param observable the observable to be converted.
     *
     * @return an object binding.
     */
    @Nonnull
    public static ObjectBinding mapToObject(@Nonnull final ObservableStringValue observable) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        return createObjectBinding(observable::get, observable);
    }

    /**
     * Converts a boolean object observable value into an object binding.
     *
     * @param observable the observable to be converted.
     *
     * @return an object binding.
     */
    @Nonnull
    public static ObjectBinding mapToObject(@Nonnull final ObservableBooleanValue observable) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        return createObjectBinding(observable::get, observable);
    }

    /**
     * Converts a integer object observable value into an object binding.
     *
     * @param observable the observable to be converted.
     *
     * @return an object binding.
     */
    @Nonnull
    public static ObjectBinding mapToObject(@Nonnull final ObservableIntegerValue observable) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        return createObjectBinding(observable::get, observable);
    }

    /**
     * Converts a long object observable value into an object binding.
     *
     * @param observable the observable to be converted.
     *
     * @return an object binding.
     */
    @Nonnull
    public static ObjectBinding mapToObject(@Nonnull final ObservableLongValue observable) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        return createObjectBinding(observable::get, observable);
    }

    /**
     * Converts a float object observable value into an object binding.
     *
     * @param observable the observable to be converted.
     *
     * @return an object binding.
     */
    @Nonnull
    public static ObjectBinding mapToObject(@Nonnull final ObservableFloatValue observable) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        return createObjectBinding(observable::get, observable);
    }

    /**
     * Converts a double object observable value into an object binding.
     *
     * @param observable the observable to be converted.
     *
     * @return an object binding.
     */
    @Nonnull
    public static ObjectBinding mapToObject(@Nonnull final ObservableDoubleValue observable) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        return createObjectBinding(observable::get, observable);
    }

    /**
     * Converts a boolean object observable value into a boolean binding.
     *
     * @param observable the observable to be converted.
     *
     * @return a boolean binding.
     */
    @Nonnull
    public static BooleanBinding mapToBoolean(@Nonnull final ObservableObjectValue observable) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        return createBooleanBinding(observable::get, observable);
    }

    /**
     * Converts a integer object observable value into a integer binding.
     *
     * @param observable the observable to be converted.
     *
     * @return a integer binding.
     */
    @Nonnull
    public static IntegerBinding mapToInteger(@Nonnull final ObservableObjectValue observable) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        return createIntegerBinding(observable::get, observable);
    }

    /**
     * Converts a long object observable value into a long binding.
     *
     * @param observable the observable to be converted.
     *
     * @return a long binding.
     */
    @Nonnull
    public static LongBinding mapToLong(@Nonnull final ObservableObjectValue observable) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        return createLongBinding(observable::get, observable);
    }

    /**
     * Converts a float object observable value into a float binding.
     *
     * @param observable the observable to be converted.
     *
     * @return a float binding.
     */
    @Nonnull
    public static FloatBinding mapToFloat(@Nonnull final ObservableObjectValue observable) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        return createFloatBinding(observable::get, observable);
    }

    /**
     * Converts a double object observable value into a double binding.
     *
     * @param observable the observable to be converted.
     *
     * @return a double binding.
     */
    @Nonnull
    public static DoubleBinding mapToDouble(@Nonnull final ObservableObjectValue observable) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        return createDoubleBinding(observable::get, observable);
    }

    /**
     * Converts a literal object observable value into a string binding.
     *
     * @param observable the observable to be converted.
     *
     * @return a string binding.
     */
    @Nonnull
    public static StringBinding mapToString(@Nonnull final ObservableObjectValue observable) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        return createStringBinding(observable::get, observable);
    }

    /**
     * Creates an observable list where all elements of the source list are mapped by the supplied function.
     *
     * @param source the source list.
     * @param mapper a non-interfering, stateless function to apply to the reduced value.
     *
     * @return an observable list.
     */
    @Nonnull
    public static  ObservableList mapList(@Nonnull final ObservableList source, @Nonnull final Function mapper) {
        return new griffon.javafx.support.MappingObservableList<>((ObservableList) source, mapper);
    }

    /**
     * Creates an observable list where all elements of the source list are mapped by the supplied function.
     *
     * @param source the source list.
     * @param mapper a non-interfering, stateless function to apply to the reduced value.
     *
     * @return an observable list.
     */
    @Nonnull
    public static  ObservableList mapList(@Nonnull final ObservableList source, @Nonnull final ObservableValue> mapper) {
        return new griffon.javafx.support.MappingObservableList<>(source, mapper);
    }

    /**
     * Creates an object binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     * @param mapper     a non-interfering, stateless function to apply to the reduced value.
     *
     * @return an object binding.
     */
    @Nonnull
    public static  ObjectBinding mapObject(@Nonnull final ObservableValue observable, @Nonnull final Function mapper) {
        return mapObject(observable, mapper, (R) null);
    }

    /**
     * Creates an object binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable   the source observable.
     * @param mapper       a non-interfering, stateless function to apply to the reduced value.
     * @param defaultValue the value to be returned if there is no value present, may be null.
     *
     * @return an object binding.
     */
    @Nonnull
    public static  ObjectBinding mapObject(@Nonnull final ObservableValue observable, @Nonnull final Function mapper, @Nullable final R defaultValue) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createObjectBinding(() -> {
            T sourceValue = observable.getValue();
            return sourceValue == null ? defaultValue : mapper.apply(sourceValue);
        }, observable);
    }

    /**
     * Creates an object binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     * @param mapper     a non-interfering, stateless function to apply to the reduced value.
     * @param supplier   a {@code Supplier} whose result is returned if no value is present.
     *
     * @return an object binding.
     */
    @Nonnull
    public static  ObjectBinding mapObject(@Nonnull final ObservableValue observable, @Nonnull final Function mapper, @Nonnull final Supplier supplier) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        requireNonNull(supplier, ERROR_SUPPLIER_NULL);
        return createObjectBinding(() -> {
            T sourceValue = observable.getValue();
            return sourceValue == null ? supplier.get() : mapper.apply(sourceValue);
        }, observable);
    }

    /**
     * Creates an object binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     * @param mapper     a non-interfering, stateless function to apply to the reduced value.
     *
     * @return an object binding.
     */
    @Nonnull
    public static  ObjectBinding mapObject(@Nonnull final ObservableValue observable, @Nonnull final ObservableValue> mapper) {
        return mapObject(observable, mapper, (R) null);
    }

    /**
     * Creates an object binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable   the source observable.
     * @param mapper       a non-interfering, stateless function to apply to the reduced value.
     * @param defaultValue the value to be returned if there is no value present, may be null.
     *
     * @return an object binding.
     */
    @Nonnull
    public static  ObjectBinding mapObject(@Nonnull final ObservableValue observable, @Nonnull final ObservableValue> mapper, @Nullable final R defaultValue) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createObjectBinding(() -> {
            T sourceValue = observable.getValue();
            Function mapperValue = mapper.getValue();
            requireNonNull(mapperValue, ERROR_MAPPER_NULL);
            return sourceValue == null ? defaultValue : mapperValue.apply(sourceValue);
        }, observable, mapper);
    }

    /**
     * Creates an object binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     * @param mapper     a non-interfering, stateless function to apply to the reduced value.
     * @param supplier   a {@code Supplier} whose result is returned if no value is present.
     *
     * @return an object binding.
     */
    @Nonnull
    public static  ObjectBinding mapObject(@Nonnull final ObservableValue observable, @Nonnull final ObservableValue> mapper, @Nonnull final Supplier supplier) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        requireNonNull(supplier, ERROR_SUPPLIER_NULL);
        return createObjectBinding(() -> {
            T sourceValue = observable.getValue();
            Function mapperValue = mapper.getValue();
            requireNonNull(mapperValue, ERROR_MAPPER_NULL);
            return sourceValue == null ? supplier.get() : mapperValue.apply(sourceValue);
        }, observable, mapper);
    }

    /**
     * Creates a boolean binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     * @param mapper     a non-interfering, stateless function to apply to the reduced value.
     *
     * @return a boolean binding.
     */
    @Nonnull
    public static BooleanBinding mapBoolean(@Nonnull final ObservableValue observable, @Nonnull final Function mapper) {
        return mapBoolean(observable, mapper, false);
    }

    /**
     * Creates a boolean binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable   the source observable.
     * @param mapper       a non-interfering, stateless function to apply to the reduced value.
     * @param defaultValue the value to be returned if there is no value present, may be null.
     *
     * @return a boolean binding.
     */
    @Nonnull
    public static BooleanBinding mapBoolean(@Nonnull final ObservableValue observable, @Nonnull final Function mapper, @Nonnull final Boolean defaultValue) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createBooleanBinding(() -> {
            Boolean sourceValue = observable.getValue();
            return sourceValue == null ? defaultValue : mapper.apply(sourceValue);
        }, observable);
    }

    /**
     * Creates a boolean binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     * @param mapper     a non-interfering, stateless function to apply to the reduced value.
     * @param supplier   a {@code Supplier} whose result is returned if no value is present.
     *
     * @return a boolean binding.
     */
    @Nonnull
    public static BooleanBinding mapBoolean(@Nonnull final ObservableValue observable, @Nonnull final Function mapper, @Nonnull final Supplier supplier) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        requireNonNull(supplier, ERROR_SUPPLIER_NULL);
        return createBooleanBinding(() -> {
            Boolean sourceValue = observable.getValue();
            return sourceValue == null ? supplier.get() : mapper.apply(sourceValue);
        }, observable);
    }

    /**
     * Creates a boolean binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     * @param mapper     a non-interfering, stateless function to apply to the reduced value.
     *
     * @return a boolean binding.
     */
    @Nonnull
    public static BooleanBinding mapBoolean(@Nonnull final ObservableValue observable, @Nonnull final ObservableValue> mapper) {
        return mapBoolean(observable, mapper, false);
    }

    /**
     * Creates a boolean binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable   the source observable.
     * @param mapper       a non-interfering, stateless function to apply to the reduced value.
     * @param defaultValue the value to be returned if there is no value present, may be null.
     *
     * @return a boolean binding.
     */
    @Nonnull
    public static BooleanBinding mapBoolean(@Nonnull final ObservableValue observable, @Nonnull final ObservableValue> mapper, @Nonnull final Boolean defaultValue) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createBooleanBinding(() -> {
            Boolean sourceValue = observable.getValue();
            Function mapperValue = mapper.getValue();
            requireNonNull(mapperValue, ERROR_MAPPER_NULL);
            return sourceValue == null ? defaultValue : mapperValue.apply(sourceValue);
        }, observable, mapper);
    }

    /**
     * Creates a boolean binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     * @param mapper     a non-interfering, stateless function to apply to the reduced value.
     * @param supplier   a {@code Supplier} whose result is returned if no value is present.
     *
     * @return a boolean binding.
     */
    @Nonnull
    public static BooleanBinding mapBoolean(@Nonnull final ObservableValue observable, @Nonnull final ObservableValue> mapper, @Nonnull final Supplier supplier) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        requireNonNull(supplier, ERROR_SUPPLIER_NULL);
        return createBooleanBinding(() -> {
            Boolean sourceValue = observable.getValue();
            Function mapperValue = mapper.getValue();
            requireNonNull(mapperValue, ERROR_MAPPER_NULL);
            return sourceValue == null ? supplier.get() : mapperValue.apply(sourceValue);
        }, observable, mapper);
    }

    /**
     * Creates an integer binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     * @param mapper     a non-interfering, stateless function to apply to the reduced value.
     *
     * @return an integer binding.
     */
    @Nonnull
    public static IntegerBinding mapInteger(@Nonnull final ObservableValue observable, @Nonnull final Function mapper) {
        return mapInteger(observable, mapper, 0);
    }

    /**
     * Creates an integer binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable   the source observable.
     * @param mapper       a non-interfering, stateless function to apply to the reduced value.
     * @param defaultValue the value to be returned if there is no value present, may be null.
     *
     * @return an integer binding.
     */
    @Nonnull
    public static IntegerBinding mapInteger(@Nonnull final ObservableValue observable, @Nonnull final Function mapper, @Nonnull final Integer defaultValue) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createIntegerBinding(() -> {
            Integer sourceValue = observable.getValue();
            return sourceValue == null ? defaultValue : mapper.apply(sourceValue);
        }, observable);
    }


    /**
     * Creates an integer binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     * @param mapper     a non-interfering, stateless function to apply to the reduced value.
     * @param supplier   a {@code Supplier} whose result is returned if no value is present.
     *
     * @return an integer binding.
     */
    @Nonnull
    public static IntegerBinding mapInteger(@Nonnull final ObservableValue observable, @Nonnull final Function mapper, @Nonnull final Supplier supplier) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        requireNonNull(supplier, ERROR_SUPPLIER_NULL);
        return createIntegerBinding(() -> {
            Integer sourceValue = observable.getValue();
            return sourceValue == null ? supplier.get() : mapper.apply(sourceValue);
        }, observable);
    }

    /**
     * Creates an integer binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     * @param mapper     a non-interfering, stateless function to apply to the reduced value.
     *
     * @return an integer binding.
     */
    @Nonnull
    public static IntegerBinding mapInteger(@Nonnull final ObservableValue observable, @Nonnull final ObservableValue> mapper) {
        return mapInteger(observable, mapper, 0);
    }

    /**
     * Creates an integer binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable   the source observable.
     * @param mapper       a non-interfering, stateless function to apply to the reduced value.
     * @param defaultValue the value to be returned if there is no value present, may be null.
     *
     * @return an integer binding.
     */
    @Nonnull
    public static IntegerBinding mapInteger(@Nonnull final ObservableValue observable, @Nonnull final ObservableValue> mapper, @Nonnull final Integer defaultValue) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createIntegerBinding(() -> {
            Integer sourceValue = observable.getValue();
            Function mapperValue = mapper.getValue();
            requireNonNull(mapperValue, ERROR_MAPPER_NULL);
            return sourceValue == null ? defaultValue : mapperValue.apply(sourceValue);
        }, observable, mapper);
    }

    /**
     * Creates an integer binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     * @param mapper     a non-interfering, stateless function to apply to the reduced value.
     * @param supplier   a {@code Supplier} whose result is returned if no value is present.
     *
     * @return an integer binding.
     */
    @Nonnull
    public static IntegerBinding mapInteger(@Nonnull final ObservableValue observable, @Nonnull final ObservableValue> mapper, @Nonnull final Supplier supplier) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        requireNonNull(supplier, ERROR_SUPPLIER_NULL);
        return createIntegerBinding(() -> {
            Integer sourceValue = observable.getValue();
            Function mapperValue = mapper.getValue();
            requireNonNull(mapperValue, ERROR_MAPPER_NULL);
            return sourceValue == null ? supplier.get() : mapperValue.apply(sourceValue);
        }, observable, mapper);
    }

    /**
     * Creates a long binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     * @param mapper     a non-interfering, stateless function to apply to the reduced value.
     *
     * @return a long binding.
     */
    @Nonnull
    public static LongBinding mapLong(@Nonnull final ObservableValue observable, @Nonnull final Function mapper) {
        return mapLong(observable, mapper, 0L);
    }

    /**
     * Creates a long binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable   the source observable.
     * @param mapper       a non-interfering, stateless function to apply to the reduced value.
     * @param defaultValue the value to be returned if there is no value present, may be null.
     *
     * @return a long binding.
     */
    @Nonnull
    public static LongBinding mapLong(@Nonnull final ObservableValue observable, @Nonnull final Function mapper, @Nonnull final Long defaultValue) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createLongBinding(() -> {
            Long sourceValue = observable.getValue();
            return sourceValue == null ? defaultValue : mapper.apply(sourceValue);
        }, observable);
    }


    /**
     * Creates a long binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     * @param mapper     a non-interfering, stateless function to apply to the reduced value.
     * @param supplier   a {@code Supplier} whose result is returned if no value is present.
     *
     * @return a long binding.
     */
    @Nonnull
    public static LongBinding mapLong(@Nonnull final ObservableValue observable, @Nonnull final Function mapper, @Nonnull final Supplier supplier) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        requireNonNull(supplier, ERROR_SUPPLIER_NULL);
        return createLongBinding(() -> {
            Long sourceValue = observable.getValue();
            return sourceValue == null ? supplier.get() : mapper.apply(sourceValue);
        }, observable);
    }

    /**
     * Creates a long binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     * @param mapper     a non-interfering, stateless function to apply to the reduced value.
     *
     * @return a long binding.
     */
    @Nonnull
    public static LongBinding mapLong(@Nonnull final ObservableValue observable, @Nonnull final ObservableValue> mapper) {
        return mapLong(observable, mapper, 0L);
    }

    /**
     * Creates a long binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable   the source observable.
     * @param mapper       a non-interfering, stateless function to apply to the reduced value.
     * @param defaultValue the value to be returned if there is no value present, may be null.
     *
     * @return a long binding.
     */
    @Nonnull
    public static LongBinding mapLong(@Nonnull final ObservableValue observable, @Nonnull final ObservableValue> mapper, @Nonnull final Long defaultValue) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createLongBinding(() -> {
            Long sourceValue = observable.getValue();
            Function mapperValue = mapper.getValue();
            requireNonNull(mapperValue, ERROR_MAPPER_NULL);
            return sourceValue == null ? defaultValue : mapperValue.apply(sourceValue);
        }, observable, mapper);
    }

    /**
     * Creates a long binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     * @param mapper     a non-interfering, stateless function to apply to the reduced value.
     * @param supplier   a {@code Supplier} whose result is returned if no value is present.
     *
     * @return a long binding.
     */
    @Nonnull
    public static LongBinding mapLong(@Nonnull final ObservableValue observable, @Nonnull final ObservableValue> mapper, @Nonnull final Supplier supplier) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        requireNonNull(supplier, ERROR_SUPPLIER_NULL);
        return createLongBinding(() -> {
            Long sourceValue = observable.getValue();
            Function mapperValue = mapper.getValue();
            requireNonNull(mapperValue, ERROR_MAPPER_NULL);
            return sourceValue == null ? supplier.get() : mapperValue.apply(sourceValue);
        }, observable, mapper);
    }

    /**
     * Creates a float binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     * @param mapper     a non-interfering, stateless function to apply to the reduced value.
     *
     * @return a float binding.
     */
    @Nonnull
    public static FloatBinding mapFloat(@Nonnull final ObservableValue observable, @Nonnull final Function mapper) {
        return mapFloat(observable, mapper, 0f);
    }

    /**
     * Creates a float binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable   the source observable.
     * @param mapper       a non-interfering, stateless function to apply to the reduced value.
     * @param defaultValue the value to be returned if there is no value present, may be null.
     *
     * @return a float binding.
     */
    @Nonnull
    public static FloatBinding mapFloat(@Nonnull final ObservableValue observable, @Nonnull final Function mapper, @Nonnull final Float defaultValue) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createFloatBinding(() -> {
            Float sourceValue = observable.getValue();
            return sourceValue == null ? defaultValue : mapper.apply(sourceValue);
        }, observable);
    }

    /**
     * Creates a float binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     * @param mapper     a non-interfering, stateless function to apply to the reduced value.
     * @param supplier   a {@code Supplier} whose result is returned if no value is present.
     *
     * @return a float binding.
     */
    @Nonnull
    public static FloatBinding mapFloat(@Nonnull final ObservableValue observable, @Nonnull final Function mapper, @Nonnull final Supplier supplier) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        requireNonNull(supplier, ERROR_SUPPLIER_NULL);
        return createFloatBinding(() -> {
            Float sourceValue = observable.getValue();
            return sourceValue == null ? supplier.get() : mapper.apply(sourceValue);
        }, observable);
    }

    /**
     * Creates a float binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     * @param mapper     a non-interfering, stateless function to apply to the reduced value.
     *
     * @return a float binding.
     */
    @Nonnull
    public static FloatBinding mapFloat(@Nonnull final ObservableValue observable, @Nonnull final ObservableValue> mapper) {
        return mapFloat(observable, mapper, 0f);
    }

    /**
     * Creates a float binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable   the source observable.
     * @param mapper       a non-interfering, stateless function to apply to the reduced value.
     * @param defaultValue the value to be returned if there is no value present, may be null.
     *
     * @return a float binding.
     */
    @Nonnull
    public static FloatBinding mapFloat(@Nonnull final ObservableValue observable, @Nonnull final ObservableValue> mapper, @Nullable final Float defaultValue) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createFloatBinding(() -> {
            Float sourceValue = observable.getValue();
            Function mapperValue = mapper.getValue();
            requireNonNull(mapperValue, ERROR_MAPPER_NULL);
            return sourceValue == null ? defaultValue : mapperValue.apply(sourceValue);
        }, observable, mapper);
    }

    /**
     * Creates a float binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     * @param mapper     a non-interfering, stateless function to apply to the reduced value.
     * @param supplier   a {@code Supplier} whose result is returned if no value is present.
     *
     * @return a float binding.
     */
    @Nonnull
    public static FloatBinding mapFloat(@Nonnull final ObservableValue observable, @Nonnull final ObservableValue> mapper, @Nonnull final Supplier supplier) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        requireNonNull(supplier, ERROR_SUPPLIER_NULL);
        return createFloatBinding(() -> {
            Float sourceValue = observable.getValue();
            Function mapperValue = mapper.getValue();
            requireNonNull(mapperValue, ERROR_MAPPER_NULL);
            return sourceValue == null ? supplier.get() : mapperValue.apply(sourceValue);
        }, observable, mapper);
    }

    /**
     * Creates a double binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     * @param mapper     a non-interfering, stateless function to apply to the reduced value.
     *
     * @return a double binding.
     */
    @Nonnull
    public static DoubleBinding mapDouble(@Nonnull final ObservableValue observable, @Nonnull final Function mapper) {
        return mapDouble(observable, mapper, 0d);
    }

    /**
     * Creates a double binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable   the source observable.
     * @param mapper       a non-interfering, stateless function to apply to the reduced value.
     * @param defaultValue the value to be returned if there is no value present, may be null.
     *
     * @return a double binding.
     */
    @Nonnull
    public static DoubleBinding mapDouble(@Nonnull final ObservableValue observable, @Nonnull final Function mapper, @Nullable final Double defaultValue) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createDoubleBinding(() -> {
            Double sourceValue = observable.getValue();
            return sourceValue == null ? defaultValue : mapper.apply(sourceValue);
        }, observable);
    }

    /**
     * Creates a double binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     * @param mapper     a non-interfering, stateless function to apply to the reduced value.
     * @param supplier   a {@code Supplier} whose result is returned if no value is present.
     *
     * @return a double binding.
     */
    @Nonnull
    public static DoubleBinding mapDouble(@Nonnull final ObservableValue observable, @Nonnull final Function mapper, @Nonnull final Supplier supplier) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        requireNonNull(supplier, ERROR_SUPPLIER_NULL);
        return createDoubleBinding(() -> {
            Double sourceValue = observable.getValue();
            return sourceValue == null ? supplier.get() : mapper.apply(sourceValue);
        }, observable);
    }

    /**
     * Creates a double binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     * @param mapper     a non-interfering, stateless function to apply to the reduced value.
     *
     * @return a double binding.
     */
    @Nonnull
    public static DoubleBinding mapDouble(@Nonnull final ObservableValue observable, @Nonnull final ObservableValue> mapper) {
        return mapDouble(observable, mapper, 0d);
    }

    /**
     * Creates a double binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable   the source observable.
     * @param mapper       a non-interfering, stateless function to apply to the reduced value.
     * @param defaultValue the value to be returned if there is no value present, may be null.
     *
     * @return a double binding.
     */
    @Nonnull
    public static DoubleBinding mapDouble(@Nonnull final ObservableValue observable, @Nonnull final ObservableValue> mapper, @Nonnull final Double defaultValue) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createDoubleBinding(() -> {
            Double sourceValue = observable.getValue();
            Function mapperValue = mapper.getValue();
            requireNonNull(mapperValue, ERROR_MAPPER_NULL);
            return sourceValue == null ? defaultValue : mapperValue.apply(sourceValue);
        }, observable, mapper);
    }

    /**
     * Creates a double binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     * @param mapper     a non-interfering, stateless function to apply to the reduced value.
     * @param supplier   a {@code Supplier} whose result is returned if no value is present.
     *
     * @return a double binding.
     */
    @Nonnull
    public static DoubleBinding mapDouble(@Nonnull final ObservableValue observable, @Nonnull final ObservableValue> mapper, @Nonnull final Supplier supplier) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        requireNonNull(supplier, ERROR_SUPPLIER_NULL);
        return createDoubleBinding(() -> {
            Double sourceValue = observable.getValue();
            Function mapperValue = mapper.getValue();
            requireNonNull(mapperValue, ERROR_MAPPER_NULL);
            return sourceValue == null ? supplier.get() : mapperValue.apply(sourceValue);
        }, observable, mapper);
    }

    /**
     * Creates a string binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     * @param mapper     a non-interfering, stateless function to apply to the reduced value.
     *
     * @return a string binding.
     */
    @Nonnull
    public static StringBinding mapString(@Nonnull final ObservableValue observable, @Nonnull final Function mapper) {
        return mapString(observable, mapper, "");
    }

    /**
     * Creates a string binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable   the source observable.
     * @param mapper       a non-interfering, stateless function to apply to the reduced value.
     * @param defaultValue the value to be returned if there is no value present, may be null.
     *
     * @return a string binding.
     */
    @Nonnull
    public static StringBinding mapString(@Nonnull final ObservableValue observable, @Nonnull final Function mapper, @Nonnull final String defaultValue) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createStringBinding(() -> {
            String sourceValue = observable.getValue();
            return sourceValue == null ? defaultValue : mapper.apply(sourceValue);
        }, observable);
    }

    /**
     * Creates a string binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     * @param mapper     a non-interfering, stateless function to apply to the reduced value.
     * @param supplier   a {@code Supplier} whose result is returned if no value is present.
     *
     * @return a string binding.
     */
    @Nonnull
    public static StringBinding mapString(@Nonnull final ObservableValue observable, @Nonnull final Function mapper, @Nonnull final Supplier supplier) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        requireNonNull(supplier, ERROR_SUPPLIER_NULL);
        return createStringBinding(() -> {
            String sourceValue = observable.getValue();
            return sourceValue == null ? supplier.get() : mapper.apply(sourceValue);
        }, observable);
    }

    /**
     * Creates a string binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     * @param mapper     a non-interfering, stateless function to apply to the reduced value.
     *
     * @return a string binding.
     */
    @Nonnull
    public static StringBinding mapString(@Nonnull final ObservableValue observable, @Nonnull final ObservableValue> mapper) {
        return mapString(observable, mapper, "");
    }

    /**
     * Creates a string binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable   the source observable.
     * @param mapper       a non-interfering, stateless function to apply to the reduced value.
     * @param defaultValue the value to be returned if there is no value present, may be null.
     *
     * @return a string binding.
     */
    @Nonnull
    public static StringBinding mapString(@Nonnull final ObservableValue observable, @Nonnull final ObservableValue> mapper, @Nonnull final String defaultValue) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createStringBinding(() -> {
            String sourceValue = observable.getValue();
            Function mapperValue = mapper.getValue();
            requireNonNull(mapperValue, ERROR_MAPPER_NULL);
            return sourceValue == null ? defaultValue : mapperValue.apply(sourceValue);
        }, observable, mapper);
    }

    /**
     * Creates a string binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     * @param mapper     a non-interfering, stateless function to apply to the reduced value.
     * @param supplier   a {@code Supplier} whose result is returned if no value is present.
     *
     * @return a string binding.
     */
    @Nonnull
    public static StringBinding mapString(@Nonnull final ObservableValue observable, @Nonnull final ObservableValue> mapper, @Nonnull final Supplier supplier) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        requireNonNull(supplier, ERROR_SUPPLIER_NULL);
        return createStringBinding(() -> {
            String sourceValue = observable.getValue();
            Function mapperValue = mapper.getValue();
            requireNonNull(mapperValue, ERROR_MAPPER_NULL);
            return sourceValue == null ? supplier.get() : mapperValue.apply(sourceValue);
        }, observable, mapper);
    }

    /**
     * Returns a boolean binding whose value is the combination of two observable values.
     *
     * @param observable1  the first observable value.
     * @param observable2  the second observable value.
     * @param defaultValue the value to be returned if there are no values present.
     * @param mapper       a non-interfering, stateless function to apply to the supplied values.
     *
     * @return a boolean binding
     */
    @Nonnull
    public static BooleanBinding mapBooleans(@Nonnull final ObservableValue observable1, @Nonnull final ObservableValue observable2, @Nonnull final Boolean defaultValue, @Nonnull final BiFunction mapper) {
        requireNonNull(observable1, ERROR_OBSERVABLE1_NULL);
        requireNonNull(observable2, ERROR_OBSERVABLE2_NULL);
        requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createBooleanBinding(() -> {
            Boolean value1 = observable1.getValue();
            Boolean value2 = observable2.getValue();
            if (value1 != null && value2 != null) {
                return mapper.apply(value1, value2);
            }
            return defaultValue;
        }, observable1, observable2);
    }

    /**
     * Returns a boolean binding whose value is the combination of two observable values.
     *
     * @param observable1 the first observable value.
     * @param observable2 the second observable value.
     * @param supplier    a {@code Supplier} whose result is returned if no values are present.
     * @param mapper      a non-interfering, stateless function to apply to the supplied values.
     *
     * @return a boolean binding
     */
    @Nonnull
    public static BooleanBinding mapBooleans(@Nonnull final ObservableValue observable1, @Nonnull final ObservableValue observable2, @Nonnull final Supplier supplier, @Nonnull final BiFunction mapper) {
        requireNonNull(observable1, ERROR_OBSERVABLE1_NULL);
        requireNonNull(observable2, ERROR_OBSERVABLE2_NULL);
        requireNonNull(supplier, ERROR_SUPPLIER_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createBooleanBinding(() -> {
            Boolean value1 = observable1.getValue();
            Boolean value2 = observable2.getValue();
            if (value1 != null && value2 != null) {
                return mapper.apply(value1, value2);
            }
            return requireNonNull(supplier.get(), ERROR_DEFAULT_VALUE_NULL);
        }, observable1, observable2);
    }

    /**
     * Returns a boolean binding whose value is the combination of two observable values.
     *
     * @param observable1  the first observable value.
     * @param observable2  the second observable value.
     * @param defaultValue the value to be returned if there is no value present.
     * @param mapper       a non-interfering, stateless function to apply to the supplied values.
     *
     * @return a boolean binding
     */
    @Nonnull
    public static BooleanBinding mapBooleans(@Nonnull final ObservableValue observable1, @Nonnull final ObservableValue observable2, @Nonnull final Boolean defaultValue, @Nonnull final ObservableValue> mapper) {
        requireNonNull(observable1, ERROR_OBSERVABLE1_NULL);
        requireNonNull(observable2, ERROR_OBSERVABLE2_NULL);
        requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createBooleanBinding(() -> {
            Boolean value1 = observable1.getValue();
            Boolean value2 = observable2.getValue();
            if (value1 != null && value2 != null) {
                BiFunction function = mapper.getValue();
                return requireNonNull(function, ERROR_MAPPER_NULL).apply(value1, value2);
            }
            return defaultValue;
        }, observable1, observable2, mapper);
    }

    /**
     * Returns a boolean binding whose value is the combination of two observable values.
     *
     * @param observable1 the first observable value.
     * @param observable2 the second observable value.
     * @param supplier    a {@code Supplier} whose result is returned if no value is present.
     * @param mapper      a non-interfering, stateless function to apply to the supplied values.
     *
     * @return a boolean binding
     */
    @Nonnull
    public static BooleanBinding mapBooleans(@Nonnull final ObservableValue observable1, @Nonnull final ObservableValue observable2, @Nonnull final Supplier supplier, @Nonnull final ObservableValue> mapper) {
        requireNonNull(observable1, ERROR_OBSERVABLE1_NULL);
        requireNonNull(observable2, ERROR_OBSERVABLE2_NULL);
        requireNonNull(supplier, ERROR_SUPPLIER_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createBooleanBinding(() -> {
            Boolean value1 = observable1.getValue();
            Boolean value2 = observable2.getValue();
            if (value1 != null && value2 != null) {
                BiFunction function = mapper.getValue();
                return requireNonNull(function, ERROR_MAPPER_NULL).apply(value1, value2);
            }
            return requireNonNull(supplier.get(), ERROR_DEFAULT_VALUE_NULL);
        }, observable1, observable2, mapper);
    }

    /**
     * Returns an integer binding whose value is the combination of two observable values.
     *
     * @param observable1  the first observable value.
     * @param observable2  the second observable value.
     * @param defaultValue the value to be returned if there are no values present.
     * @param mapper       a non-interfering, stateless function to apply to the supplied values.
     *
     * @return an integer binding
     */
    @Nonnull
    public static IntegerBinding mapIntegers(@Nonnull final ObservableValue observable1, @Nonnull final ObservableValue observable2, @Nonnull final Integer defaultValue, @Nonnull final BiFunction mapper) {
        requireNonNull(observable1, ERROR_OBSERVABLE1_NULL);
        requireNonNull(observable2, ERROR_OBSERVABLE2_NULL);
        requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createIntegerBinding(() -> {
            Number value1 = observable1.getValue();
            Number value2 = observable2.getValue();
            if (value1 != null && value2 != null) {
                return mapper.apply(value1, value2);
            }
            return defaultValue;
        }, observable1, observable2);
    }

    /**
     * Returns an integer binding whose value is the combination of two observable values.
     *
     * @param observable1 the first observable value.
     * @param observable2 the second observable value.
     * @param supplier    a {@code Supplier} whose result is returned if no values are present.
     * @param mapper      a non-interfering, stateless function to apply to the supplied values.
     *
     * @return an integer binding
     */
    @Nonnull
    public static IntegerBinding mapIntegers(@Nonnull final ObservableValue observable1, @Nonnull final ObservableValue observable2, @Nonnull final Supplier supplier, @Nonnull final BiFunction mapper) {
        requireNonNull(observable1, ERROR_OBSERVABLE1_NULL);
        requireNonNull(observable2, ERROR_OBSERVABLE2_NULL);
        requireNonNull(supplier, ERROR_SUPPLIER_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createIntegerBinding(() -> {
            Number value1 = observable1.getValue();
            Number value2 = observable2.getValue();
            if (value1 != null && value2 != null) {
                return mapper.apply(value1, value2);
            }
            return requireNonNull(supplier.get(), ERROR_DEFAULT_VALUE_NULL);
        }, observable1, observable2);
    }

    /**
     * Returns an integer binding whose value is the combination of two observable values.
     *
     * @param observable1  the first observable value.
     * @param observable2  the second observable value.
     * @param defaultValue the value to be returned if there is no value present.
     * @param mapper       a non-interfering, stateless function to apply to the supplied values.
     *
     * @return an integer binding
     */
    @Nonnull
    public static IntegerBinding mapIntegers(@Nonnull final ObservableValue observable1, @Nonnull final ObservableValue observable2, @Nonnull final Integer defaultValue, @Nonnull final ObservableValue> mapper) {
        requireNonNull(observable1, ERROR_OBSERVABLE1_NULL);
        requireNonNull(observable2, ERROR_OBSERVABLE2_NULL);
        requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createIntegerBinding(() -> {
            Number value1 = observable1.getValue();
            Number value2 = observable2.getValue();
            if (value1 != null && value2 != null) {
                BiFunction function = mapper.getValue();
                return requireNonNull(function, ERROR_MAPPER_NULL).apply(value1, value2);
            }
            return defaultValue;
        }, observable1, observable2, mapper);
    }

    /**
     * Returns an integer binding whose value is the combination of two observable values.
     *
     * @param observable1 the first observable value.
     * @param observable2 the second observable value.
     * @param supplier    a {@code Supplier} whose result is returned if no value is present.
     * @param mapper      a non-interfering, stateless function to apply to the supplied values.
     *
     * @return an integer binding
     */
    @Nonnull
    public static IntegerBinding mapIntegers(@Nonnull final ObservableValue observable1, @Nonnull final ObservableValue observable2, @Nonnull final Supplier supplier, @Nonnull final ObservableValue> mapper) {
        requireNonNull(observable1, ERROR_OBSERVABLE1_NULL);
        requireNonNull(observable2, ERROR_OBSERVABLE2_NULL);
        requireNonNull(supplier, ERROR_SUPPLIER_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createIntegerBinding(() -> {
            Number value1 = observable1.getValue();
            Number value2 = observable2.getValue();
            if (value1 != null && value2 != null) {
                BiFunction function = mapper.getValue();
                return requireNonNull(function, ERROR_MAPPER_NULL).apply(value1, value2);
            }
            return requireNonNull(supplier.get(), ERROR_DEFAULT_VALUE_NULL);
        }, observable1, observable2, mapper);
    }

    /**
     * Returns a long binding whose value is the combination of two observable values.
     *
     * @param observable1  the first observable value.
     * @param observable2  the second observable value.
     * @param defaultValue the value to be returned if there are no values present.
     * @param mapper       a non-interfering, stateless function to apply to the supplied values.
     *
     * @return a long binding
     */
    @Nonnull
    public static LongBinding mapLongs(@Nonnull final ObservableValue observable1, @Nonnull final ObservableValue observable2, @Nonnull final Long defaultValue, @Nonnull final BiFunction mapper) {
        requireNonNull(observable1, ERROR_OBSERVABLE1_NULL);
        requireNonNull(observable2, ERROR_OBSERVABLE2_NULL);
        requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createLongBinding(() -> {
            Number value1 = observable1.getValue();
            Number value2 = observable2.getValue();
            if (value1 != null && value2 != null) {
                return mapper.apply(value1, value2);
            }
            return defaultValue;
        }, observable1, observable2);
    }

    /**
     * Returns a long binding whose value is the combination of two observable values.
     *
     * @param observable1 the first observable value.
     * @param observable2 the second observable value.
     * @param supplier    a {@code Supplier} whose result is returned if no values are present.
     * @param mapper      a non-interfering, stateless function to apply to the supplied values.
     *
     * @return a long binding
     */
    @Nonnull
    public static LongBinding mapLongs(@Nonnull final ObservableValue observable1, @Nonnull final ObservableValue observable2, @Nonnull final Supplier supplier, @Nonnull final BiFunction mapper) {
        requireNonNull(observable1, ERROR_OBSERVABLE1_NULL);
        requireNonNull(observable2, ERROR_OBSERVABLE2_NULL);
        requireNonNull(supplier, ERROR_SUPPLIER_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createLongBinding(() -> {
            Number value1 = observable1.getValue();
            Number value2 = observable2.getValue();
            if (value1 != null && value2 != null) {
                return mapper.apply(value1, value2);
            }
            return requireNonNull(supplier.get(), ERROR_DEFAULT_VALUE_NULL);
        }, observable1, observable2);
    }

    /**
     * Returns a long binding whose value is the combination of two observable values.
     *
     * @param observable1  the first observable value.
     * @param observable2  the second observable value.
     * @param defaultValue the value to be returned if there is no value present.
     * @param mapper       a non-interfering, stateless function to apply to the supplied values.
     *
     * @return a long binding
     */
    @Nonnull
    public static LongBinding mapLongs(@Nonnull final ObservableValue observable1, @Nonnull final ObservableValue observable2, @Nonnull final Long defaultValue, @Nonnull final ObservableValue> mapper) {
        requireNonNull(observable1, ERROR_OBSERVABLE1_NULL);
        requireNonNull(observable2, ERROR_OBSERVABLE2_NULL);
        requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createLongBinding(() -> {
            Number value1 = observable1.getValue();
            Number value2 = observable2.getValue();
            if (value1 != null && value2 != null) {
                BiFunction function = mapper.getValue();
                return requireNonNull(function, ERROR_MAPPER_NULL).apply(value1, value2);
            }
            return defaultValue;
        }, observable1, observable2, mapper);
    }

    /**
     * Returns a long binding whose value is the combination of two observable values.
     *
     * @param observable1 the first observable value.
     * @param observable2 the second observable value.
     * @param supplier    a {@code Supplier} whose result is returned if no value is present.
     * @param mapper      a non-interfering, stateless function to apply to the supplied values.
     *
     * @return a long binding
     */
    @Nonnull
    public static LongBinding mapLongs(@Nonnull final ObservableValue observable1, @Nonnull final ObservableValue observable2, @Nonnull final Supplier supplier, @Nonnull final ObservableValue> mapper) {
        requireNonNull(observable1, ERROR_OBSERVABLE1_NULL);
        requireNonNull(observable2, ERROR_OBSERVABLE2_NULL);
        requireNonNull(supplier, ERROR_SUPPLIER_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createLongBinding(() -> {
            Number value1 = observable1.getValue();
            Number value2 = observable2.getValue();
            if (value1 != null && value2 != null) {
                BiFunction function = mapper.getValue();
                return requireNonNull(function, ERROR_MAPPER_NULL).apply(value1, value2);
            }
            return requireNonNull(supplier.get(), ERROR_DEFAULT_VALUE_NULL);
        }, observable1, observable2, mapper);
    }

    /**
     * Returns a float binding whose value is the combination of two observable values.
     *
     * @param observable1  the first observable value.
     * @param observable2  the second observable value.
     * @param defaultValue the value to be returned if there are no values present.
     * @param mapper       a non-interfering, stateless function to apply to the supplied values.
     *
     * @return a float binding
     */
    @Nonnull
    public static FloatBinding mapFloats(@Nonnull final ObservableValue observable1, @Nonnull final ObservableValue observable2, @Nonnull final Float defaultValue, @Nonnull final BiFunction mapper) {
        requireNonNull(observable1, ERROR_OBSERVABLE1_NULL);
        requireNonNull(observable2, ERROR_OBSERVABLE2_NULL);
        requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createFloatBinding(() -> {
            Number value1 = observable1.getValue();
            Number value2 = observable2.getValue();
            if (value1 != null && value2 != null) {
                return mapper.apply(value1, value2);
            }
            return defaultValue;
        }, observable1, observable2);
    }

    /**
     * Returns a float binding whose value is the combination of two observable values.
     *
     * @param observable1 the first observable value.
     * @param observable2 the second observable value.
     * @param supplier    a {@code Supplier} whose result is returned if no values are present.
     * @param mapper      a non-interfering, stateless function to apply to the supplied values.
     *
     * @return a float binding
     */
    @Nonnull
    public static FloatBinding mapFloats(@Nonnull final ObservableValue observable1, @Nonnull final ObservableValue observable2, @Nonnull final Supplier supplier, @Nonnull final BiFunction mapper) {
        requireNonNull(observable1, ERROR_OBSERVABLE1_NULL);
        requireNonNull(observable2, ERROR_OBSERVABLE2_NULL);
        requireNonNull(supplier, ERROR_SUPPLIER_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createFloatBinding(() -> {
            Number value1 = observable1.getValue();
            Number value2 = observable2.getValue();
            if (value1 != null && value2 != null) {
                return mapper.apply(value1, value2);
            }
            return requireNonNull(supplier.get(), ERROR_DEFAULT_VALUE_NULL);
        }, observable1, observable2);
    }

    /**
     * Returns a float binding whose value is the combination of two observable values.
     *
     * @param observable1  the first observable value.
     * @param observable2  the second observable value.
     * @param defaultValue the value to be returned if there is no value present.
     * @param mapper       a non-interfering, stateless function to apply to the supplied values.
     *
     * @return a float binding
     */
    @Nonnull
    public static FloatBinding mapFloats(@Nonnull final ObservableValue observable1, @Nonnull final ObservableValue observable2, @Nonnull final Float defaultValue, @Nonnull final ObservableValue> mapper) {
        requireNonNull(observable1, ERROR_OBSERVABLE1_NULL);
        requireNonNull(observable2, ERROR_OBSERVABLE2_NULL);
        requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createFloatBinding(() -> {
            Number value1 = observable1.getValue();
            Number value2 = observable2.getValue();
            if (value1 != null && value2 != null) {
                BiFunction function = mapper.getValue();
                return requireNonNull(function, ERROR_MAPPER_NULL).apply(value1, value2);
            }
            return defaultValue;
        }, observable1, observable2, mapper);
    }

    /**
     * Returns a float binding whose value is the combination of two observable values.
     *
     * @param observable1 the first observable value.
     * @param observable2 the second observable value.
     * @param supplier    a {@code Supplier} whose result is returned if no value is present.
     * @param mapper      a non-interfering, stateless function to apply to the supplied values.
     *
     * @return a float binding
     */
    @Nonnull
    public static FloatBinding mapFloats(@Nonnull final ObservableValue observable1, @Nonnull final ObservableValue observable2, @Nonnull final Supplier supplier, @Nonnull final ObservableValue> mapper) {
        requireNonNull(observable1, ERROR_OBSERVABLE1_NULL);
        requireNonNull(observable2, ERROR_OBSERVABLE2_NULL);
        requireNonNull(supplier, ERROR_SUPPLIER_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createFloatBinding(() -> {
            Number value1 = observable1.getValue();
            Number value2 = observable2.getValue();
            if (value1 != null && value2 != null) {
                BiFunction function = mapper.getValue();
                return requireNonNull(function, ERROR_MAPPER_NULL).apply(value1, value2);
            }
            return requireNonNull(supplier.get(), ERROR_DEFAULT_VALUE_NULL);
        }, observable1, observable2, mapper);
    }

    /**
     * Returns a double binding whose value is the combination of two observable values.
     *
     * @param observable1  the first observable value.
     * @param observable2  the second observable value.
     * @param defaultValue the value to be returned if there are no values present.
     * @param mapper       a non-interfering, stateless function to apply to the supplied values.
     *
     * @return a double binding
     */
    @Nonnull
    public static DoubleBinding mapDoubles(@Nonnull final ObservableValue observable1, @Nonnull final ObservableValue observable2, @Nonnull final Double defaultValue, @Nonnull final BiFunction mapper) {
        requireNonNull(observable1, ERROR_OBSERVABLE1_NULL);
        requireNonNull(observable2, ERROR_OBSERVABLE2_NULL);
        requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createDoubleBinding(() -> {
            Number value1 = observable1.getValue();
            Number value2 = observable2.getValue();
            if (value1 != null && value2 != null) {
                return mapper.apply(value1, value2);
            }
            return defaultValue;
        }, observable1, observable2);
    }

    /**
     * Returns a double binding whose value is the combination of two observable values.
     *
     * @param observable1 the first observable value.
     * @param observable2 the second observable value.
     * @param supplier    a {@code Supplier} whose result is returned if no values are present.
     * @param mapper      a non-interfering, stateless function to apply to the supplied values.
     *
     * @return a double binding
     */
    @Nonnull
    public static DoubleBinding mapDoubles(@Nonnull final ObservableValue observable1, @Nonnull final ObservableValue observable2, @Nonnull final Supplier supplier, @Nonnull final BiFunction mapper) {
        requireNonNull(observable1, ERROR_OBSERVABLE1_NULL);
        requireNonNull(observable2, ERROR_OBSERVABLE2_NULL);
        requireNonNull(supplier, ERROR_SUPPLIER_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createDoubleBinding(() -> {
            Number value1 = observable1.getValue();
            Number value2 = observable2.getValue();
            if (value1 != null && value2 != null) {
                return mapper.apply(value1, value2);
            }
            return requireNonNull(supplier.get(), ERROR_DEFAULT_VALUE_NULL);
        }, observable1, observable2);
    }

    /**
     * Returns a double binding whose value is the combination of two observable values.
     *
     * @param observable1  the first observable value.
     * @param observable2  the second observable value.
     * @param defaultValue the value to be returned if there is no value present.
     * @param mapper       a non-interfering, stateless function to apply to the supplied values.
     *
     * @return a double binding
     */
    @Nonnull
    public static DoubleBinding mapDoubles(@Nonnull final ObservableValue observable1, @Nonnull final ObservableValue observable2, @Nonnull final Double defaultValue, @Nonnull final ObservableValue> mapper) {
        requireNonNull(observable1, ERROR_OBSERVABLE1_NULL);
        requireNonNull(observable2, ERROR_OBSERVABLE2_NULL);
        requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createDoubleBinding(() -> {
            Number value1 = observable1.getValue();
            Number value2 = observable2.getValue();
            if (value1 != null && value2 != null) {
                BiFunction function = mapper.getValue();
                return requireNonNull(function, ERROR_MAPPER_NULL).apply(value1, value2);
            }
            return defaultValue;
        }, observable1, observable2, mapper);
    }

    /**
     * Returns a double binding whose value is the combination of two observable values.
     *
     * @param observable1 the first observable value.
     * @param observable2 the second observable value.
     * @param supplier    a {@code Supplier} whose result is returned if no value is present.
     * @param mapper      a non-interfering, stateless function to apply to the supplied values.
     *
     * @return a double binding
     */
    @Nonnull
    public static DoubleBinding mapDoubles(@Nonnull final ObservableValue observable1, @Nonnull final ObservableValue observable2, @Nonnull final Supplier supplier, @Nonnull final ObservableValue> mapper) {
        requireNonNull(observable1, ERROR_OBSERVABLE1_NULL);
        requireNonNull(observable2, ERROR_OBSERVABLE2_NULL);
        requireNonNull(supplier, ERROR_SUPPLIER_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createDoubleBinding(() -> {
            Number value1 = observable1.getValue();
            Number value2 = observable2.getValue();
            if (value1 != null && value2 != null) {
                BiFunction function = mapper.getValue();
                return requireNonNull(function, ERROR_MAPPER_NULL).apply(value1, value2);
            }
            return requireNonNull(supplier.get(), ERROR_DEFAULT_VALUE_NULL);
        }, observable1, observable2, mapper);
    }

    /**
     * Returns an object binding whose value is the combination of two observable values.
     *
     * @param observable1  the first observable value.
     * @param observable2  the second observable value.
     * @param defaultValue the value to be returned if there are no values present, may be null.
     * @param mapper       a non-interfering, stateless function to apply to the supplied values.
     *
     * @return an object binding
     */
    @Nonnull
    public static  ObjectBinding mapObjects(@Nonnull final ObservableValue observable1, @Nonnull final ObservableValue observable2, @Nullable final R defaultValue, @Nonnull final BiFunction mapper) {
        requireNonNull(observable1, ERROR_OBSERVABLE1_NULL);
        requireNonNull(observable2, ERROR_OBSERVABLE2_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createObjectBinding(() -> {
            A value1 = observable1.getValue();
            B value2 = observable2.getValue();
            if (value1 != null && value2 != null) {
                return mapper.apply(value1, value2);
            }
            return defaultValue;
        }, observable1, observable2);
    }

    /**
     * Returns an object binding whose value is the combination of two observable values.
     *
     * @param observable1 the first observable value.
     * @param observable2 the second observable value.
     * @param supplier    a {@code Supplier} whose result is returnedif no values are present.
     * @param mapper      a non-interfering, stateless function to apply to the supplied values.
     *
     * @return an object binding
     */
    @Nonnull
    public static  ObjectBinding mapObjects(@Nonnull final ObservableValue observable1, @Nonnull final ObservableValue observable2, @Nonnull final Supplier supplier, @Nonnull final BiFunction mapper) {
        requireNonNull(observable1, ERROR_OBSERVABLE1_NULL);
        requireNonNull(observable2, ERROR_OBSERVABLE2_NULL);
        requireNonNull(supplier, ERROR_SUPPLIER_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createObjectBinding(() -> {
            A value1 = observable1.getValue();
            B value2 = observable2.getValue();
            if (value1 != null && value2 != null) {
                return mapper.apply(value1, value2);
            }
            return supplier.get();
        }, observable1, observable2);
    }

    /**
     * Returns an object binding whose value is the combination of two observable values.
     *
     * @param observable1  the first observable value.
     * @param observable2  the second observable value.
     * @param defaultValue the value to be returned if there is no value present, may be null.
     * @param mapper       a non-interfering, stateless function to apply to the supplied values.
     *
     * @return an object binding
     */
    @Nonnull
    public static  ObjectBinding mapObjects(@Nonnull final ObservableValue observable1, @Nonnull final ObservableValue observable2, @Nullable final R defaultValue, @Nonnull final ObservableValue> mapper) {
        requireNonNull(observable1, ERROR_OBSERVABLE1_NULL);
        requireNonNull(observable2, ERROR_OBSERVABLE2_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createObjectBinding(() -> {
            A value1 = observable1.getValue();
            B value2 = observable2.getValue();
            if (value1 != null && value2 != null) {
                BiFunction function = mapper.getValue();
                return requireNonNull(function, ERROR_MAPPER_NULL).apply(value1, value2);
            }
            return defaultValue;
        }, observable1, observable2, mapper);
    }

    /**
     * Returns an object binding whose value is the combination of two observable values.
     *
     * @param observable1 the first observable value.
     * @param observable2 the second observable value.
     * @param supplier    a {@code Supplier} whose result is returned if no values are present.
     * @param mapper      a non-interfering, stateless function to apply to the supplied values.
     *
     * @return an object binding
     */
    @Nonnull
    public static  ObjectBinding mapObjects(@Nonnull final ObservableValue observable1, @Nonnull final ObservableValue observable2, @Nonnull final Supplier supplier, @Nonnull final ObservableValue> mapper) {
        requireNonNull(observable1, ERROR_OBSERVABLE1_NULL);
        requireNonNull(observable2, ERROR_OBSERVABLE2_NULL);
        requireNonNull(supplier, ERROR_SUPPLIER_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createObjectBinding(() -> {
            A value1 = observable1.getValue();
            B value2 = observable2.getValue();
            if (value1 != null && value2 != null) {
                BiFunction function = mapper.getValue();
                return requireNonNull(function, ERROR_MAPPER_NULL).apply(value1, value2);
            }
            return supplier.get();
        }, observable1, observable2, mapper);
    }

    /**
     * Returns a string binding whose value is the combination of two observable values.
     *
     * @param observable1  the first observable value.
     * @param observable2  the second observable value.
     * @param defaultValue the value to be returned if there are no values present.
     * @param mapper       a non-interfering, stateless function to apply to the supplied values.
     *
     * @return a string binding
     */
    @Nonnull
    public static StringBinding mapStrings(@Nonnull final ObservableValue observable1, @Nonnull final ObservableValue observable2, @Nullable final String defaultValue, @Nonnull final BiFunction mapper) {
        requireNonNull(observable1, ERROR_OBSERVABLE1_NULL);
        requireNonNull(observable2, ERROR_OBSERVABLE2_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createStringBinding(() -> {
            String value1 = observable1.getValue();
            String value2 = observable2.getValue();
            if (value1 != null && value2 != null) {
                return mapper.apply(value1, value2);
            }
            return defaultValue;
        }, observable1, observable2);
    }

    /**
     * Returns a string binding whose value is the combination of two observable values.
     *
     * @param observable1 the first observable value.
     * @param observable2 the second observable value.
     * @param supplier    a {@code Supplier} whose result is returned if no values are present.
     * @param mapper      a non-interfering, stateless function to apply to the supplied values.
     *
     * @return a string binding
     */
    @Nonnull
    public static StringBinding mapStrings(@Nonnull final ObservableValue observable1, @Nonnull final ObservableValue observable2, @Nonnull final Supplier supplier, @Nonnull final BiFunction mapper) {
        requireNonNull(observable1, ERROR_OBSERVABLE1_NULL);
        requireNonNull(observable2, ERROR_OBSERVABLE2_NULL);
        requireNonNull(supplier, ERROR_SUPPLIER_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createStringBinding(() -> {
            String value1 = observable1.getValue();
            String value2 = observable2.getValue();
            if (value1 != null && value2 != null) {
                return mapper.apply(value1, value2);
            }
            return supplier.get();
        }, observable1, observable2);
    }

    /**
     * Returns a string binding whose value is the combination of two observable values.
     *
     * @param observable1  the first observable value.
     * @param observable2  the second observable value.
     * @param defaultValue the value to be returned if there is no value present, may be null.
     * @param mapper       a non-interfering, stateless function to apply to the supplied values.
     *
     * @return a string binding
     */
    @Nonnull
    public static StringBinding mapStrings(@Nonnull final ObservableValue observable1, @Nonnull final ObservableValue observable2, @Nullable final String defaultValue, @Nonnull final ObservableValue> mapper) {
        requireNonNull(observable1, ERROR_OBSERVABLE1_NULL);
        requireNonNull(observable2, ERROR_OBSERVABLE2_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createStringBinding(() -> {
            String value1 = observable1.getValue();
            String value2 = observable2.getValue();
            if (value1 != null && value2 != null) {
                BiFunction function = mapper.getValue();
                return requireNonNull(function, ERROR_MAPPER_NULL).apply(value1, value2);
            }
            return defaultValue;
        }, observable1, observable2, mapper);
    }

    /**
     * Returns a string binding whose value is the combination of two observable values.
     *
     * @param observable1 the first observable value.
     * @param observable2 the second observable value.
     * @param supplier    a {@code Supplier} whose result is returned if no values are present.
     * @param mapper      a non-interfering, stateless function to apply to the supplied values.
     *
     * @return a string binding
     */
    @Nonnull
    public static StringBinding mapStrings(@Nonnull final ObservableValue observable1, @Nonnull final ObservableValue observable2, @Nonnull final Supplier supplier, @Nonnull final ObservableValue> mapper) {
        requireNonNull(observable1, ERROR_OBSERVABLE1_NULL);
        requireNonNull(observable2, ERROR_OBSERVABLE2_NULL);
        requireNonNull(supplier, ERROR_SUPPLIER_NULL);
        requireNonNull(mapper, ERROR_MAPPER_NULL);
        return createStringBinding(() -> {
            String value1 = observable1.getValue();
            String value2 = observable2.getValue();
            if (value1 != null && value2 != null) {
                BiFunction function = mapper.getValue();
                return requireNonNull(function, ERROR_MAPPER_NULL).apply(value1, value2);
            }
            return supplier.get();
        }, observable1, observable2, mapper);
    }

    /**
     * Creates an integer binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     *
     * @return an integer binding.
     */
    @Nonnull
    public static IntegerBinding mapInteger(@Nonnull final ObservableValue observable) {
        return mapInteger(observable, 0);
    }

    /**
     * Creates an integer binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable   the source observable.
     * @param defaultValue the value to be returned if there is no value present, may be null.
     *
     * @return an integer binding.
     */
    @Nonnull
    public static IntegerBinding mapInteger(@Nonnull final ObservableValue observable, @Nullable final Integer defaultValue) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        if (observable instanceof IntegerBinding) {
            return (IntegerBinding) observable;
        }
        return createIntegerBinding(() -> {
            Number value = observable.getValue();
            return value != null ? value.intValue() : defaultValue;
        }, observable);
    }

    /**
     * Creates an integer binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     * @param supplier   a {@code Supplier} whose result is returned if no value is present.
     *
     * @return an integer binding.
     */
    @Nonnull
    public static IntegerBinding mapInteger(@Nonnull final ObservableValue observable, @Nullable final Supplier supplier) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(supplier, ERROR_SUPPLIER_NULL);
        if (observable instanceof IntegerBinding) {
            return (IntegerBinding) observable;
        }
        return createIntegerBinding(() -> {
            Number value = observable.getValue();
            return value != null ? value.intValue() : supplier.get();
        }, observable);
    }

    /**
     * Creates a long binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     *
     * @return a long binding.
     */
    @Nonnull
    public static LongBinding mapLong(@Nonnull final ObservableValue observable) {
        return mapLong(observable, 0L);
    }

    /**
     * Creates a long binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable   the source observable.
     * @param defaultValue the value to be returned if there is no value present, may be null.
     *
     * @return a long binding.
     */
    @Nonnull
    public static LongBinding mapLong(@Nonnull final ObservableValue observable, @Nullable final Long defaultValue) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        if (observable instanceof LongBinding) {
            return (LongBinding) observable;
        }
        return createLongBinding(() -> {
            Number value = observable.getValue();
            return value != null ? value.longValue() : defaultValue;
        }, observable);
    }

    /**
     * Creates a long binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     * @param supplier   a {@code Supplier} whose result is returned if no value is present.
     *
     * @return a long binding.
     */
    @Nonnull
    public static LongBinding mapLong(@Nonnull final ObservableValue observable, @Nullable final Supplier supplier) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(supplier, ERROR_SUPPLIER_NULL);
        if (observable instanceof LongBinding) {
            return (LongBinding) observable;
        }
        return createLongBinding(() -> {
            Number value = observable.getValue();
            return value != null ? value.longValue() : supplier.get();
        }, observable);
    }

    /**
     * Creates a float binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     *
     * @return a float binding.
     */
    @Nonnull
    public static FloatBinding mapFloat(@Nonnull final ObservableValue observable) {
        return mapFloat(observable, 0f);
    }

    /**
     * Creates a float binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable   the source observable.
     * @param defaultValue the value to be returned if there is no value present, may be null.
     *
     * @return a float binding.
     */
    @Nonnull
    public static FloatBinding mapFloat(@Nonnull final ObservableValue observable, @Nullable final Float defaultValue) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        if (observable instanceof FloatBinding) {
            return (FloatBinding) observable;
        }
        return createFloatBinding(() -> {
            Number value = observable.getValue();
            return value != null ? value.floatValue() : defaultValue;
        }, observable);
    }

    /**
     * Creates a float binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     * @param supplier   a {@code Supplier} whose result is returned if no value is present.
     *
     * @return a float binding.
     */
    @Nonnull
    public static FloatBinding mapFloat(@Nonnull final ObservableValue observable, @Nullable final Supplier supplier) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(supplier, ERROR_SUPPLIER_NULL);
        if (observable instanceof FloatBinding) {
            return (FloatBinding) observable;
        }
        return createFloatBinding(() -> {
            Number value = observable.getValue();
            return value != null ? value.floatValue() : supplier.get();
        }, observable);
    }

    /**
     * Creates a double binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     *
     * @return a double binding.
     */
    @Nonnull
    public static DoubleBinding mapDouble(@Nonnull final ObservableValue observable) {
        return mapDouble(observable, 0d);
    }

    /**
     * Creates a double binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable   the source observable.
     * @param defaultValue the value to be returned if there is no value present, may be null.
     *
     * @return a double binding.
     */
    @Nonnull
    public static DoubleBinding mapDouble(@Nonnull final ObservableValue observable, @Nullable final Double defaultValue) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        if (observable instanceof DoubleBinding) {
            return (DoubleBinding) observable;
        }
        return createDoubleBinding(() -> {
            Number value = observable.getValue();
            return value != null ? value.doubleValue() : defaultValue;
        }, observable);
    }

    /**
     * Creates a double binding containing the value of the mapper function applied to the source observable.
     *
     * @param observable the source observable.
     * @param supplier   a {@code Supplier} whose result is returned if no value is present.
     *
     * @return a double binding.
     */
    @Nonnull
    public static DoubleBinding mapDouble(@Nonnull final ObservableValue observable, @Nullable final Supplier supplier) {
        requireNonNull(observable, ERROR_OBSERVABLE_NULL);
        requireNonNull(supplier, ERROR_SUPPLIER_NULL);
        if (observable instanceof DoubleBinding) {
            return (DoubleBinding) observable;
        }
        return createDoubleBinding(() -> {
            Number value = observable.getValue();
            return value != null ? value.doubleValue() : supplier.get();
        }, observable);
    }
}