二十一、数组(3)

本章概要

  • 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

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] 这里,我们只是将数组索引作为值插入数组。这将自动转化为 longdouble 版本。
  • [2] 这个函数只需要接受索引就能产生正确结果。这个,我们忽略索引值并且使用 val 生成结果。
  • [3] 方法引用有效,因为 Bob 的构造器接收一个 int 参数。只要我们传递的函数接收一个 int 参数且能产生正确的结果,就认为它完成了工作。
  • [4] 为了处理除了 intlongdouble 之外的基元类型,请为基元创建包装类的数组。然后使用 setAll() 的泛型版本。请注意,getChar() 生成基元类型,因此这是自动装箱到 Character

ArrayShow.java

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

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

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;
    }
}

对于 intlongdouble 这三个有特殊 Supplier 接口的原始数据类型来说,PintPlongPdouble 实现了这些接口。

这里是对 Count 的测试,这同样给我们提供了如何使用它的例子:

java 复制代码
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() 的重载用法,在这里你应该提供给它要创建的数组类型的构造器。