求优化这个冗长且费资源的代码

面试让我口述生成一个8-20位随机密码,必须包含数字字母特殊字符

import java.util.Random;


public class test {
    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            StringBuilder password = getPassword();
            System.out.println(password);
        }

    }

    public static StringBuilder getPassword() {
        Random random = new Random();
        //xyz记录生成的字母,特殊字符和数字的个数
        int x = 0;
        int y = 0;
        int z = 0;
        //随机获取一个8-20的数,作为密码的长度
        int num = random.nextInt(13) + 8;
        StringBuilder sb = new StringBuilder();
        //定义密码中会出现的字母和特殊字符
        String a = "qwertyuiopasdfghjklzxcvbnmQWEUOPASDFGHJKLZXCVBNM";
        String b = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";
        //密码多长就循环多少次
        for (int i = 1; i <= num; i++) {
            //随机获取一个1-3的数
            int n = random.nextInt(3) + 1;
            //等于1,获取一个0-9的数,合并字符串
            if (n == 1) {
                sb = sb.append(random.nextInt(10));
                x++;
                //等于2,获取一个随机字符,合并字符串
            }
            if (n == 2) {
                sb.append(find(b));
                y++;
                //等于3,随机获取一个字母,合并字符串
            }
            if (n == 3) {
                sb.append(find(a));
                z++;
            }
        }
        //如果密码不包含其中一种,重新获取
        if (x == 0 || y == 0 || z == 0) {
            sb = getPassword();
        }
        return sb;
    }

    public static String find(String arr) {
        //将字符串变成数组
        String[] split = arr.split("");
        //随机获取一个数组长度的数
        int random = new Random().nextInt(split.length);
        //根据随机获取的数返回对应下标的元素
        return split[random];
    }
}

问到我的时候直接蒙了,一点想法也没(应届,实习过),后来回家根据需求写出了上面的代码
代码写了两个静态方法,方法1是生成一个符合要求的密码,方法2是获取字符拆中的随机一个单位
方法一思路:
1.定义三个变量,分别去记录数字,字母,字符串的个数
2.从8-20中随机获取一个数作为密码的长度
3.定义出字母和字符串的字符串
4.以密码长度作为循环次数
5.循环中随机获取1-3中的一个数字,如果是1生成一个随机数字,如果是2生成一个随机特殊字符,如果是三生成一个随机字母
6.循环结束后判断1中定义的变量是否有零,如果有递归此方法;
方法二思路
1.使用字符串的特有方法将字符串变成一个数组
2.随机获取一个数组长度(arr.length)范围内的数字
3.将数字下标的元素返回
最后成功的实现了,但是还是希望提供一个更加简便的做法!


    public static void main(String[] args) {
        System.out.println(getRandom());
    }

    private static String getRandom(){
        int length = new Random().nextInt(13)+8;
        StringBuilder sb=new StringBuilder();
        for (int i = 0; i < length; i++) {
            char c = (char) (new Random().nextInt(94)+33);
            sb.append(c);
        }
        return sb.toString();
    }