本章概要
- 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;}@Overridepublic 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 Booleanimplements Supplier<java.lang.Boolean> {private boolean b = true;@Overridepublic 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 Byteimplements Supplier<java.lang.Byte> {private byte b;@Overridepublic 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 Characterimplements Supplier<java.lang.Character> {private int i;@Overridepublic 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 Shortimplements Supplier<java.lang.Short> {short s;@Overridepublic 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 Integerimplements Supplier<java.lang.Integer> {int i;@Overridepublic 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();}@Overridepublic int getAsInt() {return get();}public int[] array(int sz) {return primitive(new Integer().array(sz));}}class Longimplements Supplier<java.lang.Long> {private long l;@Overridepublic 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();}@Overridepublic long getAsLong() {return get();}public long[] array(int sz) {return primitive(new Long().array(sz));}}class Floatimplements Supplier<java.lang.Float> {private int i;@Overridepublic 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 Doubleimplements Supplier<java.lang.Double> {private int i;@Overridepublic 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();}@Overridepublic 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() 的重载用法,在这里你应该提供给它要创建的数组类型的构造器。