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. JQuery在一个简单的表单验证的例子

    html代码例如以下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http:/ ...

  2. python两个整数和浮点的方法来获取值

    /*********************************************************************  * Author  : Samson  * Date   ...

  3. AngularJS ng-if使用

    示例中,根据ng-if指令显示不同任务状态,以及判断任务是否可以操作 <div ng-app="NgifDemoApp" ng-controller="NgifDe ...

  4. 二维码彩色广告招牌的切割制作问题(C#.net下对彩色二维码圆角样式及改进)

    原文:二维码彩色广告招牌的切割制作问题(C#.net下对彩色二维码圆角样式及改进) 我们知道,目前二维码还很少用于广告招牌的制作.但随着智能手机越来越普及,互联网等网络的应用也越来越广泛,作为连接物理 ...

  5. WPF之VirtualizingStackPanel.IsVirtualizing="False"

    原文:WPF之VirtualizingStackPanel.IsVirtualizing="False" 相信从winform转到wpf的人都遇到过这样的困惑,在处理DataGri ...

  6. 配置 Visual Studio Tools for Apache Cordova

    原文:配置 Visual Studio Tools for Apache Cordova 1.连接地址 https://msdn.microsoft.com/zh-cn/library/vs/alm/ ...

  7. Win10《芒果TV》商店版更新v3.2.2:新增对Win10产品专用会员兑换码支持,全新的最具价值用户纪念奖励

    在WinHEC2016宣布Win10和ARM历史性结合之际,<芒果TV>UWP版迅速更新v3.2.2版,主要是新增对Win10产品专用会员兑换码支持,推出全新的最具价值用户纪念奖励(具有唯 ...

  8. C#调用Microsoft.DirectX.DirectSound.dll时出错

    1.修改工程的编译选项.我的开发运行环境是Windows 10 x64系统.需要修改一下工程的编译选项,把AnyCPU改成x86的. 未能加载文件或程序集“Microsoft.DirectX.Dire ...

  9. Android零基础入门第72节:SwipeRefreshLayout下拉刷新

    在实际开发中,经常都会遇到下拉刷新.上拉加载更多的情形,这一期就一起来学习Android系统的SwipeRefreshLayout下拉刷新组件. 一.SwipeRefreshLayout简介 Swip ...

  10. SpringMVC核心架构的具体流程

    核心架构的具体流程步骤如下: 1.首先用户发送请求-->DispatcherServlet,前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行 处理,作为统一访问点,进行全局的流程控 ...