美文网首页Android开发经验谈
转角遇到爱_1,你不知道的Java

转角遇到爱_1,你不知道的Java

作者: 大公爵 | 来源:发表于2019-06-12 11:34 被阅读4次

闲聊

一时无聊,在简书开一个文集,专门记录一些技术上的偏门知识,少用但有用的知识。也不知道该取什么名字,就叫转角遇到爱吧。

有丰富开发经验的人一定都有体会,真正在项目开发中,实现功能的时间其实并不长,大量的时间是浪费在了解决一些稀奇古怪的问题上,有很多冷门、少见的技术我们不知道,知道后才发现这么神奇,就拿Android开发来说,你用300行代码实现一个效果,可能一个神奇的属性就搞定了。而这些冷门的知识我们不常用,用过一次之后很快又忘记了,下次遇到同样的问题又要Google很久。这就是我决定写这个系列的原因,把一些冷门的知识汇集起来,方便自己和大家查询。

1、魔鬼死循环

boolean flag = false;
for (int i = Integer.MIN_VALUE; i <= Integer.MAX_VALUE; i++) {
    flag = !flag;
}
System.out.println(flag);

大多数人第一反应就是:flag初始为false,执行奇数次就是true,偶数次就是false,所以问题就是for循环执行奇数次还是偶数次。

如果你是这么想的,那你就上当了,这段代码的执行结果是死循环。因为Integer.MAX_VALUE + 1 = Integer.MIN_VALUE。Java中Integer类型值域范围一旦超过就会回头,变成最小值,是不是恍然大悟。

System.out.println(Integer.MIN_VALUE);
System.out.println(Integer.MAX_VALUE + 1);

// 执行结果
-2147483648
-2147483648

2、Java7.0的try-with-resources

在 Java7之前,可以使用 finally 块来确保资源被关闭,不管 try 语句正常地完成或是发生意外。

BufferedReader br = new BufferedReader(new FileReader(path));
try {
    return br.readLine();
} finally {
    if (br != null) br.close();
}

Java7之后,使用try-with-resources语句,当try退出时,会自动调用res.close()方法。不管代码块如何退出,只要之前已经被创建出来,它们都会被关闭。那什么样的资源会被关闭呢?任何实现了 java.lang.AutoCloseable的对象, 包括所有实现了 java.io.Closeable的对象, 都可以用作一个资源。

try (BufferedReader br = new BufferedReader(new FileReader(path))) {
    return br.readLine();
}

可以在一个 try-with-resources 语句中声明一个或多个资源。资源的 close 方法调用顺序与它们的创建顺序相反。

try (
  File file = new File("");
  FileReader fr = new FileReader(file);
  BufferedReader br = new BufferedReader(fr);
) {
    // do someting
}

3、数字下划线分割

我们在显示大数金额时,通常会用逗号分隔符,便于清晰读出数值。Java7之后,对于数字也支持下划线分割。

long one_million = 1_000_000_000;
System.out.println(one_million);

// 输出结果
1000000000

4、Math.abs()绝对值

你猜下面的代码打印结果是什么?

int i = Math.abs(Integer.MIN_VALUE);  
System.out.println(i)

结果还是Integer.MIN_VALUE,吃惊吧!

Math.abs()并不是一定会给你返回正数,原因很简单,就是Integer的值域问题,Integer的最大值是2147483647,最小值是-2147483648,绝对值就是2147483648,还记得前面的那个魔鬼死循环吗?
Integer.MAX_VALUE + 1 = Integer.MIN_VALUE;就是这么无语。

5、ArrayList扩容

正常创建一个ArrayList你会这么写:

ArrayList a = new ArrayList();

对应ArrayList的无参构造函数:

public ArrayList() {
    super();
    this.elementData = EMPTY_ELEMENTDATA;
}

这里有一个细节,ArrayList 底层采用 Object 类型的数组实现,当使用无参构造方法时,ArrayList 底层会生成一个长度为 10 的 Object 类型数组,当向 ArrayList 添加对象时,计数加 1,并计算容量是否适当,当存储的元素个数超过容量时,就会新建一个数组,新数组的长度是原来的1.5倍,然后把原来数组的内容拷贝大新数组。

注意,这个复制操作是非常伤性能的,如果 ArrayList 很大,执行数百次扩容,那么就会进行更多次数的新数组分配操作,以及更多次数的旧数组回收操作。于是你就会发现性能越来越差,但是又不知道为什么。

正因为如此,所以才有了第二个构造函数,传入一个指定值,作为初始数组的大小。

public ArrayList(int initialCapacity) {
    super();
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
    this.elementData = new Object[initialCapacity];
}

比如,你预期你的ArrayList至少会保存100个对象,那么你就使用第二个构造函数,传入100。这样,前100次添加都不会有数组的拷贝操作。

ArrayList a = new ArrayList(100);

总结:如果你能预期ArrayList会保存大量的数据,那么请使用第二个构造函数,传入一个合适的值作为初始容量,尽可能避免大量的性能消耗。

6、单例模式

说起单例模式,相信大多数人都能徒手写出来,毕竟是最简单的设计模式,所以我主要讲一下4种单例写法的递进关系。

1、基础形式
这是最简单的形式,申明静态实例的时候直接创建对象。

public class Singleton {
 
    private static Singleton instance = new Singleton();
 
    private Singleton(){}
 
    public static Singleton getInstance(){
        return instance;
    }
}

这中写法的缺点很明显,在初始化类的时候就创建了对象,如果我们没有用到这个单例,那就是一种浪费。所以我们需要改进。

2、懒惰形式
比起基础形式,这种形式的好处就是可以在需要的时候初始化实例。

public class Singleton {
 
    private Singleton(){}
 
    private static Singleton instance = null;
 
    public static Singleton getInstance(){
        if(instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}

虽然解决了延迟初始化的问题,但是还有个明显的问题就是线程不安全,所以还需要继续优化。

3、方法锁形式
在方法上使用synchronized关键字就可以处理多个线程同时访问的问题。每个类实例对应一个线程锁, synchronized 修饰的方法必须获得调用该方法的类实例的锁方能执行, 否则所属线程阻塞。方法一旦执行, 就独占该锁,直到从该方法返回时才将锁释放。此后被阻塞的线程方能获得该锁, 重新进入可执行状态。

public class Singleton {
 
    private Singleton(){}
 
    private static Singleton instance = null;
 
    public static synchronized Singleton getInstance(){
        if(instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}

4、Class锁形式
上面的写法虽然是线程安全的,但是每次调用 getInstance() 方法都需要进行线程锁定判断,在多线程高并发访问环境中,将会导致系统性能下降。事实上,不仅效率很低,99%情况下不需要线程锁定判断。这个时候,我们可以通过双重校验锁的方式进行处理。换句话说,利用双重校验锁,第一次检查是否实例已经创建,如果还没创建,再进行同步的方式创建单例对象。

public class Singleton {
 
    private Singleton(){}
 
    private static Singleton instance = null;
 
    public static Singleton getInstance(){
        if(instance == null){
            synchronized(Singleton.class){
                if(instance == null){
                    instance = new Singleton();
                }
            }    
        }
        return instance;
    }
}

相关文章

  • 转角遇到爱_1,你不知道的Java

    闲聊 一时无聊,在简书开一个文集,专门记录一些技术上的偏门知识,少用但有用的知识。也不知道该取什么名字,就叫转角遇...

  • 转角遇到爱(1)

    覃越要结婚了 七月流火,兰城的天气一日比一日地凉了下来。窗外的树枝摆脱了绵软的可怜相,渐渐回到了从前刚劲有力的模样...

  • 转角遇到爱1

    1 “放开我!你疯了吗?快点松手!” 夜里十一点,偶尔才看见一辆汽车飞驰而过,更别想看到什么行人了,岳晨的手心全是...

  • 2017-11-14

    转角遇到爱

  • 转角遇到爱

    昨晚带宇航买饭团的笼子,因为早上我上班出门前交代她涮我俩的盘子,宇航满口答应。晚上买完笼子,宇航给我坦白:妈妈早上...

  • 转角遇到爱

    相遇,最美。下一个转角,会不会和你相遇? ...

  • 转角遇到爱

    这世界 能轻而易举 豪不费劲做到的—— 是贫穷和衰老 其他的都需要努力和坚持; 这世界 能轻而易举 毫不费劲得到的...

  • 转角遇到爱

    早起上班,哗啦啦的大雨,一点也没有要停的趋势,待走到楼下,发现电动车的雨衣里储存的雨水都可以养小鱼了。 一点都不喜...

  • 转角遇到爱

    “三点一线!”张沐走过转角的地方忽然想到了这个词,大多头脑中有这个概念的人一般都是出于对大学无聊生活的一种抱怨。张...

  • 转角遇到爱

    呃,今天竟然吃芹菜!! 还有很多作业,没开始写! 伐开心! 听麻师说,蚂蚁观花,能让我换个视角看世界 好美呀! 很...

网友评论

    本文标题:转角遇到爱_1,你不知道的Java

    本文链接:https://www.haomeiwen.com/subject/sysabqtx.html