本章概要
- Arrays的setAll方法
- 增量生成
Arrays的setAll方法
在Java 8中, 在RaggedArray.java 中引入并在 ArrayOfGenerics.java.Array.setAll() 中重用。它使用一个生成器并生成不同的值,可以选择基于数组的索引元素(通过访问当前索引,生成器可以读取数组值并对其进行修改)。 static Arrays.setAll() 的重载签名为:
- void setAll(int[] a, IntUnaryOperator gen)
- void setAll(long[] a, IntToLongFunction gen)
- void setAll(double[] a, IntToDoubleFunctiongen)
- void setAll(T[] a, IntFunction<? extendsT> gen)
除了 int , long , double 有特殊的版本,其他的一切都由泛型版本处理。生成器不是 Supplier 因为它们不带参数,并且必须将 int 数组索引作为参数。
SimpleSetAll.java
import java.util.*;
import static com.example.test.ArrayShow.show;
class Bob {
final int id;
Bob(int n) {
id = n;
}
@Override
public String toString() {
return "Bob" + id;
}
}
public class SimpleSetAll {
public static final int SZ = 8;
static int val = 1;
static char[] chars = "abcdefghijklmnopqrstuvwxyz"
.toCharArray();
static char getChar(int n) {
return chars[n];
}
public static void main(String[] args) {
int[] ia = new int[SZ];
long[] la = new long[SZ];
double[] da = new double[SZ];
Arrays.setAll(ia, n -> n); // [1]
Arrays.setAll(la, n -> n);
Arrays.setAll(da, n -> n);
show(ia);
show(la);
show(da);
Arrays.setAll(ia, n -> val++); // [2]
Arrays.setAll(la, n -> val++);
Arrays.setAll(da, n -> val++);
show(ia);
show(la);
show(da);
Bob[] ba = new Bob[SZ];
Arrays.setAll(ba, Bob::new); // [3]
show(ba);
Character[] ca = new Character[SZ];
Arrays.setAll(ca, SimpleSetAll::getChar); // [4]
show(ca);
}
}
- [1] 这里,我们只是将数组索引作为值插入数组。这将自动转化为 long 和 double 版本。
- [2] 这个函数只需要接受索引就能产生正确结果。这个,我们忽略索引值并且使用 val 生成结果。
- [3] 方法引用有效,因为 Bob 的构造器接收一个 int 参数。只要我们传递的函数接收一个 int 参数且能产生正确的结果,就认为它完成了工作。
- [4] 为了处理除了 int ,long ,double 之外的基元类型,请为基元创建包装类的数组。然后使用 setAll() 的泛型版本。请注意,getChar() 生成基元类型,因此这是自动装箱到 Character 。
ArrayShow.java
import java.util.*;
public interface ArrayShow {
static void show(Object[] a) {
System.out.println(Arrays.toString(a));
}
static void show(boolean[] a) {
System.out.println(Arrays.toString(a));
}
static void show(byte[] a) {
System.out.println(Arrays.toString(a));
}
static void show(char[] a) {
System.out.println(Arrays.toString(a));
}
static void show(short[] a) {
System.out.println(Arrays.toString(a));
}
static void show(int[] a) {
System.out.println(Arrays.toString(a));
}
static void show(long[] a) {
System.out.println(Arrays.toString(a));
}
static void show(float[] a) {
System.out.println(Arrays.toString(a));
}
static void show(double[] a) {
System.out.println(Arrays.toString(a));
}
// Start with a description:
static void show(String info, Object[] a) {
System.out.print(info + ": ");
show(a);
}
static void show(String info, boolean[] a) {
System.out.print(info + ": ");
show(a);
}
static void show(String info, byte[] a) {
System.out.print(info + ": ");
show(a);
}
static void show(String info, char[] a) {
System.out.print(info + ": ");
show(a);
}
static void show(String info, short[] a) {
System.out.print(info + ": ");
show(a);
}
static void show(String info, int[] a) {
System.out.print(info + ": ");
show(a);
}
static void show(String info, long[] a) {
System.out.print(info + ": ");
show(a);
}
static void show(String info, float[] a) {
System.out.print(info + ": ");
show(a);
}
static void show(String info, double[] a) {
System.out.print(info + ": ");
show(a);
}
}
增量生成
这是一个方法库,用于为不同类型生成增量值。
这些被作为内部类来生成容易记住的名字;比如,为了使用 Integer 工具你可以用 new Conut.Interger() , 如果你想要使用基本数据类型 int 工具,你可以用 new Count.Pint() (基本类型的名字不能被直接使用,所以它们都在前面添加一个 P 来表示基本数据类型’primitive’, 我们的第一选择是使用基本类型名字后面跟着下划线,比如 int_ 和 double_ ,但是这种方式违背Java的命名习惯)。每个包装类的生成器都使用 get() 方法实现了它的 Supplier 。要使用Array.setAll() ,一个重载的 get(int n) 方法要接受(并忽略)其参数,以便接受 setAll() 传递的索引值。
注意,通过使用包装类的名称作为内部类名,我们必须调用 java.lang 包来保证我们可以使用实际包装类的名字:
Count.java
import java.util.*;
import java.util.function.*;
import static com.example.test.ConvertTo.primitive;
public interface Count {
class Boolean
implements Supplier<java.lang.Boolean> {
private boolean b = true;
@Override
public java.lang.Boolean get() {
b = !b;
return java.lang.Boolean.valueOf(b);
}
public java.lang.Boolean get(int n) {
return get();
}
public java.lang.Boolean[] array(int sz) {
java.lang.Boolean[] result =
new java.lang.Boolean[sz];
Arrays.setAll(result, n -> get());
return result;
}
}
class Pboolean {
private boolean b = true;
public boolean get() {
b = !b;
return b;
}
public boolean get(int n) {
return get();
}
public boolean[] array(int sz) {
return primitive(new Boolean().array(sz));
}
}
class Byte
implements Supplier<java.lang.Byte> {
private byte b;
@Override
public java.lang.Byte get() {
return b++;
}
public java.lang.Byte get(int n) {
return get();
}
public java.lang.Byte[] array(int sz) {
java.lang.Byte[] result =
new java.lang.Byte[sz];
Arrays.setAll(result, n -> get());
return result;
}
}
class Pbyte {
private byte b;
public byte get() {
return b++;
}
public byte get(int n) {
return get();
}
public byte[] array(int sz) {
return primitive(new Byte().array(sz));
}
}
char[] CHARS =
"abcdefghijklmnopqrstuvwxyz".toCharArray();
class Character
implements Supplier<java.lang.Character> {
private int i;
@Override
public java.lang.Character get() {
i = (i + 1) % CHARS.length;
return CHARS[i];
}
public java.lang.Character get(int n) {
return get();
}
public java.lang.Character[] array(int sz) {
java.lang.Character[] result =
new java.lang.Character[sz];
Arrays.setAll(result, n -> get());
return result;
}
}
class Pchar {
private int i;
public char get() {
i = (i + 1) % CHARS.length;
return CHARS[i];
}
public char get(int n) {
return get();
}
public char[] array(int sz) {
return primitive(new Character().array(sz));
}
}
class Short
implements Supplier<java.lang.Short> {
short s;
@Override
public java.lang.Short get() {
return s++;
}
public java.lang.Short get(int n) {
return get();
}
public java.lang.Short[] array(int sz) {
java.lang.Short[] result =
new java.lang.Short[sz];
Arrays.setAll(result, n -> get());
return result;
}
}
class Pshort {
short s;
public short get() {
return s++;
}
public short get(int n) {
return get();
}
public short[] array(int sz) {
return primitive(new Short().array(sz));
}
}
class Integer
implements Supplier<java.lang.Integer> {
int i;
@Override
public java.lang.Integer get() {
return i++;
}
public java.lang.Integer get(int n) {
return get();
}
public java.lang.Integer[] array(int sz) {
java.lang.Integer[] result =
new java.lang.Integer[sz];
Arrays.setAll(result, n -> get());
return result;
}
}
class Pint implements IntSupplier {
int i;
public int get() {
return i++;
}
public int get(int n) {
return get();
}
@Override
public int getAsInt() {
return get();
}
public int[] array(int sz) {
return primitive(new Integer().array(sz));
}
}
class Long
implements Supplier<java.lang.Long> {
private long l;
@Override
public java.lang.Long get() {
return l++;
}
public java.lang.Long get(int n) {
return get();
}
public java.lang.Long[] array(int sz) {
java.lang.Long[] result =
new java.lang.Long[sz];
Arrays.setAll(result, n -> get());
return result;
}
}
class Plong implements LongSupplier {
private long l;
public long get() {
return l++;
}
public long get(int n) {
return get();
}
@Override
public long getAsLong() {
return get();
}
public long[] array(int sz) {
return primitive(new Long().array(sz));
}
}
class Float
implements Supplier<java.lang.Float> {
private int i;
@Override
public java.lang.Float get() {
return java.lang.Float.valueOf(i++);
}
public java.lang.Float get(int n) {
return get();
}
public java.lang.Float[] array(int sz) {
java.lang.Float[] result =
new java.lang.Float[sz];
Arrays.setAll(result, n -> get());
return result;
}
}
class Pfloat {
private int i;
public float get() {
return i++;
}
public float get(int n) {
return get();
}
public float[] array(int sz) {
return primitive(new Float().array(sz));
}
}
class Double
implements Supplier<java.lang.Double> {
private int i;
@Override
public java.lang.Double get() {
return java.lang.Double.valueOf(i++);
}
public java.lang.Double get(int n) {
return get();
}
public java.lang.Double[] array(int sz) {
java.lang.Double[] result =
new java.lang.Double[sz];
Arrays.setAll(result, n -> get());
return result;
}
}
class Pdouble implements DoubleSupplier {
private int i;
public double get() {
return i++;
}
public double get(int n) {
return get();
}
@Override
public double getAsDouble() {
return get(0);
}
public double[] array(int sz) {
return primitive(new Double().array(sz));
}
}
}
ConvertTo.java
public interface ConvertTo {
static boolean[] primitive(Boolean[] in) {
boolean[] result = new boolean[in.length];
for (int i = 0; i < in.length; i++) {
result[i] = in[i]; // Autounboxing
}
return result;
}
static char[] primitive(Character[] in) {
char[] result = new char[in.length];
for (int i = 0; i < in.length; i++) {
result[i] = in[i];
}
return result;
}
static byte[] primitive(Byte[] in) {
byte[] result = new byte[in.length];
for (int i = 0; i < in.length; i++) {
result[i] = in[i];
}
return result;
}
static short[] primitive(Short[] in) {
short[] result = new short[in.length];
for (int i = 0; i < in.length; i++) {
result[i] = in[i];
}
return result;
}
static int[] primitive(Integer[] in) {
int[] result = new int[in.length];
for (int i = 0; i < in.length; i++) {
result[i] = in[i];
}
return result;
}
static long[] primitive(Long[] in) {
long[] result = new long[in.length];
for (int i = 0; i < in.length; i++) {
result[i] = in[i];
}
return result;
}
static float[] primitive(Float[] in) {
float[] result = new float[in.length];
for (int i = 0; i < in.length; i++) {
result[i] = in[i];
}
return result;
}
static double[] primitive(Double[] in) {
double[] result = new double[in.length];
for (int i = 0; i < in.length; i++) {
result[i] = in[i];
}
return result;
}
// Convert from primitive array to wrapped array:
static Boolean[] boxed(boolean[] in) {
Boolean[] result = new Boolean[in.length];
for (int i = 0; i < in.length; i++) {
result[i] = in[i]; // Autoboxing
}
return result;
}
static Character[] boxed(char[] in) {
Character[] result = new Character[in.length];
for (int i = 0; i < in.length; i++) {
result[i] = in[i];
}
return result;
}
static Byte[] boxed(byte[] in) {
Byte[] result = new Byte[in.length];
for (int i = 0; i < in.length; i++) {
result[i] = in[i];
}
return result;
}
static Short[] boxed(short[] in) {
Short[] result = new Short[in.length];
for (int i = 0; i < in.length; i++) {
result[i] = in[i];
}
return result;
}
static Integer[] boxed(int[] in) {
Integer[] result = new Integer[in.length];
for (int i = 0; i < in.length; i++) {
result[i] = in[i];
}
return result;
}
static Long[] boxed(long[] in) {
Long[] result = new Long[in.length];
for (int i = 0; i < in.length; i++) {
result[i] = in[i];
}
return result;
}
static Float[] boxed(float[] in) {
Float[] result = new Float[in.length];
for (int i = 0; i < in.length; i++) {
result[i] = in[i];
}
return result;
}
static Double[] boxed(double[] in) {
Double[] result = new Double[in.length];
for (int i = 0; i < in.length; i++) {
result[i] = in[i];
}
return result;
}
}
对于 int ,long ,double 这三个有特殊 Supplier 接口的原始数据类型来说,Pint , Plong 和 Pdouble 实现了这些接口。
这里是对 Count 的测试,这同样给我们提供了如何使用它的例子:
import java.util.*;
import java.util.stream.*;
import static com.example.test.ArrayShow.show;
public class TestCount {
static final int SZ = 5;
public static void main(String[] args) {
System.out.println("Boolean");
Boolean[] a1 = new Boolean[SZ];
Arrays.setAll(a1, new Count.Boolean()::get);
show(a1);
a1 = Stream.generate(new Count.Boolean())
.limit(SZ + 1).toArray(Boolean[]::new);
show(a1);
a1 = new Count.Boolean().array(SZ + 2);
show(a1);
boolean[] a1b =
new Count.Pboolean().array(SZ + 3);
show(a1b);
System.out.println("Byte");
Byte[] a2 = new Byte[SZ];
Arrays.setAll(a2, new Count.Byte()::get);
show(a2);
a2 = Stream.generate(new Count.Byte())
.limit(SZ + 1).toArray(Byte[]::new);
show(a2);
a2 = new Count.Byte().array(SZ + 2);
show(a2);
byte[] a2b = new Count.Pbyte().array(SZ + 3);
show(a2b);
System.out.println("Character");
Character[] a3 = new Character[SZ];
Arrays.setAll(a3, new Count.Character()::get);
show(a3);
a3 = Stream.generate(new Count.Character())
.limit(SZ + 1).toArray(Character[]::new);
show(a3);
a3 = new Count.Character().array(SZ + 2);
show(a3);
char[] a3b = new Count.Pchar().array(SZ + 3);
show(a3b);
System.out.println("Short");
Short[] a4 = new Short[SZ];
Arrays.setAll(a4, new Count.Short()::get);
show(a4);
a4 = Stream.generate(new Count.Short())
.limit(SZ + 1).toArray(Short[]::new);
show(a4);
a4 = new Count.Short().array(SZ + 2);
show(a4);
short[] a4b = new Count.Pshort().array(SZ + 3);
show(a4b);
System.out.println("Integer");
int[] a5 = new int[SZ];
Arrays.setAll(a5, new Count.Integer()::get);
show(a5);
Integer[] a5b =
Stream.generate(new Count.Integer())
.limit(SZ + 1).toArray(Integer[]::new);
show(a5b);
a5b = new Count.Integer().array(SZ + 2);
show(a5b);
a5 = IntStream.generate(new Count.Pint())
.limit(SZ + 1).toArray();
show(a5);
a5 = new Count.Pint().array(SZ + 3);
show(a5);
System.out.println("Long");
long[] a6 = new long[SZ];
Arrays.setAll(a6, new Count.Long()::get);
show(a6);
Long[] a6b = Stream.generate(new Count.Long())
.limit(SZ + 1).toArray(Long[]::new);
show(a6b);
a6b = new Count.Long().array(SZ + 2);
show(a6b);
a6 = LongStream.generate(new Count.Plong())
.limit(SZ + 1).toArray();
show(a6);
a6 = new Count.Plong().array(SZ + 3);
show(a6);
System.out.println("Float");
Float[] a7 = new Float[SZ];
Arrays.setAll(a7, new Count.Float()::get);
show(a7);
a7 = Stream.generate(new Count.Float())
.limit(SZ + 1).toArray(Float[]::new);
show(a7);
a7 = new Count.Float().array(SZ + 2);
show(a7);
float[] a7b = new Count.Pfloat().array(SZ + 3);
show(a7b);
System.out.println("Double");
double[] a8 = new double[SZ];
Arrays.setAll(a8, new Count.Double()::get);
show(a8);
Double[] a8b =
Stream.generate(new Count.Double())
.limit(SZ + 1).toArray(Double[]::new);
show(a8b);
a8b = new Count.Double().array(SZ + 2);
show(a8b);
a8 = DoubleStream.generate(new Count.Pdouble())
.limit(SZ + 1).toArray();
show(a8);
a8 = new Count.Pdouble().array(SZ + 3);
show(a8);
}
}
注意到原始数组类型 int[] ,long[] ,double[] 可以直接被 Arrays.setAll() 填充,但是其他的原始类型都要求用包装器类型的数组。
通过 Stream.generate() 创建的包装数组显示了 toArray() 的重载用法,在这里你应该提供给它要创建的数组类型的构造器。