Java代码优化系列(一)开篇立碑

转载请注明出处:http://blog.csdn.net/lhy_ycu/article/details/45506549

在开篇之前,先补充一下《Java学习系列》里面的instanceof关键字的使用及其陷阱。简要说明:instanceof是一个简单的二元操作符,它是用来判断一个对象是否为一个类的实例。只要instanceof左右操作数有继承或实现的关系,程序都是可以编译通过的。下面通过一个简单实例来说明一下instanceof关键字的使用及其陷阱:

class A<T> {
	public boolean isDateInstance(T t) {
		return t instanceof Date;
	}
}

public class InstanceofTest {

	public static void main(String[] args) {
		// true。一个String对象是Object实例(java中Object是所有类的父类)
		System.out.println("zhangsan" instanceof Object);
		// false。Object是父类,它的对象明显不是String类的实例
		System.out.println(new Object() instanceof String);
		// true。一个String对象是String的实例
		System.out.println(new String() instanceof String);
		// 编译不能通过。'a' 为一个char类型,即基本类型
		// System.out.println('a' instanceof Character);
		// false。只要左操作数为null(本质是无类型),那么结果就直接返回false
		System.out.println(null instanceof String);
		// false。即使将null强转也还是个null
		System.out.println((String) null instanceof String);
		// 编译不能通过。因为Date和String并没有继承或实现关系
		// System.out.println(new Date() instanceof String);
		// false。在编译成字节码时,T已经是Object类型了,由于传递了一个"lisi"实参字符串,所以T实际是String类型了。
		System.out.println(new A().isDateInstance("lisi"));
	}
}

【注意】instanceof只能用于对象的判断,不能用于基本类型的判断。

下面开始正式进入主题,先从一个自增的陷阱开始吧。

1)自增的陷阱

int num = 0;
for (int i = 0; i < 100; i++) {
	num = num++;
}
System.out.println("num = " + num);

打印结果是什么呢?答案是0,为什么呢?先看看执行步骤吧,程序第一次循环时的详细步骤如下:JVM把num值(0)拷贝到临时变量区,然后num值加1,这是num的值为1,接着返回临时变量区的值,注意这个值是1没修改过,最后将返回值赋给num,此时num的值被重置为了0。简单说来就是int temp = num; num  += 1; return temp;这3步。所以打印结果还是0,num始终保持着原来的状态。

优化:将num=num++; 修改为num++即可。

2)常量竟成变量?

大家想想,常量有可能成为变量吗?答案是有可能,只不过这种做法是不被认同的。

public static final int RAND_CONST = new Random().nextInt();

public static void main(String[] args) {
	// 通过打印几次,可以看到结果变了,也就是说常量在定义的时候就没有保证它的值运行期保持不变
	System.out.println("常量变了吗?" + RAND_CONST);
}

优化建议:务必常量的值在运行期保持不变,所以可以让RAND_CONST在定义时直接赋值写死。

3)“l” 你能看出这个字母是i的大写、数字1还是字母l的小写?

public static  long l = 11;

优化:字母后缀l尽量大写L

4)三目运算符的类型不一致?

int i = 70;
System.out.println(i < 100 ? 80 : 90.0);

打印结果出人意料,结果竟然为80.0,这是为什么呢?i<100确实为true,但由于最后一个操作数为90.0,是一个浮点数,这时编译器会将第二个操作数80转为80.0浮点数,统一结果类型,所以打印结果为80.0。

优化:90.0改为90

5)不要重载含有变长参数的方法

简要说明:变长参数必须是方法的最后一个参数,且一个方法不能定义多个变长参数。

public class Test01 {
	public static void fruitPrice(int price, int discount) {
		float realPrice = price * discount / 100.0F;
		System.out.println("非变长参数得出的结果:realPrice = " + realPrice);
	}

	public static void fruitPrice(int price, int... discounts) {
		float realPrice = price;
		for (int discount : discounts) {
			realPrice = price * discount / 100.0F;
		}
		System.out.println("变长参数得出的结果:realPrice = " + realPrice);
	}

	public static void main(String[] args) {
		fruitPrice(48888, 85);
	}
}

打印结果是什么呢?答案是:非变长参数得出的结果:realPrice = 41554.8,也就是程序执行的是第一个方法,而没有执行变长参数方法,这是为什么呢?因为Java在编译时,首先会根据实参的数量和类型(这里是2个都是int类型的实参,注意没有转成int数组)来进行处理,也就是找到fruitPrice(int price, int discount)方法,而且确认它符合方法签名条件,由于编译器也爱“偷懒”,所以程序会执行第一个方法。

参考文献:《编写高质量代码》机械工业出版社

时间: 2024-10-13 23:33:34

Java代码优化系列(一)开篇立碑的相关文章

死磕 java同步系列之开篇

简介 同步系列,这是彤哥想了好久的名字,本来是准备写锁相关的内容,但是java中的CountDownLatch.Semaphore.CyclicBarrier这些类又不属于锁,它们和锁又有很多共同点,都是为了协同多线程的执行,都是一种同步器,所以这里就借用同步来取名字了,也就是"同步系列"的来源. 概览 这一篇的内容会比较多,大致包含三大主题:java中的锁.同步器.分布式锁,大致讲的内容如下: (1)volatile (2)synchronized (3)AQS及Condition

死磕 java同步系列之Semaphore源码解析

问题 (1)Semaphore是什么? (2)Semaphore具有哪些特性? (3)Semaphore通常使用在什么场景中? (4)Semaphore的许可次数是否可以动态增减? (5)Semaphore如何实现限流? 简介 Semaphore,信号量,它保存了一系列的许可(permits),每次调用acquire()都将消耗一个许可,每次调用release()都将归还一个许可. 特性 Semaphore通常用于限制同一时间对共享资源的访问次数上,也就是常说的限流. 下面我们一起来学习Java

死磕 java同步系列之CountDownLatch源码解析

??欢迎关注我的公众号"彤哥读源码",查看更多源码系列文章, 与彤哥一起畅游源码的海洋. (手机横屏看源码更方便) 问题 (1)CountDownLatch是什么? (2)CountDownLatch具有哪些特性? (3)CountDownLatch通常运用在什么场景中? (4)CountDownLatch的初始次数是否可以调整? 简介 CountDownLatch,可以翻译为倒计时器,但是似乎不太准确,它的含义是允许一个或多个线程等待其它线程的操作执行完毕后再执行后续的操作. Cou

死磕 java同步系列之AQS终篇(面试)

问题 (1)AQS的定位? (2)AQS的重要组成部分? (3)AQS运用的设计模式? (4)AQS的总体流程? 简介 AQS的全称是AbstractQueuedSynchronizer,它的定位是为Java中几乎所有的锁和同步器提供一个基础框架. 在之前的章节中,我们一起学习了ReentrantLock.ReentrantReadWriteLock.Semaphore.CountDownLatch的源码,今天我们一起来对AQS做个总结. 状态变量state AQS中定义了一个状态变量state

死磕 java同步系列之StampedLock源码解析

问题 (1)StampedLock是什么? (2)StampedLock具有什么特性? (3)StampedLock是否支持可重入? (4)StampedLock与ReentrantReadWriteLock的对比? 简介 StampedLock是java8中新增的类,它是一个更加高效的读写锁的实现,而且它不是基于AQS来实现的,它的内部自成一片逻辑,让我们一起来学习吧. StampedLock具有三种模式:写模式.读模式.乐观读模式. ReentrantReadWriteLock中的读和写都是

死磕 java同步系列之CyclicBarrier源码解析——有图有真相

问题 (1)CyclicBarrier是什么? (2)CyclicBarrier具有什么特性? (3)CyclicBarrier与CountDownLatch的对比? 简介 CyclicBarrier,回环栅栏,它会阻塞一组线程直到这些线程同时达到某个条件才继续执行.它与CountDownLatch很类似,但又不同,CountDownLatch需要调用countDown()方法触发事件,而CyclicBarrier不需要,它就像一个栅栏一样,当一组线程都到达了栅栏处才继续往下走. 使用方法 pu

死磕 java同步系列之Phaser源码解析

问题 (1)Phaser是什么? (2)Phaser具有哪些特性? (3)Phaser相对于CyclicBarrier和CountDownLatch的优势? 简介 Phaser,翻译为阶段,它适用于这样一种场景,一个大任务可以分为多个阶段完成,且每个阶段的任务可以多个线程并发执行,但是必须上一个阶段的任务都完成了才可以执行下一个阶段的任务. 这种场景虽然使用CyclicBarrier或者CountryDownLatch也可以实现,但是要复杂的多.首先,具体需要多少个阶段是可能会变的,其次,每个阶

死磕 java同步系列之zookeeper分布式锁

问题 (1)zookeeper如何实现分布式锁? (2)zookeeper分布式锁有哪些优点? (3)zookeeper分布式锁有哪些缺点? 简介 zooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,它可以为分布式应用提供一致性服务,它是Hadoop和Hbase的重要组件,同时也可以作为配置中心.注册中心运用在微服务体系中. 本章我们将介绍zookeeper如何实现分布式锁运用在分布式系统中. 基础知识 什么是znode? zooKeeper操作和维护的为一个个数据节点,称为 z

死磕 java同步系列之redis分布式锁进化史

问题 (1)redis如何实现分布式锁? (2)redis分布式锁有哪些优点? (3)redis分布式锁有哪些缺点? (4)redis实现分布式锁有没有现成的轮子可以使用? 简介 Redis(全称:Remote Dictionary Server 远程字典服务)是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API. 本章我们将介绍如何基于redis实现分布式锁,并把其实现的进化史从头到尾讲明白,以便大家在面试的时候能讲清楚