11、Java 其它常用类

一、java.lang.System – 代表 JVM 所在操作平台。


如果要获取操作平台相关的特性,用 System 。

1、标准输入、标准输出、标准错误输出


  • in :标准输入。通常就是键盘
  • out :标准输出。通常就是屏幕
  • err :标准错误输出。通常就是屏幕
// 输出到控制台
System.out.println("Hello, World!"); // 标准输出
System.err.println("Error occurred!"); // 标准错误输出

// 从控制台读取输入
Scanner scanner = new Scanner(System.in);
System.out.print("请输入内容:");
String input = scanner.nextLine();
System.out.println("输入内容:" + input);

2、垃圾回收 或 程序终止


  • exit(int status):结束终止虚拟机,状态码非零,表示异常终止
    • 无论是否还有方法、线程在运行,都会结束终止)。
    • 可能导致资源未释放(如:文件句柄、数据库连接)。
  • gc():建议 JVM 执行垃圾回收(不保证立即执行)。
// 建议执行垃圾回收(实际执行时间不确定)
System.gc();

// 终止程序(状态码 0 表示正常退出)
System.exit(0);

3、高效数组复制


  • arraycopy():高效复制数组
public static void main(String[] args) {
    int[] src = {1, 2, 3, 4, 5};
    int[] dest = new int[5];

    // 复制整个数组
    System.arraycopy(src, 0, dest, 0, src.length);
    // [1, 2, 3, 4, 5]
    System.out.println(Arrays.toString(dest));

    dest = new int[5];

    // 部分复制(从索引 2 开始,复制 2 个元素到目标索引 1 )
    System.arraycopy(src, 2, dest, 1, 2);
    // [0, 3, 4, 0, 0]
    System.out.println(Arrays.toString(dest));
}

4、时间测量


  • currentTimeMillis(), nanoTime():获取当前时间戳(毫秒或纳秒),用于性能测量
public static void main(String[] args) throws InterruptedException {
    long startTime = System.currentTimeMillis();

    // 模拟耗时操作
    Thread.sleep(1000);

    long endTime = System.currentTimeMillis();
        // 耗时(毫秒): 1004
    System.out.println("耗时(毫秒): " + (endTime - startTime));

    // 高精度计时(纳秒)
    long nanoStart = System.nanoTime();
    // ... 执行代码 ...
    long nanoEnd = System.nanoTime();
        // 耗时(纳秒): 157
    System.out.println("耗时(纳秒): " + (nanoEnd - nanoStart));
}

5、环境变量(由操作系统管理)访问


  • getenv():获取操作系统所有的环境变量
  • getenv(String name):获取操作系统指定变量的环境变量
public static void main(String[] args) throws InterruptedException {
    // 获取 操作系统 单个环境变量
    String path = System.getenv("PATH");
    System.out.println("PATH环境变量: " + path);

    System.out.println("======================================================");

    // 获取 操作系统 所有环境变量
    Map<String, String> env = System.getenv();
    env.forEach((k, v) -> System.out.println(k + " = " + v));
}

系统属性 vs 环境变量

  • 系统属性通过 -D 参数设置(如:java -Dapp.mode=prod MyApp),属于 JVM 层面
  • 环境变量操作系统管理(如:PATHJAVA_HOME)。

6、系统属性(由 JVM 层面的 -D 参数设置)管理


  • Static Properties getProperties():获取 JVM 所有系统属性的值。
  • Static Properties getProperties(Sring key):获取 JVM 指定系统属性的值。
public static void main(String[] args) throws InterruptedException {
    // 获取 JVM 单个属性
    String javaVersion = System.getProperty("java.version");
    String userDir = System.getProperty("user.dir");
    System.out.println("Java版本: " + javaVersion);
    System.out.println("用户目录: " + userDir);
    System.out.println("==============================");
    // 获取 JVM 所有属性
    Properties props = System.getProperties();
    // 输出 JVM 中所有的 系统属性
    props.list(System.out);

    System.out.println("==============================");
    // 设置 JVM 自定义属性
    System.setProperty("app.mode", "debug");
    String mode = System.getProperty("app.mode");
    // 输出 "debug"
    System.out.println(mode);
}

二、java.lang.Runtime – 代表 JVM 所在的 JRE


  • JRE(Java 运行时环境) = JVM + 核心类库
    • 通俗地说,如果要获取 JVM 相关的特性,用 Runtime 。
  • 典型的 “单例类” Runtime构造器被隐藏了。
    • 因此,只能通过 getRuntime() 方法来获取 Runtime 实例
  • 核心作用:
    • 系统交互:执行外部进程、获取系统资源信息(如:CPU、内存)、注册 JVM 关闭钩子。
    • 资源管理:监控内存 的使用,触发垃圾回收,终止 JVM。

1、执行外部命令:exec(String command)


  • 功能:执行操作系统命令,返回 Process 对象。
  • 示例:执行 ping 命令。
public static void main(String[] args) {
    // 1、获取 Runtime 实例。
    Runtime runtime = Runtime.getRuntime();

    // 2、执行 操作系统 命令,返回 Process 对象(以 ping 为例)
    try {
        Process process;

        if (System.getProperty("os.name").toLowerCase().contains("win")) {
            // Windows
            process = runtime.exec("ping -n 4 baidu.com");
        } else {
            // Unix/Linux/Mac
            process = runtime.exec("ping -c 4 baidu.com");
        }

        // 读取命令输出
        BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
        String line;
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
        }
        // 等待命令执行完成
        int exitCode = process.waitFor();
        // 命令退出码: 0 
        System.out.println("命令退出码: " + exitCode);
    } catch (IOException | InterruptedException e) {
        e.printStackTrace();
    }
}

2、获取系统资源信息


  • 操作系统信息、cpu 核心数、内存管理。

  • totalMemory():JVM 当前分配的总内存(字节)。
  • freeMemory():JVM 当前空闲内存(字节)。
  • maxMemory():JVM 最大可分配内存(字节)。
  • gc():建议 JVM 执行垃圾回收(不保证立即执行)。
public static void main(String[] args) {
    // 1、获取 Runtime 实例。
    Runtime runtime = Runtime.getRuntime();

    // 2、输出系统信息
        // 操作系统: Mac OS X
    System.out.println("操作系统: " + System.getProperty("os.name"));
    
    // 3、返回 JVM 可用的处理器数量。
        // 处理器核心数: 12
    System.out.println("处理器核心数: " + runtime.availableProcessors());
    
    // 4、内存管理
        // JVM 当前分配的总内存(字节)。
        // 总内存: 258 MB
    System.out.println("总内存: " + runtime.totalMemory() / 1024 / 1024 + " MB");
        // JVM 当前空闲内存(字节)。
        // 空闲内存: 252 MB
    System.out.println("空闲内存: " + runtime.freeMemory() / 1024 / 1024 + " MB");
        // maxMemory():JVM 最大可分配内存(字节)。
        // 最大内存: 4096 MB
    System.out.println("最大内存: " + runtime.maxMemory() / 1024 / 1024 + " MB");

    // 5、手动触发垃圾回收。建议 JVM 执行垃圾回收(不保证立即执行)。
    runtime.gc();
    Thread.sleep(2000);
        // GC 后空闲内存: 26 MB
    System.out.println("GC 后空闲内存: " + runtime.freeMemory() / 1024 / 1024 + " MB");
}

3、终止 JVM:exit(int status)


  • 功能:终止当前 JVM,状态码 0 表示正常退出,非零表示异常。
  • 示例:条件性终止程序。
if (criticalErrorOccurred) {
    // 终止当前 JVM,状态码 0 表示正常退出,非零表示异常。
        // 强制终止,状态码 1
    Runtime.getRuntime().exit(1);
}

4、注册关闭钩子:addShutdownHook(Thread hook)


  • 功能:在 JVM 关闭前执行清理任务(如:释放资源)。
  • 示例:保存日志文件。
public static void main(String[] args) {
    // 1、获取 Runtime 实例。
    Runtime runtime = Runtime.getRuntime();

    // 2、注册关闭钩子
    // 在 JVM 关闭前执行清理任务(如释放资源)。
    runtime.addShutdownHook(new Thread(() -> {
        System.out.println("JVM 关闭中...");
        System.out.println("正在执行清理操作...");
        System.out.println("正在保存日志...");
    }));

    // 终止当前 JVM,状态码 0 表示正常退出,非零表示异常。
    runtime.exit(0);
}

三、Java 生成随机数


1、Math.random() 静态方法


  • 作用:大于或等于 0.0小于 1.0 的伪随机 double 精度值。
  • 本质:用的就是 new java.util.Random()
    • Random 对象 赋值给 Math 的静态内部类 RandomNumberGeneratorHolder 的静态常量 randomNumberGenerator 。
    • 使用 Math.random() 时,就不用每次就 new 一个 Random 对象了。
public static double random() {
    return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble();
}

private static final class RandomNumberGeneratorHolder {
    static final Random randomNumberGenerator = new Random();
}

2、java.util.Random 工具类 – 生成 伪随机数


  • nextInt(int bound):得到一个 [0, bound) 范围内的随机数
    • 因此,bound 参数必须大于 0
    • 否则,会抛出 java.lang.IllegalArgumentException 异常。
  • 示例:
    • 生成 [5, 15] 的整数。
int min = 5, max = 15;
int value = random.nextInt(max - min + 1) + min;
System.out.println("范围随机数: " + value);

  • 使用了 AtomicLong自旋 + CAS ,所以, Random 生成随机数是线程安全的。
    • 高并发场景中,造成了很大的性能开销
public Random() {
    this(seedUniquifier() ^ System.nanoTime());
}

public Random(long seed) {
    if (getClass() == Random.class)
        this.seed = new AtomicLong(initialScramble(seed));
    else {
        // subclass might have overriden setSeed
        this.seed = new AtomicLong();
        setSeed(seed);
    }
}


public int nextInt() {
    // 调用 nextInt 默认会生成 32 个比特位的数字。
    return next(32);
}

public int nextInt(int bound) {
    if (bound <= 0)
        throw new IllegalArgumentException(BadBound);

    int r = next(31);
    int m = bound - 1;
    if ((bound & m) == 0) {
        // i.e., bound is a power of 2
        r = (int)((bound * (long)r) >> 31);
    } else {
        for (int u = r; u - (r = u % bound) + m < 0; u = next(31)){
            ;
        }
    }
    return r;
}

// 计算出 nextseed 会使 CAS,将 nextseed 替换现有 oldseed 。
protected int next(int bits) {
    long oldseed, nextseed;
    AtomicLong seed = this.seed;
    do {
        oldseed = seed.get();
        nextseed = (oldseed * multiplier + addend) & mask;
    } while (!seed.compareAndSet(oldseed, nextseed));
    return (int)(nextseed >>> (48 - bits));
}
  • 只要两个 Random 对象的种子相同,而且方法的调用顺序也相同,它们就会产生相同的数字序列
    • Random 产生的数字并不是真正随机的,而是一种伪随机
public static void main(String[] args) {
    long seed = 12345L;

    Random random1 = new Random(seed);
    Random random2 = new Random(seed);

    // Random1: 51
    System.out.println("Random1: " + random1.nextInt(100));
    // Random2: 51   与 Random1 相同
    System.out.println("Random2: " + random2.nextInt(100));
}

3、java.util.concurrent.ThreadLocalRandom 工具类(Java7)


  • 每个线程必须通过 ThreadLocalRandom.current() 获取自己的实例,禁止跨线程传递
    • 即:不能在多线程之间共享 ThreadLocalRandom 。
import java.util.concurrent.ThreadLocalRandom;

public class ParallelStreamExample {
    public static void main(String[] args) {
        // 生成10个 [100, 200) 的随机数(并行流)
        ThreadLocalRandom.current().ints(10, 100, 200)
                         .parallel()
                         .forEach(System.out::println);
    }
}
  • 虽然 Random 线程安全,但是,由于 CAS 乐观锁在多线程下消耗性能。
    • 所以,多线性推荐使用 ThreadLocalRandom;
  • ThreadLocalRandom 都是通过 UNSAFE 调用本地方法拿到线程本身的一些变量作为外部因子
    • 所有的参数绑定在线程本身,和其他线程没有竞争
    • 所以,可以不加锁就保证线程安全
public static ThreadLocalRandom current() {
    if (UNSAFE.getInt(Thread.currentThread(), PROBE) == 0){
        localInit();
    }
    return instance;
}

static final void localInit() {
    int p = probeGenerator.addAndGet(PROBE_INCREMENT);
    int probe = (p == 0) ? 1 : p; // skip 0
    long seed = mix64(seeder.getAndAdd(SEEDER_INCREMENT));
    Thread t = Thread.currentThread();
    UNSAFE.putLong(t, SEED, seed);
    UNSAFE.putInt(t, PROBE, probe);
}

public int nextInt() {
    return mix32(nextSeed());
}

private static int mix32(long z) {
    z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL;
    return (int)(((z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L) >>> 32);
}

final long nextSeed() {
    Thread t; long r;
    // read and update per-thread seed
    UNSAFE.putLong(t = Thread.currentThread(), SEED,
                   r = UNSAFE.getLong(t, SEED) + GAMMA);
    return r;
}

4、java.Security.SecureRandom


  • Java 提供的加密安全随机数生成器(CSPRNG),专为 高安全性 场景设计。
    • 如:密钥生成、令牌验证、加密盐值等。
  • SecureRandom 通过强随机性算法生成不可预测的随机数,确保安全敏感操作安全性。

  • SecureRandom 可以理解为 Random 升级,它的种子选取比较多。
    • 主要有:时间、CPU 使用情况、点击事件等一些种子,安全性高。
  • 因为 SecureRandom 采用了很多外部参数,会产生熵源不足时阻塞问题。
    • 曾经项目中,因为,有的业务凌晨没有流量,这个问题实际发生过。
    • 建议有明显低谷的业务,低谷时低于 1TPS 时不要用
  • 熵不足的系统(如:某些虚拟化环境)中,/dev/random 可能阻塞
    • 建议用 /dev/urandom(通过配置 -Djava.security.egd=file:/dev/urandom)。
  • 算法选择
    • SecureRandom.getInstanceStrong()
      • 返回平台最强的随机源(可能阻塞直到熵足够)。
    • new SecureRandom()
      • 默认使用 NativePRNG混合模式优先非阻塞源(如:/dev/urandom)。

0、指定算法和提供者

  • 代码:
// 使用 SHA1PRNG 算法(Sun 提供者)
SecureRandom sr1 = SecureRandom.getInstance("SHA1PRNG", "SUN");

// 使用 NativePRNG(依赖 操作系统)
SecureRandom sr2 = SecureRandom.getInstance("NativePRNG");

1、生成随机字节数组(加密盐)

  • 代码:
public static void main(String[] args) {
    // 1、生成随机字节数组(加密盐)
    try {
        // 创建 SecureRandom 实例(默认算法)
            // 或 new SecureRandom()
        SecureRandom secureRandom = SecureRandom.getInstanceStrong();

        // 生成 16 字节的随机盐
        byte[] salt = new byte[16];
        secureRandom.nextBytes(salt);

        // 随机盐(Hex): b91d220a3a63698ff89e72b53c4a6cba
        System.out.println("随机盐(Hex): " + bytesToHex(salt));
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
}

// 字节数组转十六进制字符串
private static String bytesToHex(byte[] bytes) {
    StringBuilder sb = new StringBuilder();
    for (byte b : bytes) {
        sb.append(String.format("%02x", b));
    }
    return sb.toString();
}

2、生成指定范围的随机整数(如 OTP 验证码)

  • 代码:
public static void main(String[] args) {
    // 2、生成指定范围的随机整数(如 OTP 验证码)
    SecureRandom secureRandom = new SecureRandom();
    // 生成 100000-999999 的6位数
    int otp = secureRandom.nextInt(900000) + 100000;
    // OTP 验证码: 105075
    System.out.println("OTP 验证码: " + otp);
}

3、生成加密密钥(AES 密钥)

  • 代码:
public static void main(String[] args) throws NoSuchAlgorithmException {
    // 3、生成加密密钥(AES 密钥)
    KeyGenerator keyGen = KeyGenerator.getInstance("AES");
    SecureRandom secureRandom = new SecureRandom();
        // 256位密钥
    keyGen.init(256, secureRandom);
    SecretKey secretKey = keyGen.generateKey();
    // AES 密钥(Base64): TxU+QzxntpYgQtyFvUCgQgDLHdHYOddfTn4yRJ8qRgU=
    System.out.println("AES 密钥(Base64): " + java.util.Base64.getEncoder().encodeToString(secretKey.getEncoded()));
}

5、随机字符串 生成

  • 随机字符串,可以使用 Apache Commons-Lang 包中的 RandomStringUtils 类。

四、java.lang.Math 类


  • Java 标准库中提供数学运算工具类,包含大量静态方法,可直接调用
  • Math 类方法通常由底层硬件优化,适合高性能计算

1、取整


  • 向上取整
// 4.0
double ceil = Math.ceil(3.2);
  • 向下取整
// 3.0
double floor = Math.floor(3.8);

2、四舍五入


  • Math.round() ‌函数用于将一个数字四舍五入到最接近的整数。其工作原理如下:
  • ‌1、正数四舍五入规则‌:
    • 如果小数部分小于 0.5,则向下舍入(即向下取整)。
    • 如果小数部分大于或等于 0.5,则向上舍入(即向上取整)‌12
  • ‌2、负数四舍五入规则‌:
    • 如果小数部分大于 -0.5,则向上舍入(即向零方向舍入)。
    • 如果小数部分小于或等于 -0.5,则向下舍入(即远离零方向舍入)‌
// 4
long round = Math.round(3.5);

// -3(注意中间值向正无穷舍入)
long roundNeg = Math.round(-3.5);

五、java.util.UUID


  • Java 中用于生成操作 通用唯一标识符 (Universally Unique Identifier,UUID) 的工具类。
  • UUID 是一个 128 位的全局唯一标识符,常用于分布式系统唯一标识数据资源
public static void main(String[] args) {
    // 生成随机 UUID
    UUID uuid = UUID.randomUUID();
        // UUID: 8af85994-1506-4bf3-9205-9bbaaa99c086
    System.out.println("UUID: " + uuid);

    // 解析字符串为 UUID
    UUID parsed = UUID.fromString(uuid.toString());
        // Parsed UUID: 8af85994-1506-4bf3-9205-9bbaaa99c086
    System.out.println("Parsed UUID: " + parsed);

    // 比较 UUID
        // true .
    System.out.println("Equals: " + uuid.equals(parsed));
}

1、版本演化


  • 版本1 - 基于时间戳单调计数器MAC 地址生成。
    • 全局唯一部分有序。
  • 版本2 - 保留用于没有已知详细信息的安全 ID。(基本不再使用
  • 版本3 - 根据提供的某些数据的 MD5 哈希值生成的。
    * RFC 在候选数据中建议了 DNS 和 URL。
  • 版本4 - 根据完全随机的数据生成的。
    • 高随机性,无顺序性,重复概率极低。
    • 适合无需排序的场景(如:会话 ID)。
  • 版本5 - 根据提供的一些数据的 SHA1 哈希值生成的。比版本3更安全
    * 与 v3 一样,RFC 建议使用 DNS 或 URL 作为候选。
  • 版本6 - 基于时间戳单调计数器MAC 地址生成。
    * 这些数据与版本 1 相同,但更改了顺序,以便对它们进行排序时将按创建时间排序
    • 时间戳部分自然排序,适合数据库主键。
  • 版本7 - 由时间戳随机数据生成。
    • Unix时间戳(毫秒,48位) + 随机数(74位)
    • 系统时间兼容,无需依赖节点ID。
    • 时间戳高位保证有序,适合分布式系统
  • 版本8 - 完全是自定义的(除了所有版本都包含的必需版本/变体字段)。

2、版本选择建议


  • 需要 时间有序
    • 优先选择 v6/v7(若环境支持),其次 v1(注意隐私)。
  • 需要 完全随机
    • 使用 v4(默认选择)。
  • 需要 确定性生成
    • 使用 v3/v5(如资源唯一标识)。
  • 需要 自定义结构
    • 使用 v8 或自行实现。

六、Comparable 和 Comparator


1、实现自定义排序的两个接口


  • 对象实现 Comparable 接口
  • 定义比较规则的类实现 Comparator 接口

2、代码


public class AboutSort {
    public static void main(String[] args) {
        User user1 = new User(0);
        User user2 = new User(0);
        System.out.println(user1.compareTo(user2));

        Shoper shoper1 = new Shoper(1);
        Shoper shoper2 = new Shoper(2);
        Shoper.ShoperComparator comparator = new Shoper(0).new ShoperComparator();
        System.out.println(comparator.compare(shoper1, shoper2));
    }
}

class User implements Comparable<User>{
    int age;

    public User(int age) {
        this.age = age;
    }

    @Override
    public int compareTo(User user) {
        if(null == user){
            throw new RuntimeException("被比较对象不能为 null");
        }
        int ageGap = this.age - user.age;
        return ageGap < 0 ? -1 : ageGap > 0 ? 1 : 0;
    }
}

class Shoper {
    int age;

    public Shoper(int age) {
        this.age = age;
    }

    class ShoperComparator implements Comparator<Shoper>{
        @Override
        public int compare(Shoper o1, Shoper o2) {
            int ageGap = o1.age - o2.age;
            return ageGap < 0 ? -1 : ageGap > 0 ? 1 : 0;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值