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