《HardCore Java》读书笔记系列--之一

最近在图书馆借到了《HardCore Java》(难得图书馆能有这么好的书)。本来是不想看的,但发现其中有几个感兴趣的话题就索性从头读了起来,看完了两章发现自己原来一点都不懂JAVA,为了能更好的记住书中的内容,特记读书笔记于此。这本书的读者至少应该是一个初级程序员,并且使用过一段时间的JAVA,因为这本书谈论的是如何在实际的项目中使用JAVA,指出一些教科书中常用的方法在实际项目中的陷阱,并给出好的建议。

第一章:JAVA in Review
        正象作者在这章的开头所说的:“即使是中级和高级程序员也将从本章获益”,虽然这里列出的是一些零散的东西,但很值得注意(这里我只是挑选了一些,而没有把书上的全部要点写下来,里面也有一些是我个人的理解,而且看的是英文版的,所有如果理解错了,还请多担待,所以这里的内容万万不可全信,最好是自己去看书):
   1continue,break:

        这里要提到的主要是标签(LABEL),在写程序时往往要从多层循环的最内层跳到最外层或者其他层,这时可以使用标签,跳到你想去的地方,JAVA里的标签和其他语言的标签差不多,但是java里面没有goto语句。声明标签时 “label_name:statement...”,使用标签时 “continue/break label_name”,只是在声明标签时,标签名的前面不能有其他标识符或者语句(可以有空格)。但continue/break语句所用的标签名必须是包含当前的语句的语句块,如:

label_1:{
    for(int i=0;i<10;++i){
        ...;
        if(compare()){
            break/continue label_1;
        }
    }
}

这就是合法的。
label_1:{
    for(int i=0;i<10;++i){
        ...;
        if(compare()){
            break/continue label_2;
        }
    }
}
label_2:
    statement;

这就是不合法的。
在continue和break之间还有一些不同,那就是continue语句所使用的标签名所指定的语句块必须是循环语句,而

break则没有这个限制。如:
label_1:{
    statement....
    for(int i=0;i<10;++i){
        ...;
        if(compare()){
            break label_1;
        }
    }
}

这是合法的。
label_1:{
    statement....
    for(int i=0;i<10;++i){
        ...;
        if(compare()){
            continue label_1;
        }
    }
}

这就是非法的。
2 assert
     assert是jdk 1.4引进的,其作用和其他语言中的assert大同小异。其语法是
               assert Boolean_Expression [:Detail_Expression]
注意啊,是expression,而不是statement。
  关于assert和exception的选择,作者给出了如下建议:
 1:不要用assert检查public修饰的函数的参数的合法性。这些函数应该抛出NullPointerException,IllegalArgumentException或者其他的异常,因为这些函数是将被其他程序员使用,但参数出现错误时,使用这些函数的程序员应该知道。
 2:使用assert为protected,private修饰的函数的参数做前置和后置条件检查。
 3:不要用assert检查软件的用户错误,如用户的输入错误等。
 4:用assert检查参数和变量不应该出现的情况,如:
  List list = new ArrayList(otherList);
  assert (list.size()<5):"list size too big";

 5:用assert检查代码的非法分支。如:
  if(i == 1){
      ...;
  }else if(i == 2){
      ...;
  }else{
      assert false:"invalid variable i";
  }

 6:不要用assert做其它的不该做的工作。assert仅仅是一个开发人员级别(developer-level)的错误标志,不要用assert来修改系统的任何其它东西
 7:不要国际化assert的错误消息。原因同上。
 8:用assert来检查后置条件。如:一个函数不应该返回null,那么返回前可以用assert检查
  public List test(){
      List result = null;
      if(condition()){
          result = new List();
          ....;
      }
      ....;
      assert (result != null);
      return result;
  }

注意,assert在java项目中是可以关闭的,这是java虚拟机就会忽略assert语句,所以assert是一个很好的调试语句。
3 Chaining Constructors
  当一个类有多个构造函数时,就会经常出现重复代码,如:
  public class Test{
      public Test(){
          i = 0;
          j = 0;
      }
      public Test(int i){
          this.i = i;
          j = 0;
      }
      public Test(int i,int j){
          this.i = 0;
          this.j = 0;
      }
  }

这是我们完全可以这样写:
  public class Test{
      public Test(){
          this(0,0);
      }
      public Test(int i){
          this(i,0);
      }
      public Test(int i,int j){
          this.i = i;
          this.j = j;
      }
  }

  要注意的是,使用链式构造函数(Chaining Constructors)的时候,就像super()一样,必须把this()放在第一行。
4 Initialization
  如下示例:
  instance-scoped attributes:
 String test = "just a test";
 String test1;
 {
     test1 = "another test";
 }

  class-scoped attributes:
 static String t_1 = "first";
 static String t_2;
 static final String t_3;
 static{
     t_2 = "second";
     t_3 = "third";
 }

  这些都是合法的初始化。
  注意:static{} 的调用是根据它的声明顺序初始化的,所以下面的将是错误的:
 final static String VALUE_ONE = "BLUE";
 static{
     System.out.println(VALUE_ONE);
     System.out.println(VALUE_TWO);//compile error
 }
 final static String VALUE_ONE = "WHITE";
  避免这种错误的最好办法就是首先声明所有的static变量,再声明static方法
  还有就是初始化时不能抛出除RuntimeException类型的异常之外的任何异常。
5 Access Issues
  虽然java中有良好的存取限制机制,但是有一点往往被我们忽略了,那就是对同一个class的不同实例间的存取限制,如下面的类:
  public class FriendAccess{
      private int value;
      public FriendAccess(int value){
          setValue(value);
      };
      public void setValue(int value){   
          this.value = value*3;
      }
      ...;
      public void someMethod(final FriendAccess obj){
          if(obj.value == 5 && this.value == 5){//注意,这是直接存取。
              obj.value = 25;//注意
          }
      }
  }

  我们往往是要使用setValue方法设定value,但是这里我们直接就存取value,这样可能会跳过很多操作,如这里的乘3操作。这也是一个很不容易被发现的bug。
6 Common Mistakes
  6.1 System Streams
    我们一般会习惯于这么写(尤其是使用IDE产生的代码):
 try{
     ...
 }catch (Exception e){
         e.printStackTrace();
         throw new MyExceptions();
 }

    这里的问题是错误消息将会在一个console窗口显示,可是这个窗口可能被隐藏了,活着重定向到其它地方甚至是其它机器。解决办法最好是用自己的方法把消息输出到一个指定的地方,如log4j中的方法都有这样的重载。
  6.2 System.exit()
    System.exit()是推出整个应用程序而不会仅仅是你的模块,所以当你写一个类库或者一个模块的时候最好不要用这个方法,否则整个应用程序可能会莫名其妙的推出了。
  6.3 Default Execution
    我记得在看一些程序语言的教程的时候,在介绍switch语句时通常会建议不要忘了使用default,在default这里放上默认的操作,但这往往会带来问题,如:
    String op;//语句块1
    ....
    if(op.equals("+")){//语句块2
        result = i+j;
    }else if(op.equals("-")){
        result = i-j;
    }else if(op.equals("*")){
        result = i*j;
    }else {
        result = i/j;
    }

这里默认做的是除法,但是如果有一天你又加入了位操作符‘>>’‘<<’,而语句块1离语句块2很远,你忘记了修改语句块2,这时就会得到错误的结果,作者的建议就是不要在默认操作中做任何特定的动作,最好是抛出异常或者是其它你能构容易发现错误的方法。

啊,第一章终于写完了,这里我省去了书上的很多地方,所以你最好去读书。如有错误或不妥之处,欢迎批评指正。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值