1. 求长度各有千秋

你是否曾经在面试的时候,经常被问到:数组有没有 length() 方法?字符串有没有 length() 方法? 集合有没有 length() 方法?

面对这个问题,那么不得不吐槽一下,Java 中获取长度的方式,设计着实有点乱,对刚入门的程序猿而言,那绝对是一脸的懵逼。

String[] array = {"abc", "def"};
String str = "abcedf";
List<String> list = new ArrayList<String>();
list.add("abc");
list.add("def");
System.out.println("数组的长度: " + array.length);
System.out.println("字符串的长度: " + str.length());
System.out.println("集合的长度: " + list.size());

正式科普一下,希望能够铭记你心中。数组求长度用 length 属性;字符串求长度用 length() 方法;集合求长度用 size() 方法。

2. 字符串截取有深意

对于程序猿来说,编程规范能够养成良好的编程习惯,提高代码质量,减少沟通成本。阿里 Java 开发手册编程规约中记载,【强制】方法名、參数名、成员变量、局部变量都统一使用 lowerCamelCase 风格,必须遵从驼峰形式。

看到这里,不得不提 String 中的 substring 方法,你是不是经常把“substring”写成“subString”。本次这个命名不是吐槽的重点。主要想分享如下代码片段。

public class StringInterview {
   public static void main(String[] args) {
       String str = "......abcdefgh.......";
       String subStr = str.substring(1,3);
       str = null;
       System.out.println(subStr);
   }
}

假如上述这段程序在 Java 1.6 中运行,代码中虽然强制使 str 引用为空,本意是释放 str 占用的空间,但是这个时候,GC 是无法回收这个大的 char 数组的,因为还在被 subStr 字符串内部引用着,虽然 subStr 只截取这个大数组的一小部分。当 str 是一个非常大字符串的时候,这种浪费是非常明显的,甚至会带来内存泄露问题。

深入 Java 1.6 中 substring 的设计一探究竟。

public String substring(int beginIndex, int endIndex) {
  if (beginIndex < 0) {
      。。 。。 。。
  }
  if (endIndex > count) {
       。。 。。 。。
  }
  if (beginIndex > endIndex) {
       。。 。。 。。
  }
  return ((beginIndex == 0) && (endIndex == count)) ? this :
   new String(offset + beginIndex, endIndex - beginIndex, value);
}

到此你应该拨云见日豁然开朗。当我们调用字符串 str 的 substring 得到字符串 subStr,其实这个操作,无非就是调整了一下 subStr 的 offset 和 count ,用到的内容还是 str 之前的 value 字符数组,并没有重新创建新的专属于 subStr 的内容字符数组。如果 subStr 的生命周期要长于 str 或者手动设置 str 为null,当垃圾回收进行后,str 被回收掉,subStr 没有回收掉,那么内存占用依旧存在,因为 subStr 持有 str 字符数组的引用。

正式科普一下,这个问题出现在 Java 1.6,并且 Java 1.7 中已经修复。虽然已经修复,并不代表我们就不需要了解,如果你正在求职路上,稍微了解一下,说不定会加分。

3. 一条 if 语句引发不满

先给各位抛一段 Java LinkedList 类的代码片段,一起吐槽吐槽。

public E getFirst() {
   final Node<E> f = first;
  if (f == null)
       throw new NoSuchElementException();
   return f.item;
}

JDK 中 if 语句后只有一条语句,大部分都是这么实现的。原则上,if 语句如果后面跟着只有一句话,是可以不加的。但是在我们实际开发中,有些现象却会让你匪夷所思,不信你看看下面的代码片段。
片段一:

if (f == null)
   //抛出异常,或者加一条打印语句,加上此句注释逻辑就变了
   throw new NoSuchElementException();

片段二:

public class Interview {
   public static void main(String[] args) {
       Class c = Interview.class;
       try {
           Object o = c.newInstance();
           if (o instanceof Interview)
               Interview tt = (Interview) o; //为什么会报错?请各位解释原因
       } catch (Exception e) {
           e.printStackTrace();
       }
   }
}

正式科普一下,看似一个简单的编码规范,背后隐藏了多少坑啊,所以为了良好的编程习惯,建议还是统一加上大括号为好,良好的编码习惯是真重要啊。

4. 时间实现也找茬

Tiago Fernandez 做过一次投票,选举最烂的 Java API,排第二的就是日期 API(Date 和Calender)。一言不合就抛代码,如下片段是计算两个日期之间的天数。

public static void main(String[] args) {
   Calendar begin = Calendar.getInstance();
   begin.set(1990, Calendar.JUNE, 17);
   Calendar end = Calendar.getInstance();
   System.out.println(alculatedDays(begin, end));
   System.out.println(alculatedDays(begin, end)); // 为什么显示 0?
}
public static long alculatedDays(Calendar begin, Calendar end) {
   long days = 0;
   while (begin.before(end)) {
       begin.add(Calendar.DAY_OF_MONTH, 1);
       days++;
   }
   return days;
}

alculatedDays 方法,如果连续计算两个 Date 实例的话,第二次会取得 0,因为 Calendar 状态是可变的,考虑到重复计算的场合,最好复制一个新的 Calendar,改造如下

public static long alculatedDays(Calendar begin, Calendar end) {
   Calendar calendar = (Calendar) begin.clone(); // 复制
   long days = 0;
   while (calendar.before(end)) {
       calendar.add(Calendar.DAY_OF_MONTH, 1);
       days++;
   }
   return days;
}

不过万物都在向前进化,因为由于原来老旧的日期 API 一直被人诟病,所以 JDK 1.8 中对日期的改动是特别大的,基本上是引入了一套全新易用的 API,各位有时间可以体验一下。

好了,吐槽中见真谛,今天就讲这么多吧。希望你能 get 到一点点共鸣,如果你比较感兴趣,就多多关注和分享给身边的朋友吧。

吐槽:那些Java设计中不得不说的槽点的更多相关文章

  1. 吐槽,Java 设计的槽点

    今天不灌水,直接上干货!希望下面的讲解,能与你产生一些共鸣. 1. 求长度各有千秋 你是否曾经在面试的时候,经常被问到:数组有没有 length() 方法?字符串有没有 length() 方法? 集合 ...

  2. Java的GUI设计中如何跨界面传值

    在Java设计中我们会遇到登录界面的信息,在后面的某个情况也需要使用. 比如这是笔者的一个登录界面 可以看到获取密码和账号 在这个时候的功能的完成需要密码和账号 // 登录信息的获取 public S ...

  3. 在Java API设计中,面向接口编程的思想,以及接口和工厂的关系

    现在的java API的设计中,提倡面向接口的编程,即在API的设计中,参数的传递和返回建议使用接口,而不是具体的实现类,如一个方法的输入参数类型应该使用Map接口,而不是HashMap或Hashta ...

  4. Java Map 集合类在selenium自动化测试设计中的应用

    我们在设计自动化测试用例的时候,往往很多工作是在处理测试的数据. 测试数据无论用Excel 文件, XML文件或者任何一种形式测存储方式,都会设计到参数化以及我们对数据的操作. 这个时候,我们会用到以 ...

  5. 【Java心得总结六】Java容器中——Collection

    在[Java心得总结五]Java容器上——容器初探这篇博文中,我对Java容器类库从一个整体的偏向于宏观的角度初步认识了Java容器类库.而在这篇博文中,我想着重对容器类库中的Collection容器 ...

  6. Java编程中“为了性能”尽量要做到的一些地方

    最近的机器内存又爆满了,除了新增机器内存外,还应该好好review一下我们的代码,有很多代码编写过于随意化,这些不好的习惯或对程序语言的不了解是应该好好打压打压了. 下面是参考网络资源总结的一些在Ja ...

  7. 编写高质量代码:改善Java程序的151个建议(第一章:JAVA开发中通用的方法和准则)

    编写高质量代码:改善Java程序的151个建议(第一章:JAVA开发中通用的方法和准则) 目录 建议1: 不要在常量和变量中出现易混淆的字母 建议2: 莫让常量蜕变成变量 建议3: 三元操作符的类型务 ...

  8. java编程中'为了性能'一些尽量做到的地方

    原文地址:http://blog.csdn.NET/m13666368773/article/details/7796924 最近的机器内存又爆满了,出了新增机器内存外,还应该好好review一下我们 ...

  9. Java开发中的23种设计模式详解

    [放弃了原文访问者模式的Demo,自己写了一个新使用场景的Demo,加上了自己的理解] [源码地址:https://github.com/leon66666/DesignPattern] 一.设计模式 ...

随机推荐

  1. 作为学术用的 matlab

    1. 可重复实验 程序实现的所谓随机,并非完全的随机,而是由某一算法(或者再需要一个种子值)生成出来的. randn('state', 0) % set state so that example c ...

  2. Java之"Mozilla Rhino"引擎(二)

    在Java中使用Rhino, 能让你使用类似Groovy, ECMAScript...等等之类的不同动态脚本语言, 其中值得推荐的是ECMAScript, 它是Rhino的默认实现, 同时也在JDK1 ...

  3. WPF学习笔记:(二)数据绑定模式与INotifyPropertyChanged接口

    数据绑定模式共有四种:OneTime.OneWay.OneWayToSource和TwoWay,默认是TwoWay.一般来说,完成数据绑定要有三个要点:目标属性是依赖属性.绑定设置和实现了INotif ...

  4. 移花接木:借助 IViewLocationExpander 更换 ASP.NET Core View Component 视图路径

    端午节在家将一个 asp.net 项目向 asp.net core 迁移时遇到了一个问题,用 view component 取代 Html.RenderAction 之后,运行时 view compo ...

  5. WPF 附加属性的使用

    using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threa ...

  6. WPF滚动条嵌套,响应鼠标滑轮事件的处理

    在C# 中,两个ScrollViewer嵌套在一起或者ScrollViewer里面嵌套一个ListBox.Listview(控件本身有scrollviewer)的时候,我们本想要的效果是鼠标滚动整个S ...

  7. 百度蜘蛛ip段代表的不同含义

    有时候我们在分析百度蜘蛛的时候,会发现很多的ip,这些个ip地址,根据后面的参数可以发现都是百度的.刚学习SEO不久的同学肯定要问:这些ip地址到底代表什么含义,是不是不同的ip地址所代表的含义不一样 ...

  8. QLocalServer与QLocalSocket进程通讯

    在Qt中,提供了多种IPC方法,作者所用的是QLocalServer和QLocalSocket.看起来好像和Socket搭上点边,实则底层是windows的name pipe.这应该是支持双工通信的. ...

  9. mage J和Graphpad如何对Western Blot条带灰度分析

    原文 mage J和Graphpad如何对Western Blot条带灰度分析 WB是研究蛋白表达的一个经典方法.对于一些时间点或者是不同组织蛋白表达量的分析就涉及到量的变化.一些凝胶成像软件带有此分 ...

  10. C# DataGridView合计行

    在网上搜了很多关于DataGridView合计行的设计及源码,都不是很合我心意.于是自己写了一个关于合计行的DLL.以后每次要用到合计行的时候只要引用这个DLL就可以了. 效果图如下: 引用Dll: ...