CollectionBindings.java
0001 /*
0002  * SPDX-License-Identifier: Apache-2.0
0003  *
0004  * Copyright 2008-2017 the original author or authors.
0005  *
0006  * Licensed under the Apache License, Version 2.0 (the "License");
0007  * you may not use this file except in compliance with the License.
0008  * You may obtain a copy of the License at
0009  *
0010  *     http://www.apache.org/licenses/LICENSE-2.0
0011  *
0012  * Unless required by applicable law or agreed to in writing, software
0013  * distributed under the License is distributed on an "AS IS" BASIS,
0014  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0015  * See the License for the specific language governing permissions and
0016  * limitations under the License.
0017  */
0018 package griffon.javafx.beans.binding;
0019 
0020 import javafx.beans.binding.NumberBinding;
0021 import javafx.beans.binding.StringBinding;
0022 import javafx.beans.value.ObservableValue;
0023 import javafx.collections.ObservableList;
0024 import javafx.collections.ObservableMap;
0025 import javafx.collections.ObservableSet;
0026 
0027 import javax.annotation.Nonnull;
0028 import javax.annotation.Nullable;
0029 import java.util.Map;
0030 import java.util.function.DoubleSupplier;
0031 import java.util.function.Function;
0032 import java.util.function.Supplier;
0033 import java.util.function.ToDoubleFunction;
0034 
0035 import static java.util.Objects.requireNonNull;
0036 import static java.util.stream.Collectors.joining;
0037 import static javafx.beans.binding.Bindings.createDoubleBinding;
0038 import static javafx.beans.binding.Bindings.createStringBinding;
0039 
0040 /**
0041  @author Andres Almiray
0042  @since 2.10.0
0043  */
0044 public final class CollectionBindings {
0045     private static final String ERROR_ITEMS_NULL = "Argument 'items' must not be null";
0046     private static final String ERROR_MAPPER_NULL = "Argument 'mapper' must not be null";
0047     private static final String ERROR_SUPPLIER_NULL = "Argument 'supplier' must not be null";
0048     private static final String ERROR_DELIMITER_NULL = "Argument 'delimiter' must not be null";
0049     private static final String ERROR_DEFAULT_VALUE_NULL = "Argument 'defaultValue' must not be null";
0050 
0051     private CollectionBindings() {
0052         // prevent instantiation
0053     }
0054 
0055     /**
0056      * Creates a string binding that constructs a sequence of characters separated by a delimiter.
0057      *
0058      @param items     the observable list of items.
0059      @param delimiter the sequence of characters to be used between each element.
0060      *
0061      @return a string binding.
0062      */
0063     @Nonnull
0064     public static StringBinding joinList(@Nonnull final ObservableList<?> items, @Nullable final String delimiter) {
0065         return joinList(items, delimiter, String::valueOf);
0066     }
0067 
0068     /**
0069      * Creates a string binding that constructs a sequence of characters separated by a delimiter.
0070      *
0071      @param items     the observable list of items.
0072      @param delimiter the sequence of characters to be used between each element.
0073      @param mapper    a non-interfering, stateless function to apply to the each element.
0074      *
0075      @return a string binding.
0076      */
0077     @Nonnull
0078     public static <T> StringBinding joinList(@Nonnull final ObservableList<T> items, @Nullable final String delimiter, @Nonnull final Function<? super T, String> mapper) {
0079         requireNonNull(items, ERROR_ITEMS_NULL);
0080         requireNonNull(mapper, ERROR_MAPPER_NULL);
0081         final String value = delimiter == null "" : delimiter;
0082         return createStringBinding(() -> items.stream().map(mapper).collect(joining(value)), items);
0083     }
0084 
0085     /**
0086      * Creates a string binding that constructs a sequence of characters separated by a delimiter.
0087      *
0088      @param items     the observable list of items.
0089      @param delimiter the sequence of characters to be used between each element.
0090      *
0091      @return a string binding.
0092      */
0093     @Nonnull
0094     public static StringBinding joinList(@Nonnull final ObservableList<?> items, @Nonnull final ObservableValue<String> delimiter) {
0095         requireNonNull(items, ERROR_ITEMS_NULL);
0096         requireNonNull(delimiter, ERROR_DELIMITER_NULL);
0097         return createStringBinding(() -> {
0098             String value = delimiter.getValue();
0099             value = value == null "" : value;
0100             return items.stream().map(String::valueOf).collect(joining(value));
0101         }, items, delimiter);
0102     }
0103 
0104     /**
0105      * Creates a string binding that constructs a sequence of characters separated by a delimiter.
0106      *
0107      @param items     the observable list of items.
0108      @param delimiter the sequence of characters to be used between each element.
0109      @param mapper    a non-interfering, stateless function to apply to the each element.
0110      *
0111      @return a string binding.
0112      */
0113     @Nonnull
0114     public static <T> StringBinding joinList(@Nonnull final ObservableList<T> items, @Nonnull final ObservableValue<String> delimiter, @Nonnull final ObservableValue<Function<? super T, String>> mapper) {
0115         requireNonNull(items, ERROR_ITEMS_NULL);
0116         requireNonNull(delimiter, ERROR_DELIMITER_NULL);
0117         requireNonNull(mapper, ERROR_MAPPER_NULL);
0118         return createStringBinding(() -> {
0119             String value = delimiter.getValue();
0120             value = value == null "" : value;
0121             final Function<? super T, String> mapperValue = mapper.getValue() != null ? mapper.getValue() : String::valueOf;
0122             return items.stream().map(mapperValue).collect(joining(value));
0123         }, items, delimiter, mapper);
0124     }
0125 
0126     /**
0127      * Creates a string binding that constructs a sequence of characters separated by a delimiter.
0128      *
0129      @param items     the observable set of items.
0130      @param delimiter the sequence of characters to be used between each element.
0131      *
0132      @return a string binding.
0133      */
0134     @Nonnull
0135     public static StringBinding joinSet(@Nonnull final ObservableSet<?> items, @Nullable final String delimiter) {
0136         return joinSet(items, delimiter, String::valueOf);
0137     }
0138 
0139     /**
0140      * Creates a string binding that constructs a sequence of characters separated by a delimiter.
0141      *
0142      @param items     the observable set of items.
0143      @param delimiter the sequence of characters to be used between each element.
0144      @param mapper    a non-interfering, stateless function to apply to the each element.
0145      *
0146      @return a string binding.
0147      */
0148     @Nonnull
0149     public static <T> StringBinding joinSet(@Nonnull final ObservableSet<T> items, @Nullable final String delimiter, @Nonnull final Function<? super T, String> mapper) {
0150         requireNonNull(items, ERROR_ITEMS_NULL);
0151         requireNonNull(mapper, ERROR_MAPPER_NULL);
0152         final String value = delimiter == null "" : delimiter;
0153         return createStringBinding(() -> items.stream().map(mapper).collect(joining(value)), items);
0154     }
0155 
0156     /**
0157      * Creates a string binding that constructs a sequence of characters separated by a delimiter.
0158      *
0159      @param items     the observable set of items.
0160      @param delimiter the sequence of characters to be used between each element.
0161      *
0162      @return a string binding.
0163      */
0164     @Nonnull
0165     public static StringBinding joinSet(@Nonnull final ObservableSet<?> items, @Nonnull final ObservableValue<String> delimiter) {
0166         requireNonNull(items, ERROR_ITEMS_NULL);
0167         requireNonNull(delimiter, ERROR_DELIMITER_NULL);
0168         return createStringBinding(() -> {
0169             String value = delimiter.getValue();
0170             value = value == null "" : value;
0171             return items.stream().map(String::valueOf).collect(joining(value));
0172         }, items, delimiter);
0173     }
0174 
0175     /**
0176      * Creates a string binding that constructs a sequence of characters separated by a delimiter.
0177      *
0178      @param items     the observable set of items.
0179      @param delimiter the sequence of characters to be used between each element.
0180      @param mapper    a non-interfering, stateless function to apply to the each element.
0181      *
0182      @return a string binding.
0183      */
0184     @Nonnull
0185     public static <T> StringBinding joinSet(@Nonnull final ObservableSet<T> items, @Nonnull final ObservableValue<String> delimiter, @Nonnull final ObservableValue<Function<? super T, String>> mapper) {
0186         requireNonNull(items, ERROR_ITEMS_NULL);
0187         requireNonNull(delimiter, ERROR_DELIMITER_NULL);
0188         requireNonNull(mapper, ERROR_MAPPER_NULL);
0189         return createStringBinding(() -> {
0190             String value = delimiter.getValue();
0191             value = value == null "" : value;
0192             final Function<? super T, String> mapperValue = mapper.getValue() != null ? mapper.getValue() : String::valueOf;
0193             return items.stream().map(mapperValue).collect(joining(value));
0194         }, items, delimiter, mapper);
0195     }
0196 
0197     /**
0198      * Creates a string binding that constructs a sequence of characters separated by a delimiter.
0199      *
0200      @param items     the observable map of items.
0201      @param delimiter the sequence of characters to be used between each entry.
0202      *
0203      @return a string binding.
0204      */
0205     @Nonnull
0206     public static <K, V> StringBinding joinMap(@Nonnull final ObservableMap<K, V> items, @Nullable final String delimiter) {
0207         return joinMap(items, delimiter, entry -> String.valueOf(entry.getKey()) "=" + String.valueOf(entry.getValue()));
0208     }
0209 
0210     /**
0211      * Creates a string binding that constructs a sequence of characters separated by a delimiter.
0212      *
0213      @param items     the observable map of items.
0214      @param delimiter the sequence of characters to be used between each element.
0215      @param mapper    a non-interfering, stateless function to apply to the each entry.
0216      *
0217      @return a string binding.
0218      */
0219     @Nonnull
0220     public static <K, V> StringBinding joinMap(@Nonnull final ObservableMap<K, V> items, @Nullable final String delimiter, @Nonnull final Function<Map.Entry<K, V>, String> mapper) {
0221         requireNonNull(items, ERROR_ITEMS_NULL);
0222         requireNonNull(mapper, ERROR_MAPPER_NULL);
0223         final String value = delimiter == null "," : delimiter;
0224         return createStringBinding(() -> items.entrySet().stream().map(mapper).collect(joining(value)), items);
0225     }
0226 
0227     /**
0228      * Creates a string binding that constructs a sequence of characters separated by a delimiter.
0229      *
0230      @param items     the observable map of items.
0231      @param delimiter the sequence of characters to be used between each entry.
0232      *
0233      @return a string binding.
0234      */
0235     @Nonnull
0236     public static <K, V> StringBinding joinMap(@Nonnull final ObservableMap<K, V> items, @Nonnull final ObservableValue<String> delimiter) {
0237         requireNonNull(items, ERROR_ITEMS_NULL);
0238         requireNonNull(delimiter, ERROR_DELIMITER_NULL);
0239         final Function<Map.Entry<K, V>, String> mapper = entry -> String.valueOf(entry.getKey()) "=" + String.valueOf(entry.getValue());
0240         return createStringBinding(() -> {
0241             String value = delimiter.getValue();
0242             value = value == null "" : value;
0243             return items.entrySet().stream().map(mapper).collect(joining(value));
0244         }, items, delimiter);
0245     }
0246 
0247     /**
0248      * Creates a string binding that constructs a sequence of characters separated by a delimiter.
0249      *
0250      @param items     the observable map of items.
0251      @param delimiter the sequence of characters to be used between each element.
0252      @param mapper    a non-interfering, stateless function to apply to the each entry.
0253      *
0254      @return a string binding.
0255      */
0256     @Nonnull
0257     public static <K, V> StringBinding joinMap(@Nonnull final ObservableMap<K, V> items, @Nonnull final ObservableValue<String> delimiter, @Nonnull final ObservableValue<Function<Map.Entry<K, V>, String>> mapper) {
0258         requireNonNull(items, ERROR_ITEMS_NULL);
0259         requireNonNull(delimiter, ERROR_DELIMITER_NULL);
0260         requireNonNull(mapper, ERROR_MAPPER_NULL);
0261         final Function<Map.Entry<K, V>, String> mv = entry -> String.valueOf(entry.getKey()) "=" + String.valueOf(entry.getValue());
0262         return createStringBinding(() -> {
0263             String value = delimiter.getValue();
0264             value = value == null "" : value;
0265             final Function<Map.Entry<K, V>, String> mapperValue = mapper.getValue() != null ? mapper.getValue() : mv;
0266             return items.entrySet().stream().map(mapperValue).collect(joining(value));
0267         }, items, delimiter, mapper);
0268     }
0269 
0270     /**
0271      * Creates a number binding that computes the minimum value amongst elements.
0272      *
0273      @param items        the observable list of items.
0274      @param defaultValue the value to be returned if there is no value present.
0275      *
0276      @return a number binding
0277      */
0278     @Nonnull
0279     public static NumberBinding minInList(@Nonnull final ObservableList<? extends Number> items, @Nonnull final Number defaultValue) {
0280         requireNonNull(items, ERROR_ITEMS_NULL);
0281         requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
0282         return createDoubleBinding(() -> items.stream().mapToDouble(Number::doubleValue).min().orElse(defaultValue.doubleValue()), items);
0283     }
0284 
0285     /**
0286      * Creates a number binding that computes the minimum value amongst elements.
0287      *
0288      @param items    the observable list of items.
0289      @param supplier a {@code Supplier} whose result is returned if no value is present.
0290      *
0291      @return a number binding
0292      */
0293     @Nonnull
0294     public static NumberBinding minInList(@Nonnull final ObservableList<? extends Number> items, @Nonnull final Supplier<? extends Number> supplier) {
0295         requireNonNull(items, ERROR_ITEMS_NULL);
0296         requireNonNull(supplier, ERROR_SUPPLIER_NULL);
0297         return createDoubleBinding(() -> items.stream().mapToDouble(Number::doubleValue).min().orElseGet(resolveDoubleSupplier(supplier)), items);
0298     }
0299 
0300     /**
0301      * Creates a number binding that computes the maximum value amongst elements.
0302      *
0303      @param items        the observable list of items.
0304      @param defaultValue the value to be returned if there is no value present.
0305      *
0306      @return a number binding
0307      */
0308     @Nonnull
0309     public static NumberBinding maxInList(@Nonnull final ObservableList<? extends Number> items, @Nonnull final Number defaultValue) {
0310         requireNonNull(items, ERROR_ITEMS_NULL);
0311         requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
0312         return createDoubleBinding(() -> items.stream().mapToDouble(Number::doubleValue).max().orElse(defaultValue.doubleValue()), items);
0313     }
0314 
0315     /**
0316      * Creates a number binding that computes the maximum value amongst elements.
0317      *
0318      @param items    the observable list of items.
0319      @param supplier a {@code Supplier} whose result is returned if no value is present.
0320      *
0321      @return a number binding
0322      */
0323     @Nonnull
0324     public static NumberBinding maxInList(@Nonnull final ObservableList<? extends Number> items, @Nonnull final Supplier<? extends Number> supplier) {
0325         requireNonNull(items, ERROR_ITEMS_NULL);
0326         requireNonNull(supplier, ERROR_SUPPLIER_NULL);
0327         return createDoubleBinding(() -> items.stream().mapToDouble(Number::doubleValue).max().orElseGet(resolveDoubleSupplier(supplier)), items);
0328     }
0329 
0330     /**
0331      * Creates a number binding that computes the average value amongst elements.
0332      *
0333      @param items        the observable list of items.
0334      @param defaultValue the value to be returned if there is no value present.
0335      *
0336      @return a number binding
0337      */
0338     @Nonnull
0339     public static NumberBinding averageInList(@Nonnull final ObservableList<? extends Number> items, @Nonnull final Number defaultValue) {
0340         requireNonNull(items, ERROR_ITEMS_NULL);
0341         requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
0342         return createDoubleBinding(() -> items.stream().mapToDouble(Number::doubleValue).average().orElse(defaultValue.doubleValue()), items);
0343     }
0344 
0345     /**
0346      * Creates a number binding that computes the average value amongst elements.
0347      *
0348      @param items    the observable list of items.
0349      @param supplier a {@code Supplier} whose result is returned if no value is present.
0350      *
0351      @return a number binding
0352      */
0353     @Nonnull
0354     public static NumberBinding averageInList(@Nonnull final ObservableList<? extends Number> items, @Nonnull final Supplier<? extends Number> supplier) {
0355         requireNonNull(items, ERROR_ITEMS_NULL);
0356         requireNonNull(supplier, ERROR_SUPPLIER_NULL);
0357         return createDoubleBinding(() -> items.stream().mapToDouble(Number::doubleValue).average().orElseGet(resolveDoubleSupplier(supplier)), items);
0358     }
0359 
0360     /**
0361      * Creates a number binding that contains the sum of the items of the given observable list.
0362      *
0363      @param items the observable list of items.
0364      *
0365      @return a number binding.
0366      */
0367     @Nonnull
0368     public static NumberBinding sumOfList(@Nonnull final ObservableList<? extends Number> items) {
0369         requireNonNull(items, ERROR_ITEMS_NULL);
0370         return createDoubleBinding(() -> items.stream().mapToDouble(Number::doubleValue).sum(), items);
0371     }
0372 
0373     /**
0374      * Creates a number binding that computes the minimum value amongst elements.
0375      *
0376      @param items        the observable list of items.
0377      @param defaultValue the value to be returned if there is no value present.
0378      @param mapper       a non-interfering, stateless function to apply to the each element.
0379      *
0380      @return a number binding
0381      */
0382     @Nonnull
0383     public static <T> NumberBinding minInList(@Nonnull final ObservableList<T> items, @Nonnull final Number defaultValue, @Nonnull final ToDoubleFunction<? super T> mapper) {
0384         requireNonNull(items, ERROR_ITEMS_NULL);
0385         requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
0386         requireNonNull(mapper, ERROR_MAPPER_NULL);
0387         return createDoubleBinding(() -> items.stream().mapToDouble(mapper).min().orElse(defaultValue.doubleValue()), items);
0388     }
0389 
0390     /**
0391      * Creates a number binding that computes the minimum value amongst elements.
0392      *
0393      @param items    the observable list of items.
0394      @param supplier a {@code Supplier} whose result is returned if no value is present.
0395      @param mapper   a non-interfering, stateless function to apply to the each element.
0396      *
0397      @return a number binding
0398      */
0399     @Nonnull
0400     public static <T> NumberBinding minInList(@Nonnull final ObservableList<T> items, @Nonnull final Supplier<? extends Number> supplier, @Nonnull final ToDoubleFunction<? super T> mapper) {
0401         requireNonNull(items, ERROR_ITEMS_NULL);
0402         requireNonNull(supplier, ERROR_SUPPLIER_NULL);
0403         requireNonNull(mapper, ERROR_MAPPER_NULL);
0404         return createDoubleBinding(() -> items.stream().mapToDouble(mapper).min().orElseGet(resolveDoubleSupplier(supplier)), items);
0405     }
0406 
0407     /**
0408      * Creates a number binding that computes the maximum value amongst elements.
0409      *
0410      @param items        the observable list of items.
0411      @param defaultValue the value to be returned if there is no value present.
0412      @param mapper       a non-interfering, stateless function to apply to the each element.
0413      *
0414      @return a number binding
0415      */
0416     @Nonnull
0417     public static <T> NumberBinding maxInList(@Nonnull final ObservableList<T> items, @Nonnull final Number defaultValue, @Nonnull final ToDoubleFunction<? super T> mapper) {
0418         requireNonNull(items, ERROR_ITEMS_NULL);
0419         requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
0420         requireNonNull(mapper, ERROR_MAPPER_NULL);
0421         return createDoubleBinding(() -> items.stream().mapToDouble(mapper).max().orElse(defaultValue.doubleValue()), items);
0422     }
0423 
0424     /**
0425      * Creates a number binding that computes the maximum value amongst elements.
0426      *
0427      @param items    the observable list of items.
0428      @param supplier a {@code Supplier} whose result is returned if no value is present.
0429      @param mapper   a non-interfering, stateless function to apply to the each element.
0430      *
0431      @return a number binding
0432      */
0433     @Nonnull
0434     public static <T> NumberBinding maxInList(@Nonnull final ObservableList<T> items, @Nonnull final Supplier<? extends Number> supplier, @Nonnull final ToDoubleFunction<? super T> mapper) {
0435         requireNonNull(items, ERROR_ITEMS_NULL);
0436         requireNonNull(supplier, ERROR_SUPPLIER_NULL);
0437         requireNonNull(mapper, ERROR_MAPPER_NULL);
0438         return createDoubleBinding(() -> items.stream().mapToDouble(mapper).max().orElseGet(resolveDoubleSupplier(supplier)), items);
0439     }
0440 
0441     /**
0442      * Creates a number binding that computes the average value amongst elements.
0443      *
0444      @param items        the observable list of items.
0445      @param defaultValue the value to be returned if there is no value present.
0446      @param mapper       a non-interfering, stateless function to apply to the each element.
0447      *
0448      @return a number binding
0449      */
0450     @Nonnull
0451     public static <T> NumberBinding averageInList(@Nonnull final ObservableList<T> items, @Nonnull final Number defaultValue, @Nonnull final ToDoubleFunction<? super T> mapper) {
0452         requireNonNull(items, ERROR_ITEMS_NULL);
0453         requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
0454         requireNonNull(mapper, ERROR_MAPPER_NULL);
0455         return createDoubleBinding(() -> items.stream().mapToDouble(mapper).average().orElse(defaultValue.doubleValue()), items);
0456     }
0457 
0458     /**
0459      * Creates a number binding that computes the average value amongst elements.
0460      *
0461      @param items    the observable list of items.
0462      @param supplier a {@code Supplier} whose result is returned if no value is present.
0463      @param mapper   a non-interfering, stateless function to apply to the each element.
0464      *
0465      @return a number binding
0466      */
0467     @Nonnull
0468     public static <T> NumberBinding averageInList(@Nonnull final ObservableList<T> items, @Nonnull final Supplier<? extends Number> supplier, @Nonnull final ToDoubleFunction<? super T> mapper) {
0469         requireNonNull(items, ERROR_ITEMS_NULL);
0470         requireNonNull(supplier, ERROR_SUPPLIER_NULL);
0471         requireNonNull(mapper, ERROR_MAPPER_NULL);
0472         return createDoubleBinding(() -> items.stream().mapToDouble(mapper).average().orElseGet(resolveDoubleSupplier(supplier)), items);
0473     }
0474 
0475     /**
0476      * Creates a number binding that contains the sum of the items of the given observable list.
0477      *
0478      @param items  the observable list of items.
0479      @param mapper a non-interfering, stateless function to apply to the each element.
0480      *
0481      @return a number binding.
0482      */
0483     @Nonnull
0484     public static <T> NumberBinding sumOfList(@Nonnull final ObservableList<T> items, @Nonnull final ToDoubleFunction<? super T> mapper) {
0485         requireNonNull(items, ERROR_ITEMS_NULL);
0486         requireNonNull(mapper, ERROR_MAPPER_NULL);
0487         return createDoubleBinding(() -> items.stream().mapToDouble(mapper).sum(), items);
0488     }
0489 
0490     /**
0491      * Creates a number binding that computes the minimum value amongst elements.
0492      *
0493      @param items        the observable list of items.
0494      @param defaultValue the value to be returned if there is no value present.
0495      @param mapper       a non-interfering, stateless function to apply to the each element.
0496      *
0497      @return a number binding
0498      */
0499     @Nonnull
0500     public static <T> NumberBinding minInList(@Nonnull final ObservableList<T> items, @Nonnull final Number defaultValue, @Nonnull final ObservableValue<ToDoubleFunction<? super T>> mapper) {
0501         requireNonNull(items, ERROR_ITEMS_NULL);
0502         requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
0503         requireNonNull(mapper, ERROR_MAPPER_NULL);
0504         return createDoubleBinding(() -> {
0505             ToDoubleFunction<? super T> mapperValue = mapper.getValue();
0506             requireNonNull(mapperValue, ERROR_MAPPER_NULL);
0507             return items.stream().mapToDouble(mapperValue).min().orElse(defaultValue.doubleValue());
0508         }, items, mapper);
0509     }
0510 
0511     /**
0512      * Creates a number binding that computes the minimum value amongst elements.
0513      *
0514      @param items    the observable list of items.
0515      @param supplier a {@code Supplier} whose result is returned if no value is present.
0516      @param mapper   a non-interfering, stateless function to apply to the each element.
0517      *
0518      @return a number binding
0519      */
0520     @Nonnull
0521     public static <T> NumberBinding minInList(@Nonnull final ObservableList<T> items, @Nonnull final Supplier<? extends Number> supplier, @Nonnull final ObservableValue<ToDoubleFunction<? super T>> mapper) {
0522         requireNonNull(items, ERROR_ITEMS_NULL);
0523         requireNonNull(supplier, ERROR_SUPPLIER_NULL);
0524         requireNonNull(mapper, ERROR_MAPPER_NULL);
0525         return createDoubleBinding(() -> {
0526             ToDoubleFunction<? super T> mapperValue = mapper.getValue();
0527             requireNonNull(mapperValue, ERROR_MAPPER_NULL);
0528             return items.stream().mapToDouble(mapperValue).min().orElseGet(resolveDoubleSupplier(supplier));
0529         }, items, mapper);
0530     }
0531 
0532     /**
0533      * Creates a number binding that computes the maximum value amongst elements.
0534      *
0535      @param items        the observable list of items.
0536      @param defaultValue the value to be returned if there is no value present.
0537      @param mapper       a non-interfering, stateless function to apply to the each element.
0538      *
0539      @return a number binding
0540      */
0541     @Nonnull
0542     public static <T> NumberBinding maxInList(@Nonnull final ObservableList<T> items, @Nonnull final Number defaultValue, @Nonnull final ObservableValue<ToDoubleFunction<? super T>> mapper) {
0543         requireNonNull(items, ERROR_ITEMS_NULL);
0544         requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
0545         requireNonNull(mapper, ERROR_MAPPER_NULL);
0546         return createDoubleBinding(() -> {
0547             ToDoubleFunction<? super T> mapperValue = mapper.getValue();
0548             requireNonNull(mapperValue, ERROR_MAPPER_NULL);
0549             return items.stream().mapToDouble(mapperValue).max().orElse(defaultValue.doubleValue());
0550         }, items, mapper);
0551     }
0552 
0553     /**
0554      * Creates a number binding that computes the maximum value amongst elements.
0555      *
0556      @param items    the observable list of items.
0557      @param supplier a {@code Supplier} whose result is returned if no value is present.
0558      @param mapper   a non-interfering, stateless function to apply to the each element.
0559      *
0560      @return a number binding
0561      */
0562     @Nonnull
0563     public static <T> NumberBinding maxInList(@Nonnull final ObservableList<T> items, @Nonnull final Supplier<? extends Number> supplier, @Nonnull final ObservableValue<ToDoubleFunction<? super T>> mapper) {
0564         requireNonNull(items, ERROR_ITEMS_NULL);
0565         requireNonNull(supplier, ERROR_SUPPLIER_NULL);
0566         requireNonNull(mapper, ERROR_MAPPER_NULL);
0567         return createDoubleBinding(() -> {
0568             ToDoubleFunction<? super T> mapperValue = mapper.getValue();
0569             requireNonNull(mapperValue, ERROR_MAPPER_NULL);
0570             return items.stream().mapToDouble(mapperValue).max().orElseGet(resolveDoubleSupplier(supplier));
0571         }, items, mapper);
0572     }
0573 
0574     /**
0575      * Creates a number binding that computes the average value amongst elements.
0576      *
0577      @param items        the observable list of items.
0578      @param defaultValue the value to be returned if there is no value present.
0579      @param mapper       a non-interfering, stateless function to apply to the each element.
0580      *
0581      @return a number binding
0582      */
0583     @Nonnull
0584     public static <T> NumberBinding averageInList(@Nonnull final ObservableList<T> items, @Nonnull final Number defaultValue, @Nonnull final ObservableValue<ToDoubleFunction<? super T>> mapper) {
0585         requireNonNull(items, ERROR_ITEMS_NULL);
0586         requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
0587         requireNonNull(mapper, ERROR_MAPPER_NULL);
0588         return createDoubleBinding(() -> {
0589             ToDoubleFunction<? super T> mapperValue = mapper.getValue();
0590             requireNonNull(mapperValue, ERROR_MAPPER_NULL);
0591             return items.stream().mapToDouble(mapperValue).average().orElse(defaultValue.doubleValue());
0592         }, items, mapper);
0593     }
0594 
0595     /**
0596      * Creates a number binding that computes the average value amongst elements.
0597      *
0598      @param items    the observable list of items.
0599      @param supplier a {@code Supplier} whose result is returned if no value is present.
0600      @param mapper   a non-interfering, stateless function to apply to the each element.
0601      *
0602      @return a number binding
0603      */
0604     @Nonnull
0605     public static <T> NumberBinding averageInList(@Nonnull final ObservableList<T> items, @Nonnull final Supplier<? extends Number> supplier, @Nonnull final ObservableValue<ToDoubleFunction<? super T>> mapper) {
0606         requireNonNull(items, ERROR_ITEMS_NULL);
0607         requireNonNull(supplier, ERROR_SUPPLIER_NULL);
0608         requireNonNull(mapper, ERROR_MAPPER_NULL);
0609         return createDoubleBinding(() -> {
0610             ToDoubleFunction<? super T> mapperValue = mapper.getValue();
0611             requireNonNull(mapperValue, ERROR_MAPPER_NULL);
0612             return items.stream().mapToDouble(mapperValue).average().orElseGet(resolveDoubleSupplier(supplier));
0613         }, items, mapper);
0614     }
0615 
0616     /**
0617      * Creates a number binding that contains the sum of the items of the given observable list.
0618      *
0619      @param items  the observable list of items.
0620      @param mapper a non-interfering, stateless function to apply to the each element.
0621      *
0622      @return a number binding.
0623      */
0624     @Nonnull
0625     public static <T> NumberBinding sumOfList(@Nonnull final ObservableList<T> items, @Nonnull final ObservableValue<ToDoubleFunction<? super T>> mapper) {
0626         requireNonNull(items, ERROR_ITEMS_NULL);
0627         requireNonNull(mapper, ERROR_MAPPER_NULL);
0628         return createDoubleBinding(() -> {
0629             ToDoubleFunction<? super T> mapperValue = mapper.getValue();
0630             requireNonNull(mapperValue, ERROR_MAPPER_NULL);
0631             return items.stream().mapToDouble(mapperValue).sum();
0632         }, items, mapper);
0633     }
0634 
0635     /**
0636      * Creates a number binding that computes the minimum value amongst elements.
0637      *
0638      @param items        the observable set of items.
0639      @param defaultValue the value to be returned if there is no value present.
0640      *
0641      @return a number binding
0642      */
0643     @Nonnull
0644     public static NumberBinding minInSet(@Nonnull final ObservableSet<? extends Number> items, @Nonnull final Number defaultValue) {
0645         requireNonNull(items, ERROR_ITEMS_NULL);
0646         requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
0647         return createDoubleBinding(() -> items.stream().mapToDouble(Number::doubleValue).min().orElse(defaultValue.doubleValue()), items);
0648     }
0649 
0650     /**
0651      * Creates a number binding that computes the minimum value amongst elements.
0652      *
0653      @param items    the observable set of items.
0654      @param supplier a {@code Supplier} whose result is returned if no value is present.
0655      *
0656      @return a number binding
0657      */
0658     @Nonnull
0659     public static NumberBinding minInSet(@Nonnull final ObservableSet<? extends Number> items, @Nonnull final Supplier<? extends Number> supplier) {
0660         requireNonNull(items, ERROR_ITEMS_NULL);
0661         requireNonNull(supplier, ERROR_SUPPLIER_NULL);
0662         return createDoubleBinding(() -> items.stream().mapToDouble(Number::doubleValue).min().orElseGet(resolveDoubleSupplier(supplier)), items);
0663     }
0664 
0665     /**
0666      * Creates a number binding that computes the maximum value amongst elements.
0667      *
0668      @param items        the observable set of items.
0669      @param defaultValue the value to be returned if there is no value present.
0670      *
0671      @return a number binding
0672      */
0673     @Nonnull
0674     public static NumberBinding maxInSet(@Nonnull final ObservableSet<? extends Number> items, @Nonnull final Number defaultValue) {
0675         requireNonNull(items, ERROR_ITEMS_NULL);
0676         requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
0677         return createDoubleBinding(() -> items.stream().mapToDouble(Number::doubleValue).max().orElse(defaultValue.doubleValue()), items);
0678     }
0679 
0680     /**
0681      * Creates a number binding that computes the maximum value amongst elements.
0682      *
0683      @param items    the observable set of items.
0684      @param supplier a {@code Supplier} whose result is returned if no value is present.
0685      *
0686      @return a number binding
0687      */
0688     @Nonnull
0689     public static NumberBinding maxInSet(@Nonnull final ObservableSet<? extends Number> items, @Nonnull final Supplier<? extends Number> supplier) {
0690         requireNonNull(items, ERROR_ITEMS_NULL);
0691         requireNonNull(supplier, ERROR_SUPPLIER_NULL);
0692         return createDoubleBinding(() -> items.stream().mapToDouble(Number::doubleValue).max().orElseGet(resolveDoubleSupplier(supplier)), items);
0693     }
0694 
0695     /**
0696      * Creates a number binding that computes the average value amongst elements.
0697      *
0698      @param items        the observable set of items.
0699      @param defaultValue the value to be returned if there is no value present.
0700      *
0701      @return a number binding
0702      */
0703     @Nonnull
0704     public static NumberBinding averageInSet(@Nonnull final ObservableSet<? extends Number> items, @Nonnull final Number defaultValue) {
0705         requireNonNull(items, ERROR_ITEMS_NULL);
0706         requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
0707         return createDoubleBinding(() -> items.stream().mapToDouble(Number::doubleValue).average().orElse(defaultValue.doubleValue()), items);
0708     }
0709 
0710     /**
0711      * Creates a number binding that computes the average value amongst elements.
0712      *
0713      @param items    the observable set of items.
0714      @param supplier a {@code Supplier} whose result is returned if no value is present.
0715      *
0716      @return a number binding
0717      */
0718     @Nonnull
0719     public static NumberBinding averageInSet(@Nonnull final ObservableSet<? extends Number> items, @Nonnull final Supplier<? extends Number> supplier) {
0720         requireNonNull(items, ERROR_ITEMS_NULL);
0721         requireNonNull(supplier, ERROR_SUPPLIER_NULL);
0722         return createDoubleBinding(() -> items.stream().mapToDouble(Number::doubleValue).average().orElseGet(resolveDoubleSupplier(supplier)), items);
0723     }
0724 
0725     /**
0726      * Creates a number binding that contains the sum of the items of the given observable set.
0727      *
0728      @param items the observable set of items.
0729      *
0730      @return a number binding.
0731      */
0732     @Nonnull
0733     public static NumberBinding sumOfSet(@Nonnull final ObservableSet<? extends Number> items) {
0734         requireNonNull(items, ERROR_ITEMS_NULL);
0735         return createDoubleBinding(() -> items.stream().mapToDouble(Number::doubleValue).sum(), items);
0736     }
0737 
0738     /**
0739      * Creates a number binding that computes the minimum value amongst elements.
0740      *
0741      @param items        the observable set of items.
0742      @param defaultValue the value to be returned if there is no value present.
0743      @param mapper       a non-interfering, stateless function to apply to the each element.
0744      *
0745      @return a number binding
0746      */
0747     @Nonnull
0748     public static <T> NumberBinding minInSet(@Nonnull final ObservableSet<T> items, @Nonnull final Number defaultValue, @Nonnull final ToDoubleFunction<? super T> mapper) {
0749         requireNonNull(items, ERROR_ITEMS_NULL);
0750         requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
0751         requireNonNull(mapper, ERROR_MAPPER_NULL);
0752         return createDoubleBinding(() -> items.stream().mapToDouble(mapper).min().orElse(defaultValue.doubleValue()), items);
0753     }
0754 
0755     /**
0756      * Creates a number binding that computes the minimum value amongst elements.
0757      *
0758      @param items    the observable set of items.
0759      @param supplier a {@code Supplier} whose result is returned if no value is present.
0760      @param mapper   a non-interfering, stateless function to apply to the each element.
0761      *
0762      @return a number binding
0763      */
0764     @Nonnull
0765     public static <T> NumberBinding minInSet(@Nonnull final ObservableSet<T> items, @Nonnull final Supplier<? extends Number> supplier, @Nonnull final ToDoubleFunction<? super T> mapper) {
0766         requireNonNull(items, ERROR_ITEMS_NULL);
0767         requireNonNull(supplier, ERROR_SUPPLIER_NULL);
0768         requireNonNull(mapper, ERROR_MAPPER_NULL);
0769         return createDoubleBinding(() -> items.stream().mapToDouble(mapper).min().orElseGet(resolveDoubleSupplier(supplier)), items);
0770     }
0771 
0772     /**
0773      * Creates a number binding that computes the maximum value amongst elements.
0774      *
0775      @param items        the observable set of items.
0776      @param defaultValue the value to be returned if there is no value present.
0777      @param mapper       a non-interfering, stateless function to apply to the each element.
0778      *
0779      @return a number binding
0780      */
0781     @Nonnull
0782     public static <T> NumberBinding maxInSet(@Nonnull final ObservableSet<T> items, @Nonnull final Number defaultValue, @Nonnull final ToDoubleFunction<? super T> mapper) {
0783         requireNonNull(items, ERROR_ITEMS_NULL);
0784         requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
0785         requireNonNull(mapper, ERROR_MAPPER_NULL);
0786         return createDoubleBinding(() -> items.stream().mapToDouble(mapper).max().orElse(defaultValue.doubleValue()), items);
0787     }
0788 
0789     /**
0790      * Creates a number binding that computes the maximum value amongst elements.
0791      *
0792      @param items    the observable set of items.
0793      @param supplier a {@code Supplier} whose result is returned if no value is present.
0794      @param mapper   a non-interfering, stateless function to apply to the each element.
0795      *
0796      @return a number binding
0797      */
0798     @Nonnull
0799     public static <T> NumberBinding maxInSet(@Nonnull final ObservableSet<T> items, @Nonnull final Supplier<? extends Number> supplier, @Nonnull final ToDoubleFunction<? super T> mapper) {
0800         requireNonNull(items, ERROR_ITEMS_NULL);
0801         requireNonNull(supplier, ERROR_SUPPLIER_NULL);
0802         requireNonNull(mapper, ERROR_MAPPER_NULL);
0803         return createDoubleBinding(() -> items.stream().mapToDouble(mapper).max().orElseGet(resolveDoubleSupplier(supplier)), items);
0804     }
0805 
0806     /**
0807      * Creates a number binding that computes the average value amongst elements.
0808      *
0809      @param items        the observable set of items.
0810      @param defaultValue the value to be returned if there is no value present.
0811      @param mapper       a non-interfering, stateless function to apply to the each element.
0812      *
0813      @return a number binding
0814      */
0815     @Nonnull
0816     public static <T> NumberBinding averageInSet(@Nonnull final ObservableSet<T> items, @Nonnull final Number defaultValue, @Nonnull final ToDoubleFunction<? super T> mapper) {
0817         requireNonNull(items, ERROR_ITEMS_NULL);
0818         requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
0819         requireNonNull(mapper, ERROR_MAPPER_NULL);
0820         return createDoubleBinding(() -> items.stream().mapToDouble(mapper).average().orElse(defaultValue.doubleValue()), items);
0821     }
0822 
0823     /**
0824      * Creates a number binding that computes the average value amongst elements.
0825      *
0826      @param items    the observable set of items.
0827      @param supplier a {@code Supplier} whose result is returned if no value is present.
0828      @param mapper   a non-interfering, stateless function to apply to the each element.
0829      *
0830      @return a number binding
0831      */
0832     @Nonnull
0833     public static <T> NumberBinding averageInSet(@Nonnull final ObservableSet<T> items, @Nonnull final Supplier<? extends Number> supplier, @Nonnull final ToDoubleFunction<? super T> mapper) {
0834         requireNonNull(items, ERROR_ITEMS_NULL);
0835         requireNonNull(supplier, ERROR_SUPPLIER_NULL);
0836         requireNonNull(mapper, ERROR_MAPPER_NULL);
0837         return createDoubleBinding(() -> items.stream().mapToDouble(mapper).average().orElseGet(resolveDoubleSupplier(supplier)), items);
0838     }
0839 
0840     /**
0841      * Creates a number binding that contains the sum of the items of the given observable set.
0842      *
0843      @param items  the observable set of items.
0844      @param mapper a non-interfering, stateless function to apply to the each element.
0845      *
0846      @return a number binding.
0847      */
0848     @Nonnull
0849     public static <T> NumberBinding sumOfSet(@Nonnull final ObservableSet<T> items, @Nonnull final ToDoubleFunction<? super T> mapper) {
0850         requireNonNull(items, ERROR_ITEMS_NULL);
0851         requireNonNull(mapper, ERROR_MAPPER_NULL);
0852         return createDoubleBinding(() -> items.stream().mapToDouble(mapper).sum(), items);
0853     }
0854 
0855     /**
0856      * Creates a number binding that computes the minimum value amongst elements.
0857      *
0858      @param items        the observable set of items.
0859      @param defaultValue the value to be returned if there is no value present.
0860      @param mapper       a non-interfering, stateless function to apply to the each element.
0861      *
0862      @return a number binding
0863      */
0864     @Nonnull
0865     public static <T> NumberBinding minInSet(@Nonnull final ObservableSet<T> items, @Nonnull final Number defaultValue, @Nonnull final ObservableValue<ToDoubleFunction<? super T>> mapper) {
0866         requireNonNull(items, ERROR_ITEMS_NULL);
0867         requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
0868         requireNonNull(mapper, ERROR_MAPPER_NULL);
0869         return createDoubleBinding(() -> {
0870             ToDoubleFunction<? super T> mapperValue = mapper.getValue();
0871             requireNonNull(mapperValue, ERROR_MAPPER_NULL);
0872             return items.stream().mapToDouble(mapperValue).min().orElse(defaultValue.doubleValue());
0873         }, items, mapper);
0874     }
0875 
0876     /**
0877      * Creates a number binding that computes the minimum value amongst elements.
0878      *
0879      @param items    the observable set of items.
0880      @param supplier a {@code Supplier} whose result is returned if no value is present.
0881      @param mapper   a non-interfering, stateless function to apply to the each element.
0882      *
0883      @return a number binding
0884      */
0885     @Nonnull
0886     public static <T> NumberBinding minInSet(@Nonnull final ObservableSet<T> items, @Nonnull final Supplier<? extends Number> supplier, @Nonnull final ObservableValue<ToDoubleFunction<? super T>> mapper) {
0887         requireNonNull(items, ERROR_ITEMS_NULL);
0888         requireNonNull(supplier, ERROR_SUPPLIER_NULL);
0889         requireNonNull(mapper, ERROR_MAPPER_NULL);
0890         return createDoubleBinding(() -> {
0891             ToDoubleFunction<? super T> mapperValue = mapper.getValue();
0892             requireNonNull(mapperValue, ERROR_MAPPER_NULL);
0893             return items.stream().mapToDouble(mapperValue).min().orElseGet(resolveDoubleSupplier(supplier));
0894         }, items, mapper);
0895     }
0896 
0897     /**
0898      * Creates a number binding that computes the maximum value amongst elements.
0899      *
0900      @param items        the observable set of items.
0901      @param defaultValue the value to be returned if there is no value present.
0902      @param mapper       a non-interfering, stateless function to apply to the each element.
0903      *
0904      @return a number binding
0905      */
0906     @Nonnull
0907     public static <T> NumberBinding maxInSet(@Nonnull final ObservableSet<T> items, @Nonnull final Number defaultValue, @Nonnull final ObservableValue<ToDoubleFunction<? super T>> mapper) {
0908         requireNonNull(items, ERROR_ITEMS_NULL);
0909         requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
0910         requireNonNull(mapper, ERROR_MAPPER_NULL);
0911         return createDoubleBinding(() -> {
0912             ToDoubleFunction<? super T> mapperValue = mapper.getValue();
0913             requireNonNull(mapperValue, ERROR_MAPPER_NULL);
0914             return items.stream().mapToDouble(mapperValue).max().orElse(defaultValue.doubleValue());
0915         }, items, mapper);
0916     }
0917 
0918     /**
0919      * Creates a number binding that computes the maximum value amongst elements.
0920      *
0921      @param items    the observable set of items.
0922      @param supplier a {@code Supplier} whose result is returned if no value is present.
0923      @param mapper   a non-interfering, stateless function to apply to the each element.
0924      *
0925      @return a number binding
0926      */
0927     @Nonnull
0928     public static <T> NumberBinding maxInSet(@Nonnull final ObservableSet<T> items, @Nonnull final Supplier<? extends Number> supplier, @Nonnull final ObservableValue<ToDoubleFunction<? super T>> mapper) {
0929         requireNonNull(items, ERROR_ITEMS_NULL);
0930         requireNonNull(supplier, ERROR_SUPPLIER_NULL);
0931         requireNonNull(mapper, ERROR_MAPPER_NULL);
0932         return createDoubleBinding(() -> {
0933             ToDoubleFunction<? super T> mapperValue = mapper.getValue();
0934             requireNonNull(mapperValue, ERROR_MAPPER_NULL);
0935             return items.stream().mapToDouble(mapperValue).max().orElseGet(resolveDoubleSupplier(supplier));
0936         }, items, mapper);
0937     }
0938 
0939     /**
0940      * Creates a number binding that computes the average value amongst elements.
0941      *
0942      @param items        the observable set of items.
0943      @param defaultValue the value to be returned if there is no value present.
0944      @param mapper       a non-interfering, stateless function to apply to the each element.
0945      *
0946      @return a number binding
0947      */
0948     @Nonnull
0949     public static <T> NumberBinding averageInSet(@Nonnull final ObservableSet<T> items, @Nonnull final Number defaultValue, @Nonnull final ObservableValue<ToDoubleFunction<? super T>> mapper) {
0950         requireNonNull(items, ERROR_ITEMS_NULL);
0951         requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
0952         requireNonNull(mapper, ERROR_MAPPER_NULL);
0953         return createDoubleBinding(() -> {
0954             ToDoubleFunction<? super T> mapperValue = mapper.getValue();
0955             requireNonNull(mapperValue, ERROR_MAPPER_NULL);
0956             return items.stream().mapToDouble(mapperValue).average().orElse(defaultValue.doubleValue());
0957         }, items, mapper);
0958     }
0959 
0960     /**
0961      * Creates a number binding that computes the average value amongst elements.
0962      *
0963      @param items    the observable set of items.
0964      @param supplier a {@code Supplier} whose result is returned if no value is present.
0965      @param mapper   a non-interfering, stateless function to apply to the each element.
0966      *
0967      @return a number binding
0968      */
0969     @Nonnull
0970     public static <T> NumberBinding averageInSet(@Nonnull final ObservableSet<T> items, @Nonnull final Supplier<? extends Number> supplier, @Nonnull final ObservableValue<ToDoubleFunction<? super T>> mapper) {
0971         requireNonNull(items, ERROR_ITEMS_NULL);
0972         requireNonNull(supplier, ERROR_SUPPLIER_NULL);
0973         requireNonNull(mapper, ERROR_MAPPER_NULL);
0974         return createDoubleBinding(() -> {
0975             ToDoubleFunction<? super T> mapperValue = mapper.getValue();
0976             requireNonNull(mapperValue, ERROR_MAPPER_NULL);
0977             return items.stream().mapToDouble(mapperValue).average().orElseGet(resolveDoubleSupplier(supplier));
0978         }, items, mapper);
0979     }
0980 
0981     /**
0982      * Creates a number binding that contains the sum of the items of the given observable set.
0983      *
0984      @param items  the observable set of items.
0985      @param mapper a non-interfering, stateless function to apply to the each element.
0986      *
0987      @return a number binding.
0988      */
0989     @Nonnull
0990     public static <T> NumberBinding sumOfSet(@Nonnull final ObservableSet<T> items, @Nonnull final ObservableValue<ToDoubleFunction<? super T>> mapper) {
0991         requireNonNull(items, ERROR_ITEMS_NULL);
0992         requireNonNull(mapper, ERROR_MAPPER_NULL);
0993         return createDoubleBinding(() -> {
0994             ToDoubleFunction<? super T> mapperValue = mapper.getValue();
0995             requireNonNull(mapperValue, ERROR_MAPPER_NULL);
0996             return items.stream().mapToDouble(mapperValue).sum();
0997         }, items, mapper);
0998     }
0999 
1000     /**
1001      * Creates a number binding that computes the minimum value amongst values.
1002      *
1003      @param items        the observable map of items.
1004      @param defaultValue the value to be returned if there is no value present.
1005      *
1006      @return a number binding
1007      */
1008     @Nonnull
1009     public static <K> NumberBinding minInMap(@Nonnull final ObservableMap<K, ? extends Number> items, @Nonnull final Number defaultValue) {
1010         requireNonNull(items, ERROR_ITEMS_NULL);
1011         requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
1012         return createDoubleBinding(() -> items.values().stream().mapToDouble(Number::doubleValue).min().orElse(defaultValue.doubleValue()), items);
1013     }
1014 
1015     /**
1016      * Creates a number binding that computes the minimum value amongst values.
1017      *
1018      @param items    the observable map of items.
1019      @param supplier a {@code Supplier} whose result is returned if no value is present.
1020      *
1021      @return a number binding
1022      */
1023     @Nonnull
1024     public static <K> NumberBinding minInMap(@Nonnull final ObservableMap<K, ? extends Number> items, @Nonnull final Supplier<? extends Number> supplier) {
1025         requireNonNull(items, ERROR_ITEMS_NULL);
1026         requireNonNull(supplier, ERROR_SUPPLIER_NULL);
1027         return createDoubleBinding(() -> items.values().stream().mapToDouble(Number::doubleValue).min().orElseGet(resolveDoubleSupplier(supplier)), items);
1028     }
1029 
1030     /**
1031      * Creates a number binding that computes the maximum value amongst values.
1032      *
1033      @param items        the observable map of items.
1034      @param defaultValue the value to be returned if there is no value present.
1035      *
1036      @return a number binding
1037      */
1038     @Nonnull
1039     public static <K> NumberBinding maxInMap(@Nonnull final ObservableMap<K, ? extends Number> items, @Nonnull final Number defaultValue) {
1040         requireNonNull(items, ERROR_ITEMS_NULL);
1041         requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
1042         return createDoubleBinding(() -> items.values().stream().mapToDouble(Number::doubleValue).max().orElse(defaultValue.doubleValue()), items);
1043     }
1044 
1045     /**
1046      * Creates a number binding that computes the maximum value amongst values.
1047      *
1048      @param items    the observable map of items.
1049      @param supplier a {@code Supplier} whose result is returned if no value is present.
1050      *
1051      @return a number binding
1052      */
1053     @Nonnull
1054     public static <K> NumberBinding maxInMap(@Nonnull final ObservableMap<K, ? extends Number> items, @Nonnull final Supplier<? extends Number> supplier) {
1055         requireNonNull(items, ERROR_ITEMS_NULL);
1056         requireNonNull(supplier, ERROR_SUPPLIER_NULL);
1057         return createDoubleBinding(() -> items.values().stream().mapToDouble(Number::doubleValue).max().orElseGet(resolveDoubleSupplier(supplier)), items);
1058     }
1059 
1060     /**
1061      * Creates a number binding that computes the average value amongst values.
1062      *
1063      @param items        the observable map of items.
1064      @param defaultValue the value to be returned if there is no value present.
1065      *
1066      @return a number binding
1067      */
1068     @Nonnull
1069     public static <K> NumberBinding averageInMap(@Nonnull final ObservableMap<K, ? extends Number> items, @Nonnull final Number defaultValue) {
1070         requireNonNull(items, ERROR_ITEMS_NULL);
1071         requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
1072         return createDoubleBinding(() -> items.values().stream().mapToDouble(Number::doubleValue).average().orElse(defaultValue.doubleValue()), items);
1073     }
1074 
1075     /**
1076      * Creates a number binding that computes the average value amongst values.
1077      *
1078      @param items    the observable map of items.
1079      @param supplier a {@code Supplier} whose result is returned if no value is present.
1080      *
1081      @return a number binding
1082      */
1083     @Nonnull
1084     public static <K> NumberBinding averageInMap(@Nonnull final ObservableMap<K, ? extends Number> items, @Nonnull final Supplier<? extends Number> supplier) {
1085         requireNonNull(items, ERROR_ITEMS_NULL);
1086         requireNonNull(supplier, ERROR_SUPPLIER_NULL);
1087         return createDoubleBinding(() -> items.values().stream().mapToDouble(Number::doubleValue).average().orElseGet(resolveDoubleSupplier(supplier)), items);
1088     }
1089 
1090     /**
1091      * Creates a number binding that contains the sum of the values of the given observable map.
1092      *
1093      @param items the observable map of items.
1094      *
1095      @return a number binding.
1096      */
1097     @Nonnull
1098     public static <K> NumberBinding sumOfMap(@Nonnull final ObservableMap<K, ? extends Number> items) {
1099         requireNonNull(items, ERROR_ITEMS_NULL);
1100         return createDoubleBinding(() -> items.values().stream().mapToDouble(Number::doubleValue).sum(), items);
1101     }
1102 
1103     /**
1104      * Creates a number binding that computes the minimum value amongst values.
1105      *
1106      @param items        the observable map of items.
1107      @param defaultValue the value to be returned if there is no value present.
1108      @param mapper       a non-interfering, stateless function to apply to the each value.
1109      *
1110      @return a number binding
1111      */
1112     @Nonnull
1113     public static <K, V> NumberBinding minInMap(@Nonnull final ObservableMap<K, V> items, @Nonnull final Number defaultValue, @Nonnull final ToDoubleFunction<? super V> mapper) {
1114         requireNonNull(items, ERROR_ITEMS_NULL);
1115         requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
1116         requireNonNull(mapper, ERROR_MAPPER_NULL);
1117         return createDoubleBinding(() -> items.values().stream().mapToDouble(mapper).min().orElse(defaultValue.doubleValue()), items);
1118     }
1119 
1120     /**
1121      * Creates a number binding that computes the minimum value amongst values.
1122      *
1123      @param items    the observable map of items.
1124      @param supplier a {@code Supplier} whose result is returned if no value is present.
1125      @param mapper   a non-interfering, stateless function to apply to the each value.
1126      *
1127      @return a number binding
1128      */
1129     @Nonnull
1130     public static <K, V> NumberBinding minInMap(@Nonnull final ObservableMap<K, V> items, @Nonnull final Supplier<? extends Number> supplier, @Nonnull final ToDoubleFunction<? super V> mapper) {
1131         requireNonNull(items, ERROR_ITEMS_NULL);
1132         requireNonNull(supplier, ERROR_SUPPLIER_NULL);
1133         requireNonNull(mapper, ERROR_MAPPER_NULL);
1134         return createDoubleBinding(() -> items.values().stream().mapToDouble(mapper).min().orElseGet(resolveDoubleSupplier(supplier)), items);
1135     }
1136 
1137     /**
1138      * Creates a number binding that computes the maximum value amongst values.
1139      *
1140      @param items        the observable map of items.
1141      @param defaultValue the value to be returned if there is no value present.
1142      @param mapper       a non-interfering, stateless function to apply to the each value.
1143      *
1144      @return a number binding
1145      */
1146     @Nonnull
1147     public static <K, V> NumberBinding maxInMap(@Nonnull final ObservableMap<K, V> items, @Nonnull final Number defaultValue, @Nonnull final ToDoubleFunction<? super V> mapper) {
1148         requireNonNull(items, ERROR_ITEMS_NULL);
1149         requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
1150         requireNonNull(mapper, ERROR_MAPPER_NULL);
1151         return createDoubleBinding(() -> items.values().stream().mapToDouble(mapper).max().orElse(defaultValue.doubleValue()), items);
1152     }
1153 
1154     /**
1155      * Creates a number binding that computes the maximum value amongst values.
1156      *
1157      @param items    the observable map of items.
1158      @param supplier a {@code Supplier} whose result is returned if no value is present.
1159      @param mapper   a non-interfering, stateless function to apply to the each value.
1160      *
1161      @return a number binding
1162      */
1163     @Nonnull
1164     public static <K, V> NumberBinding maxInMap(@Nonnull final ObservableMap<K, V> items, @Nonnull final Supplier<? extends Number> supplier, @Nonnull final ToDoubleFunction<? super V> mapper) {
1165         requireNonNull(items, ERROR_ITEMS_NULL);
1166         requireNonNull(supplier, ERROR_SUPPLIER_NULL);
1167         requireNonNull(mapper, ERROR_MAPPER_NULL);
1168         return createDoubleBinding(() -> items.values().stream().mapToDouble(mapper).max().orElseGet(resolveDoubleSupplier(supplier)), items);
1169     }
1170 
1171     /**
1172      * Creates a number binding that computes the average value amongst values.
1173      *
1174      @param items        the observable map of items.
1175      @param defaultValue the value to be returned if there is no value present.
1176      @param mapper       a non-interfering, stateless function to apply to the each value.
1177      *
1178      @return a number binding
1179      */
1180     @Nonnull
1181     public static <K, V> NumberBinding averageInMap(@Nonnull final ObservableMap<K, V> items, @Nonnull final Number defaultValue, @Nonnull final ToDoubleFunction<? super V> mapper) {
1182         requireNonNull(items, ERROR_ITEMS_NULL);
1183         requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
1184         requireNonNull(mapper, ERROR_MAPPER_NULL);
1185         return createDoubleBinding(() -> items.values().stream().mapToDouble(mapper).average().orElse(defaultValue.doubleValue()), items);
1186     }
1187 
1188     /**
1189      * Creates a number binding that computes the average value amongst values.
1190      *
1191      @param items    the observable map of items.
1192      @param supplier a {@code Supplier} whose result is returned if no value is present.
1193      @param mapper   a non-interfering, stateless function to apply to the each value.
1194      *
1195      @return a number binding
1196      */
1197     @Nonnull
1198     public static <K, V> NumberBinding averageInMap(@Nonnull final ObservableMap<K, V> items, @Nonnull final Supplier<? extends Number> supplier, @Nonnull final ToDoubleFunction<? super V> mapper) {
1199         requireNonNull(items, ERROR_ITEMS_NULL);
1200         requireNonNull(supplier, ERROR_SUPPLIER_NULL);
1201         requireNonNull(mapper, ERROR_MAPPER_NULL);
1202         return createDoubleBinding(() -> items.values().stream().mapToDouble(mapper).average().orElseGet(resolveDoubleSupplier(supplier)), items);
1203     }
1204 
1205     /**
1206      * Creates a number binding that contains the sum of the values of the given observable map.
1207      *
1208      @param items  the observable map of items.
1209      @param mapper a non-interfering, stateless function to apply to the each value.
1210      *
1211      @return a number binding.
1212      */
1213     @Nonnull
1214     public static <K, V> NumberBinding sumOfMap(@Nonnull final ObservableMap<K, V> items, @Nonnull final ToDoubleFunction<? super V> mapper) {
1215         requireNonNull(items, ERROR_ITEMS_NULL);
1216         requireNonNull(mapper, ERROR_MAPPER_NULL);
1217         return createDoubleBinding(() -> items.values().stream().mapToDouble(mapper).sum(), items);
1218     }
1219 
1220     /**
1221      * Creates a number binding that computes the minimum value amongst values.
1222      *
1223      @param items        the observable map of items.
1224      @param defaultValue the value to be returned if there is no value present.
1225      @param mapper       a non-interfering, stateless function to apply to the each value.
1226      *
1227      @return a number binding
1228      */
1229     @Nonnull
1230     public static <K, V> NumberBinding minInMap(@Nonnull final ObservableMap<K, V> items, @Nonnull final Number defaultValue, @Nonnull final ObservableValue<ToDoubleFunction<? super V>> mapper) {
1231         requireNonNull(items, ERROR_ITEMS_NULL);
1232         requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
1233         requireNonNull(mapper, ERROR_MAPPER_NULL);
1234         return createDoubleBinding(() -> {
1235             ToDoubleFunction<? super V> mapperValue = mapper.getValue();
1236             requireNonNull(mapperValue, ERROR_MAPPER_NULL);
1237             return items.values().stream().mapToDouble(mapperValue).min().orElse(defaultValue.doubleValue());
1238         }, items, mapper);
1239     }
1240 
1241     /**
1242      * Creates a number binding that computes the minimum value amongst values.
1243      *
1244      @param items    the observable map of items.
1245      @param supplier a {@code Supplier} whose result is returned if no value is present.
1246      @param mapper   a non-interfering, stateless function to apply to the each value.
1247      *
1248      @return a number binding
1249      */
1250     @Nonnull
1251     public static <K, V> NumberBinding minInMap(@Nonnull final ObservableMap<K, V> items, @Nonnull final Supplier<? extends Number> supplier, @Nonnull final ObservableValue<ToDoubleFunction<? super V>> mapper) {
1252         requireNonNull(items, ERROR_ITEMS_NULL);
1253         requireNonNull(supplier, ERROR_SUPPLIER_NULL);
1254         requireNonNull(mapper, ERROR_MAPPER_NULL);
1255         return createDoubleBinding(() -> {
1256             ToDoubleFunction<? super V> mapperValue = mapper.getValue();
1257             requireNonNull(mapperValue, ERROR_MAPPER_NULL);
1258             return items.values().stream().mapToDouble(mapperValue).min().orElseGet(resolveDoubleSupplier(supplier));
1259         }, items, mapper);
1260     }
1261 
1262     /**
1263      * Creates a number binding that computes the maximum value amongst values.
1264      *
1265      @param items        the observable map of items.
1266      @param defaultValue the value to be returned if there is no value present.
1267      @param mapper       a non-interfering, stateless function to apply to the each value.
1268      *
1269      @return a number binding
1270      */
1271     @Nonnull
1272     public static <K, V> NumberBinding maxInMap(@Nonnull final ObservableMap<K, V> items, @Nonnull final Number defaultValue, @Nonnull final ObservableValue<ToDoubleFunction<? super V>> mapper) {
1273         requireNonNull(items, ERROR_ITEMS_NULL);
1274         requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
1275         requireNonNull(mapper, ERROR_MAPPER_NULL);
1276         return createDoubleBinding(() -> {
1277             ToDoubleFunction<? super V> mapperValue = mapper.getValue();
1278             requireNonNull(mapperValue, ERROR_MAPPER_NULL);
1279             return items.values().stream().mapToDouble(mapperValue).max().orElse(defaultValue.doubleValue());
1280         }, items, mapper);
1281     }
1282 
1283     /**
1284      * Creates a number binding that computes the maximum value amongst values.
1285      *
1286      @param items    the observable map of items.
1287      @param supplier a {@code Supplier} whose result is returned if no value is present.
1288      @param mapper   a non-interfering, stateless function to apply to the each value.
1289      *
1290      @return a number binding
1291      */
1292     @Nonnull
1293     public static <K, V> NumberBinding maxInMap(@Nonnull final ObservableMap<K, V> items, @Nonnull final Supplier<? extends Number> supplier, @Nonnull final ObservableValue<ToDoubleFunction<? super V>> mapper) {
1294         requireNonNull(items, ERROR_ITEMS_NULL);
1295         requireNonNull(supplier, ERROR_SUPPLIER_NULL);
1296         requireNonNull(mapper, ERROR_MAPPER_NULL);
1297         return createDoubleBinding(() -> {
1298             ToDoubleFunction<? super V> mapperValue = mapper.getValue();
1299             requireNonNull(mapperValue, ERROR_MAPPER_NULL);
1300             return items.values().stream().mapToDouble(mapperValue).max().orElseGet(resolveDoubleSupplier(supplier));
1301         }, items, mapper);
1302     }
1303 
1304     /**
1305      * Creates a number binding that computes the average value amongst values.
1306      *
1307      @param items        the observable map of items.
1308      @param defaultValue the value to be returned if there is no value present.
1309      @param mapper       a non-interfering, stateless function to apply to the each value.
1310      *
1311      @return a number binding
1312      */
1313     @Nonnull
1314     public static <K, V> NumberBinding averageInMap(@Nonnull final ObservableMap<K, V> items, @Nonnull final Number defaultValue, @Nonnull final ObservableValue<ToDoubleFunction<? super V>> mapper) {
1315         requireNonNull(items, ERROR_ITEMS_NULL);
1316         requireNonNull(defaultValue, ERROR_DEFAULT_VALUE_NULL);
1317         requireNonNull(mapper, ERROR_MAPPER_NULL);
1318         return createDoubleBinding(() -> {
1319             ToDoubleFunction<? super V> mapperValue = mapper.getValue();
1320             requireNonNull(mapperValue, ERROR_MAPPER_NULL);
1321             return items.values().stream().mapToDouble(mapperValue).average().orElse(defaultValue.doubleValue());
1322         }, items, mapper);
1323     }
1324 
1325     /**
1326      * Creates a number binding that computes the average value amongst values.
1327      *
1328      @param items    the observable map of items.
1329      @param supplier a {@code Supplier} whose result is returned if no value is present.
1330      @param mapper   a non-interfering, stateless function to apply to the each value.
1331      *
1332      @return a number binding
1333      */
1334     @Nonnull
1335     public static <K, V> NumberBinding averageInMap(@Nonnull final ObservableMap<K, V> items, @Nonnull final Supplier<? extends Number> supplier, @Nonnull final ObservableValue<ToDoubleFunction<? super V>> mapper) {
1336         requireNonNull(items, ERROR_ITEMS_NULL);
1337         requireNonNull(supplier, ERROR_SUPPLIER_NULL);
1338         requireNonNull(mapper, ERROR_MAPPER_NULL);
1339         return createDoubleBinding(() -> {
1340             ToDoubleFunction<? super V> mapperValue = mapper.getValue();
1341             requireNonNull(mapperValue, ERROR_MAPPER_NULL);
1342             return items.values().stream().mapToDouble(mapperValue).average().orElseGet(resolveDoubleSupplier(supplier));
1343         }, items, mapper);
1344     }
1345 
1346     /**
1347      * Creates a number binding that contains the sum of the values of the given observable map.
1348      *
1349      @param items  the observable map of items.
1350      @param mapper a non-interfering, stateless function to apply to the each value.
1351      *
1352      @return a number binding.
1353      */
1354     @Nonnull
1355     public static <K, V> NumberBinding sumOfMap(@Nonnull final ObservableMap<K, V> items, @Nonnull final ObservableValue<ToDoubleFunction<? super V>> mapper) {
1356         requireNonNull(items, ERROR_ITEMS_NULL);
1357         requireNonNull(mapper, ERROR_MAPPER_NULL);
1358         return createDoubleBinding(() -> {
1359             ToDoubleFunction<? super V> mapperValue = mapper.getValue();
1360             requireNonNull(mapperValue, ERROR_MAPPER_NULL);
1361             return items.values().stream().mapToDouble(mapperValue).sum();
1362         }, items, mapper);
1363     }
1364 
1365     @Nonnull
1366     private static DoubleSupplier resolveDoubleSupplier(@Nonnull final Supplier<? extends Number> supplier) {
1367         requireNonNull(supplier, ERROR_SUPPLIER_NULL);
1368         return () -> supplier.get().doubleValue();
1369     }
1370 }