有什么方法可以在 Java 中自动生成动态代码?

Is there any way to automate dynamic code generation in Java?

我希望我的代码中有一些东西可以动态生成循环及其相应的主体。我的代码现在看起来像这样,我已经明确定义了每个循环和循环体,每个循环和循环体都基于变量 "len" 的值运行。我怎样才能改变它,以便动态生成我为每个条件编写的循环代码?

ArrayList<String> mapAll(String input){
        int len = input.length();
        ArrayList<String> outputs= new ArrayList<>();
        //String[] outputs = new String[len];
        ArrayList<String> outputStrings= new ArrayList<>();
        for (int i = 0; i <len ; i++)
            outputs.add(mapOne(Character.toString(input.charAt(i))));

        if (len == 1)
            for (int i = 0; i <outputs.get(len -1).length() ; i++)
                    outputStrings = outputs;

        else if (len == 2)
            for (int i = 0; i <outputs.get(len-2).length() ; i++)
                for (int j = 0; j < outputs.get(len - 1).length(); j++)
                    outputStrings.add(Character.toString(outputs.get(len - 2).charAt(i)) + outputs.get(len - 1).charAt(j));



        else if(len == 3)
            for (int i = 0; i <outputs.get(len-3).length(); i++)
                for (int j = 0; j <outputs.get(len-2).length(); j++)
                    for (int k = 0; k <outputs.get(len-1).length(); k++)
                        outputStrings.add(Character.toString(outputs.get(len-3).charAt(i)) + outputs.get(len - 2).charAt(j) + outputs.get(len - 1).charAt(k));


        else if(len==4)
            for (int i = 0; i < outputs.get(len-4).length(); i++)
                for(int j = 0; j < outputs.get(len-3).length(); j++)
                    for(int k = 0; k < outputs.get(len-2).length(); k++)
                        for(int l = 0; l < outputs.get(len-1).length(); l++)
                            outputStrings.add(Character.toString(outputs.get(len-4).charAt(i)) + outputs.get(len-3).charAt(j) + outputs.get(len-2).charAt(k)+ outputs.get(len-1).charAt(l));


        return outputStrings;
    }

mapOne方法的实现:

   private String mapOne(String in){
        String out;
        switch (in){
            case "a":
                out = "a"+"q"+"w"+"s"+"z";
                break;
            case "b":
                out = "b"+"g"+"h"+"v"+"n"+" ";
                break;
            case "c":
                out = "c"+"d"+"f"+"x"+"v"+" ";
                break;
            case "d":
                out = "d"+"e"+"r"+"s"+"f"+"x"+"c";
                break;
            case "e":
                out = "e"+"w"+"r"+"s"+"d";
                break;
            case "f":
                out = "f"+"r"+"t"+"d"+"g"+"c"+"v";
                break;
            case "g":
                out = "g"+"t"+"y"+"f"+"h"+"v"+"b";
                break;
            case "h":
                out = "h"+"y"+"u"+"g"+"j"+"b"+"n";
                break;
            case "i":
                out = "i"+"u"+"o"+"j"+"k";
                break;
            case "j":
                out = "j"+"u"+"i"+"h"+"k"+"n"+"m";
                break;
            case "k":
                out = "k"+"i"+"o"+"j"+"l"+"m";
                break;
            case "l":
                out = "l"+"o"+"p"+"k";
                break;
            case "m":
                out = "m"+"j"+"k"+"n"+" ";
                break;
            case "n":
                out = "n"+"h"+"j"+"b"+"m"+" ";
                break;
            case "o":
                out = "o"+"i"+"p"+"k"+"l";
                break;
            case "p":
                out = "p"+"o"+"l";
                break;
            case "q":
                out = "q"+"w"+"a";
                break;
            case "r":
                out = "r"+"e"+"t"+"d"+"f";
                break;
            case "s":
                out = "s"+"w"+"e"+"a"+"d"+"z"+"x";
                break;
            case "t":
                out = "t"+"r"+"y"+"f"+"g";
                break;
            case "u":
                out = "u"+"y"+"i"+"h"+"j";
                break;
            case "v":
                out = "v"+"f"+"g"+"c"+"b"+" ";
                break;
            case "w":
                out = "w"+"q"+"e"+"a"+"s";
                break;
            case "x":
                out = "x"+"s"+"d"+"z"+"c"+" ";
                break;
            case "y":
                out = "y"+"t"+"u"+"g"+"h";
                break;
            case "z":
                out = "z"+"a"+"s"+"x";
                break;
            case " ":
                out = " "+"x"+"c"+"v"+"b"+"n"+"m";
                break;
            default:
                out = "#";


        }
        return out;
    }

带有流的干净版本:

static ArrayList<String> mapAll1(String input) {
    int len = input.length();
    ArrayList<String> outputs = new ArrayList<>();
    //String[] outputs = new String[len];
    ArrayList<String> outputStrings = new ArrayList<>();
    for (int i = 0; i < len; i++)
        outputs.add(mapOne(Character.toString(input.charAt(i))));

    if (len == 1)
        for (int i = 0; i < outputs.get(len - 1).length(); i++)
            outputStrings = outputs;

    else {
        outputStrings = IntStream
                .range(0, len)
                // get last n strings from outputs, starts from last
                .mapToObj(i -> outputs.get(len - (i + 1)))
                // transform List<String> into List<List<String>>,
                .map(x -> new ArrayList<>(x.chars()
                        .mapToObj(Character::toString)
                        .collect(Collectors.toList()))
                )
                // reduce
                .reduce(new ArrayList<>(), (acc, list) -> new ArrayList<>(
                        acc.isEmpty() ? list : list.stream()
                                .flatMap(prefix -> acc.stream()
                                        .map(tail -> prefix + tail)
                                ).collect(Collectors.toList())));
    }

    return outputStrings;
}

主要部分以旧方式编写,并有进一步说明

if (len == 1)
    for (int i = 0; i < outputs.get(len - 1).length(); i++)
        outputStrings = outputs;

else {
    ArrayList<ArrayList<String>> tokenizeStrings = new ArrayList();
    // get last n strings from outputs, starts from last
    for (int i = 0; i < len; i++) {
        // transform List<String> into List<List<String>>,
        tokenizeStrings.add( new ArrayList<>(outputs.get(len - (i + 1)).chars()
                .mapToObj(Character::toString)
                .collect(Collectors.toList())));
    }

    outputStrings = new ArrayList<>();
    // reduce
    for (ArrayList<String> list: tokenizeStrings) {
        if (outputStrings.isEmpty()) {
            // first iteration just makes a copy
            outputStrings = list;
        } else {
            ArrayList<String> temp = new ArrayList<>();
            for (String prefix : list) {
                // for the rest iterations use string 'prefix' from current list
                // and add it in front of every string from main list 'outputStrings'
                for (String tail : outputStrings) {
                    temp.add(prefix + tail);
                }
            }
            // replace outputStrings with temp list
            outputStrings = temp;
        }
    }
}

return outputStrings;