一些JAVA常用API的用法,可能会极大提高你的编程效率(一)

目录

其他API

快速获得随机数

强行四舍五入

查看数值二进制的方法

测试运行时间的更精确方式


其他API

我会按照java的各个体系,分类介绍一些比较基础的API,比如string体系的,collection体系的,本章介绍的是一些比较常用,但我并不打算介绍完他们的整个体系的API,所以先放在“其他API”一类。

快速获得随机数

大家想获得随机数,一般都是要两个步骤:新建random对象,用random对象获得随机数

public static int getRandomValue(int n) {
    /* 获取[0,n)的随机整数 */
    Random random = new Random();        //获得random对象
    return random.nextInt(n);    //通过random对象获得随机值
}

通过Math.random()可以一步到位:

    public static int getRandomInt(int n) {
        /* 获取[0,n)的随机整数 */
        return  (int) (Math.random() * n);
    }

这个方法可以让我们省去创建random对象的麻烦,而且可扩展性一点不比random.next()差:

    /**
     *获得[0,max)的随机整数
     */
    public static int getRandomInt(int max) {
        return (int) (Math.random() * max);
    }

    /**
     * 获得[lo,hi)的随机小数
     */
    public static double getRandomDouble(double lo, double hi) {
        return Math.random() * (hi - lo) + lo;
    }

    /**
     * 获得[lo,hi)的随机整数
     */
    public static int getRandomInt(int lo, int hi) {
        return getRandomInt(hi - lo) + lo;
    }

其实通过查看源码,发现Math.random()的本质还是random.nextDouble()而已:

    /* Math类中的部分源码 */

    private static final class RandomNumberGeneratorHolder {
        static final Random randomNumberGenerator = new Random();
    }
    public static double random() {
        return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble();
    }

以后我们就用Math.random()来代替新建random对象吧!

 

强行四舍五入

有时当我们计算得到一个双精度浮点数,结果会很长,因为double是可以保留到小数点后面15位(虽然并不精确),这就导致我们的打印结果非常难看。

public class TestDemo {
    public static void main(String[] args) {
        // 打印20以内随机11个数的平均数
        IntStream.generate(() -> ((int) (Math.random() * 20))) //Math生成随机数
                .limit(11)
                .average()
                .ifPresent(System.out::println);    //9.909090909090908
                
    }
}

打印结果很长而且无意义,Math有一个around()方法能让小数四舍五入得到一个整数。

public class RoundTest {
    public static void main(String[] args) {
        double db=2.551549683573541;
        System.out.println("Math.round(db) = " + Math.round(db));     //Math.round(db) = 3
    }
}

但是当我们需要要小数点后面两个数值的时候,around()方法就显得异常尴尬,但其实只需要简单一步就能化解尴尬:printf()

public class TestDemo {
    public static void main(String[] args) {
        // 改进版的四舍五入!
        IntStream.generate(() -> ((int) (Math.random() * 20)))  //Math生成随机数
                .limit(11)
                .average()
                .ifPresent(aver-> System.out.printf("%.2f",aver));  //5.73
    }
}

马上乖乖变成5.73,其中printf()是一个规定了打印格式的方法,以后的博文会进一步讲下这个方法。现在就先记住printf()这个方法就好了!

另外要注意,double的值是不精确的,这个方法也只是强行把后面的小数去掉的方法,在开发测试中可以用,在实际工作中,还是要用BigDecimal的setScale方法。

 

查看数值二进制的方法

String Integer.toBinaryString(int)  这个静态方法可以把一个整数类型变成二进制的字符串输出。同理还有Integer.toHexString(int) / Integer.toOrcString(int) 分别返回十六进制和八进制的字符串,这些方法对我们开发中查看数值底层是很有帮助的:

public class IntegerTest {
    public static void main(String[] args) {
        testInt();
        System.out.println("---------");
        testChar();
        System.out.println("---------");

        String str = "你好吗";
        char[] chars = str.toCharArray();
        System.out.println("查看每个字符的2进制码:");
        for (char aChar : chars) {
           System.out.println(aChar+" : "+Integer.toBinaryString(aChar));
        }
        System.out.println();
        System.out.println("查看每个字符的16进制码");
        for (char aChar : chars) {
            System.out.println(aChar+" : "+Integer.toHexString(aChar));
        }
    }

    public static void testInt() {
        System.out.println("Integer.toBinaryString(30) = " + Integer.toBinaryString(30));
        System.out.println("Integer.toHexString(30) = " + Integer.toHexString(30));
        System.out.println("Integer.toOctalString(30) = " + Integer.toOctalString(30));
    }

    public static void testChar() {
        System.out.println("Integer.toBinaryString('b') = " + Integer.toBinaryString('b'));
        System.out.println("Integer.toHexString('b') = " + Integer.toHexString('b'));
        System.out.println("Integer.toOctalString('b') = " + Integer.toOctalString('b'));
    }
}

Integer.toBinaryString(30) = 11110
Integer.toHexString(30) = 1e
Integer.toOctalString(30) = 36
---------
Integer.toBinaryString('b') = 1100010
Integer.toHexString('b') = 62
Integer.toOctalString('b') = 142
---------
查看每个字符的2进制:
你 : 100111101100000
好 : 101100101111101
吗 : 101010000010111

查看每个字符的16进制码
你 : 4f60
好 : 597d
吗 : 5417

但是这个方法在处理负数的时候就不太好使:

public class ByteString {
    public static void main(String[] args) {
        byte[] bytes = "小鹏头".getBytes();  //通过字符串获得字节数组
        int count = 1;
        for (byte aByte : bytes) {

            System.out.print(aByte+":"+Integer.toHexString(aByte)+" ");
            //System.out.printf("%x ",aByte);
            if (count++%3==0) {
                System.out.println();
            }
        }
    }
}

运行结果:

-27:ffffffe5 -80:ffffffb0 -113:ffffff8f 
-23:ffffffe9 -71:ffffffb9 -113:ffffff8f 
-27:ffffffe5 -92:ffffffa4 -76:ffffffb4

可以看到有很多诡异的ffff在前面,这是因为java 的负数是取数字的补码的原因,我们这里不深入探讨这方面,想进一步了解的同学可以前往:https://blog.csdn.net/weixin_37870009/article/details/79775926 了解。

那如何拿到byte正确的16进制字符串呢?还是用格式化输出语句:printf() 我们用"%x"可以指定一个整数以16进制的字符串格式输出。

public class ByteString {
    public static void main(String[] args) {
        byte[] bytes = "小鹏头".getBytes();   //通过字符串获得字节数组
        int count = 1;
        for (byte aByte : bytes) {
            //System.out.print(":"+Integer.toHexString(aByte)+" ");
            System.out.printf(aByte+":%x   ",aByte);    //用格式化输出处理字节元素
            if (count++%3==0) {
                System.out.println();
            }
        }
    }
}

输出结果:
-27:e5   -80:b0   -113:8f   
-23:e9   -71:b9   -113:8f   
-27:e5   -92:a4   -76:b4   

可以得到清晰的16进制字符串,我们是把“小鹏头”这个字符串按照“UTF-8”编码来编程字节码然后输出了。

 

测试运行时间的更精确方式

很多人都用System.currentTimeMillis()来测试任务耗时,但有的时候,currentTimeMillis并不是很精确,用System.nanoTime()可以获得更精确的时间:

public class TestDemo {
    public static void main(String[] args) {
        /* 新建一个任务:用foreach方式遍历一个数组 */
        int[] ints = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        TodoList one = () -> {
            for (int anInt : ints) {
                System.out.print(anInt + ",");
            }
        };
        /* 新建一个:用Stream方式遍历一个数组 */
        TodoList two = () -> IntStream.of(ints).forEach(n-> System.out.print(n+","));
        //分别测试各个耗时:
        System.out.println("任务一");
        testInNano(one);
        System.out.println("任务二");
        testInNano(two);

        System.out.println("任务一:");
        testInMillion(one);
        System.out.println("任务二:");
        testInMillion(two);
    }

    public static void testInMillion(TodoList todoList) {
        long begin = System.currentTimeMillis();
        todoList.doSomething();
        System.out.println("以毫秒为单位的测试:" + (System.currentTimeMillis() - begin));
    }

    public static void testInNano(TodoList todoList) {
        long begin = System.nanoTime();
        todoList.doSomething();
        System.out.println("以纳秒为单位的测试:" + (System.nanoTime() - begin));
    }
}


任务一
1,2,3,4,5,6,7,8,9,10,以纳秒为单位的测试:18332792
任务二
1,2,3,4,5,6,7,8,9,10,以纳秒为单位的测试:4451214
任务一:
1,2,3,4,5,6,7,8,9,10,以毫秒为单位的测试:0
任务二:
1,2,3,4,5,6,7,8,9,10,以毫秒为单位的测试:0

可以看到,一些操作如果以毫秒为单位会获得0毫秒,只有以纳秒为单位才能得到运行时间。1毫秒 = 1000 000 纳秒 。

System.currentTimeMillis()得到的是1970年0时0分0秒到现在的毫秒值,而System.nanoTime()得到的时间毫无意义,他只能用来跟之前的纳秒值作相减才有意义,每次启动JVM都会以不同的时间点作为纳秒的0点。

另外,其实从上述测试可以看出,sream比传统的foreach是真的速度快很多的!

本章所有源码已经上传github:https://github.com/huheman/Blog/tree/master/API_test/src

本人水平有限,如您发现有任何错漏,请在评论中不吝指教

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值