Coverage Summary for Class: MoreCollectors (com.google.common.collect)
| Class | Method, % | Line, % |
|---|---|---|
| MoreCollectors | 0% (0/6) | 0% (0/10) |
| MoreCollectors$ToOptionalState | 0% (0/6) | 0% (0/42) |
| Total | 0% (0/12) | 0% (0/52) |
1 /* 2 * Copyright (C) 2016 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.common.collect; 18 19 import static com.google.common.base.Preconditions.checkNotNull; 20 21 import com.google.common.annotations.GwtCompatible; 22 import java.util.ArrayList; 23 import java.util.List; 24 import java.util.NoSuchElementException; 25 import java.util.Optional; 26 import java.util.stream.Collector; 27 import org.checkerframework.checker.nullness.qual.Nullable; 28 29 /** 30 * Collectors not present in {@code java.util.stream.Collectors} that are not otherwise associated 31 * with a {@code com.google.common} type. 32 * 33 * @author Louis Wasserman 34 * @since 21.0 35 */ 36 @GwtCompatible 37 public final class MoreCollectors { 38 39 /* 40 * TODO(lowasser): figure out if we can convert this to a concurrent AtomicReference-based 41 * collector without breaking j2cl? 42 */ 43 private static final Collector<Object, ?, Optional<Object>> TO_OPTIONAL = 44 Collector.of( 45 ToOptionalState::new, 46 ToOptionalState::add, 47 ToOptionalState::combine, 48 ToOptionalState::getOptional, 49 Collector.Characteristics.UNORDERED); 50 51 /** 52 * A collector that converts a stream of zero or one elements to an {@code Optional}. The returned 53 * collector throws an {@code IllegalArgumentException} if the stream consists of two or more 54 * elements, and a {@code NullPointerException} if the stream consists of exactly one element, 55 * which is null. 56 */ 57 @SuppressWarnings("unchecked") 58 public static <T> Collector<T, ?, Optional<T>> toOptional() { 59 return (Collector) TO_OPTIONAL; 60 } 61 62 private static final Object NULL_PLACEHOLDER = new Object(); 63 64 private static final Collector<Object, ?, Object> ONLY_ELEMENT = 65 Collector.of( 66 ToOptionalState::new, 67 (state, o) -> state.add((o == null) ? NULL_PLACEHOLDER : o), 68 ToOptionalState::combine, 69 state -> { 70 Object result = state.getElement(); 71 return (result == NULL_PLACEHOLDER) ? null : result; 72 }, 73 Collector.Characteristics.UNORDERED); 74 75 /** 76 * A collector that takes a stream containing exactly one element and returns that element. The 77 * returned collector throws an {@code IllegalArgumentException} if the stream consists of two or 78 * more elements, and a {@code NoSuchElementException} if the stream is empty. 79 */ 80 @SuppressWarnings("unchecked") 81 public static <T> Collector<T, ?, T> onlyElement() { 82 return (Collector) ONLY_ELEMENT; 83 } 84 85 /** 86 * This atrocity is here to let us report several of the elements in the stream if there were more 87 * than one, not just two. 88 */ 89 private static final class ToOptionalState { 90 static final int MAX_EXTRAS = 4; 91 92 @Nullable Object element; 93 @Nullable List<Object> extras; 94 95 ToOptionalState() { 96 element = null; 97 extras = null; 98 } 99 100 IllegalArgumentException multiples(boolean overflow) { 101 StringBuilder sb = 102 new StringBuilder().append("expected one element but was: <").append(element); 103 for (Object o : extras) { 104 sb.append(", ").append(o); 105 } 106 if (overflow) { 107 sb.append(", ..."); 108 } 109 sb.append('>'); 110 throw new IllegalArgumentException(sb.toString()); 111 } 112 113 void add(Object o) { 114 checkNotNull(o); 115 if (element == null) { 116 this.element = o; 117 } else if (extras == null) { 118 extras = new ArrayList<>(MAX_EXTRAS); 119 extras.add(o); 120 } else if (extras.size() < MAX_EXTRAS) { 121 extras.add(o); 122 } else { 123 throw multiples(true); 124 } 125 } 126 127 ToOptionalState combine(ToOptionalState other) { 128 if (element == null) { 129 return other; 130 } else if (other.element == null) { 131 return this; 132 } else { 133 if (extras == null) { 134 extras = new ArrayList<>(); 135 } 136 extras.add(other.element); 137 if (other.extras != null) { 138 this.extras.addAll(other.extras); 139 } 140 if (extras.size() > MAX_EXTRAS) { 141 extras.subList(MAX_EXTRAS, extras.size()).clear(); 142 throw multiples(true); 143 } 144 return this; 145 } 146 } 147 148 Optional<Object> getOptional() { 149 if (extras == null) { 150 return Optional.ofNullable(element); 151 } else { 152 throw multiples(false); 153 } 154 } 155 156 Object getElement() { 157 if (element == null) { 158 throw new NoSuchElementException(); 159 } else if (extras == null) { 160 return element; 161 } else { 162 throw multiples(false); 163 } 164 } 165 } 166 167 private MoreCollectors() {} 168 }