Skip to content

Commit

Permalink
Merge pull request #26 from Archinamon/master
Browse files Browse the repository at this point in the history
Array constructor lambda reference support for Stream:collect method
  • Loading branch information
aNNiMON committed Feb 16, 2016
2 parents d2d2412 + b6db841 commit 726d913
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 1 deletion.
41 changes: 40 additions & 1 deletion src/main/java/com/annimon/stream/Stream.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.annimon.stream.function.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
Expand Down Expand Up @@ -311,12 +313,15 @@ private void nextIteration() {


//<editor-fold defaultstate="collapsed" desc="Implementation">
static final long MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
static final String BAD_SIZE = "Stream size exceeds max array size";

private final Iterator<? extends T> iterator;

private Stream(Iterator<? extends T> iterator) {
this.iterator = iterator;
}

private Stream(Iterable<? extends T> iterable) {
this(iterable.iterator());
}
Expand Down Expand Up @@ -718,6 +723,35 @@ public Optional<T> reduce(BiFunction<T, T, T> accumulator) {
}
return foundAny ? Optional.of(result) : (Optional<T>) Optional.empty();
}

/**
* Collects elements to an array, the {@code generator} constructor of provided.
*
* <p>This is a terminal operation.
*
* @param <R> the type of the result
* @param generator the array constructor reference that accommodates future array of assigned size
* @return the result of collect elements
* @see #collect(com.annimon.stream.Collector)
* @see #collect(com.annimon.stream.function.Supplier, com.annimon.stream.function.BiConsumer)
*/
public <R> R[] collect(IntFunction<R[]> generator) {
Collection<T> container = new ArrayList<T>();
while (iterator.hasNext()) {
container.add(iterator.next());
}
final int size = container.size();

if (size >= MAX_ARRAY_SIZE) throw new IllegalArgumentException(BAD_SIZE);

//noinspection unchecked
T[] source = container.toArray(Stream.<T>newArray(size));
R[] boxed = generator.apply(size);

//noinspection SuspiciousSystemArraycopy
System.arraycopy(source, 0, boxed, 0, size);
return boxed;
}

/**
* Collects elements to {@code supplier} provided container by applying the given accumulation function.
Expand Down Expand Up @@ -887,6 +921,11 @@ private boolean match(Predicate<? super T> predicate, int matchKind) {
// noneMatch -> true
return !kindAny;
}

@SafeVarargs
static <E> E[] newArray(int length, E... array) {
return Arrays.copyOf(array, length);
}

//</editor-fold>
}
25 changes: 25 additions & 0 deletions src/main/java/com/annimon/stream/function/IntFunction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.annimon.stream.function;

/**
* Represents a function that accepts an int-valued argument and produces a
* result. This is the {@code int}-consuming primitive specialization for
* {@link Function}.
*
* <p>This is a <a href="package-summary.html">functional interface</a>
* whose functional method is {@link #apply(int)}.
*
* @param <R> the type of the result of the function
*
* @see Function
*/
@FunctionalInterface
public interface IntFunction<R> {

/**
* Applies this function to the given argument.
*
* @param value the function argument
* @return the function result
*/
R apply(int value);
}
14 changes: 14 additions & 0 deletions src/test/java/com/annimon/stream/Functions.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
import com.annimon.stream.function.BiConsumer;
import com.annimon.stream.function.BiFunction;
import com.annimon.stream.function.Function;
import com.annimon.stream.function.IntFunction;
import com.annimon.stream.function.Predicate;
import com.annimon.stream.function.Supplier;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
Expand All @@ -13,6 +16,17 @@
* Functions that used in tests.
*/
public final class Functions {

public static <T> IntFunction<T[]> arrayGenerator(final Class<T[]> clazz) {
return new IntFunction<T[]>() {

@Override
@SuppressWarnings("unchecked")
public T[] apply(int value) {
return (T[]) Array.newInstance(clazz.getComponentType(), value);
}
};
}

public static <T> Function<T, String> convertToString() {
return new Function<T, String>() {
Expand Down
10 changes: 10 additions & 0 deletions src/test/java/com/annimon/stream/StreamTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -738,6 +738,16 @@ public void testFindFirstAfterFiltering() {
assertNotNull(result.get());
assertEquals(6, (int) result.get());
}

@Test
public void testCollectToArrayTerminationOperation() {
Integer[] numbers = Stream.ofRange(1, 1000)
.filter(Functions.remainder(2))
.collect(Functions.arrayGenerator(Integer[].class));

assertTrue(numbers.length > 0);
assertNotNull(numbers[100]);
}

@Test
public void testCustomIntermediateOperator_Reverse() {
Expand Down

0 comments on commit 726d913

Please sign in to comment.