zoukankan      html  css  js  c++  java
  • OpenJDK源码研究笔记(十五):吐槽JDK中的10个富有争议的设计

    前14篇文章,分享了JDK中值得学习和借鉴的编码和设计方法。

    每个硬币都是有两面的。Every coin has two sides。

    当然,JDK中也有很多值得改进或者说富有争议的设计。

    本篇,就来详细吐槽下JDK中的10个富有争议的设计。

    网友指出
    1.求和抛异常,错误提示不合理。

      在OpenJDK源码研究笔记(一)-参数检查&抛出带关键错误提示信息的异常 这篇文章中,有个网友指出:“第三个if的提示信息有点问题。前两个if说明了position和size都不可能为负,求和通常不可能为负,只有一种情况是 求和 溢出了吧,此时异常信息再这样抛,反而是信息不明确

    protected FileLock(AsynchronousFileChannel channel, long position,
                long size, boolean shared) {
            if (position < 0)
                throw new IllegalArgumentException("Negative position");
            if (size < 0)
                throw new IllegalArgumentException("Negative size");
            if (position + size < 0)
                throw new IllegalArgumentException("Negative position + size");
            this.channel = channel;
            this.position = position;
            this.size = size;
            this.shared = shared;
        }


    2.标记接口可以用注解替代。

    OpenJDK源码研究笔记(三)-RandomAccess等标记接口的作用 这篇文章中,有个网友指出:“空接口,比如 Serializable 之类的,都只是一个记号, 其实用annotation 更合适。”

    比如ArrayList的定义是 class ArrayList implements Serialiable{}。

    可以修改为@Serialize
    class ArrayList{}
    几个观点

    a.注解是JDK1.5才有的。之前的API当然还是应该支持。
    注解的话,我觉得也是可以的。可能看起来不够简洁。
    实现一个空的接口,用instanceof挺方便的。

    b.实现接口也好,用注解也好。最终,都是一种设计的2种不同实现。
    实现接口用Instance of,用注解 调用方法。
    用接口能够更好地兼容以前的代码。
    c.从兼容的角度看,确实是的。
    但是从设计目的来看,注解更好。
    而且不影响对象继承结构,就是加了个标记。


    方法定义
    3.重复定义方法。

     

    public interface List<E> extends Collection<E>{
    
        int size();
        boolean isEmpty();
    
    }


    既然继承了父接口Collection,为何还要 重复去定义父类中已经存在的接口??

    public interface Set<E> extends Collection<E>等接口的定义 也是如此。

    4.双端队列同一种操作有2种类似的实现。
     

    java.util.Deque<E>
        /**
         * 查询队列中的第1个元素。
         * 当队列为空时,返回null。
    
         */
        E peekFirst();
     
    
      /**
         * 查询队列中的第1个元素。
         * 与peekFirst方法不同的是,当队列为空时,抛出异常。
         * @throws NoSuchElementException if this deque is empty
         */
        E getFirst();
    


    为什么要定义2套API呢?显得有些重复,容易让人产生疑惑。
     

    5.集合接口Set的返回值不同。

     

    java.util.Set
    
     public abstract E get(int index);
     public E set(int index, E element);
    
      public boolean add(E e);
     
    



     为什么就这个方法没有返回值呢?

      public void add(int index, E element) ;

      上面的3个方法都是有返回值的,同样是add(E e)也是有boolean返回值。

    设计问题 
    6.List生成子列表后,就不能再操作原列表。

       

    List<E> subList(int fromIndex, int toIndex);
       List<String> list = new ArrayList<String>();
    
      list.add("A");
    
      list.add("B");
    
      List<String> subList = list.subList(0,2);
    
      subList.add("C");


    以上代码会抛出java.util.ConcurrentModificationException

      有的时候,我们确实有这个需求。

      既然JDK这样设计,我们只能尽可能避开上述用法。

    7.不可变集合的实现方式。
     java.util.Collections.unmodifiableList(list);

    这种方法的实现,其实返回一个“不可变”的List实现。

    static class UnmodifiableList<E> extends UnmodifiableCollection<E>
       implements List<E> {
      private static final long serialVersionUID = -283967356065247728L;
      final List<? extends E> list;
    
      UnmodifiableList(List<? extends E> list) {
       super(list);
       this.list = list;
      }
    
      public E get(int index) {
       return list.get(index);
      }
    
      public E set(int index, E element) {
       throw new UnsupportedOperationException();
      }
    
      public void add(int index, E element) {
       throw new UnsupportedOperationException();
      }
    
      public E remove(int index) {
       throw new UnsupportedOperationException();
      }
    
    }


    把那些会修改List的方法,以抛出异常的方式实现。

    在看源码之前,我总觉得有其它方法实现。

    看到源码是这种方式实现的,我有点失望。

    看来是我想多了。

     
    8.参数检查不合理。
     

    java.util.logging.Handler.setFormatter(Formatter)
     
     public void setFormatter(Formatter newFormatter) throws SecurityException {
      checkAccess();
      // Check for a null pointer:
      newFormatter.getClass();
      formatter = newFormatter;
     }


    就是简单地调用一个类的方法newFormatter.getClass();来检查该类是否为null。

    这种方式是否更好呢?

    if(newFormatter==null){

        throw new NullPointerException("");

     编码习惯

     9.一条If语句的括号问题。
     大部分的只有一条语句的if语句是这么写的。
     

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


    我比较习惯以下写法,防止“看走眼”。
     if (f == null){
        throw new NoSuchElementException();
     }
     另外,我经常会写下面这样的注释,
     if (f == null)
       //抛出异常,或者加一条打印语句
       throw new NoSuchElementException();
      这种写法,很容易看错。
     
     这种类似的代码有很多,如果if语句再嵌套一层,就更容易看错了。
     

    public ScriptEngineManager() {
      ClassLoader ctxtLoader = Thread.currentThread().getContextClassLoader();
      if (canCallerAccessLoader(ctxtLoader)) {
        if (DEBUG)
         System.out.println("using " + ctxtLoader);
        init(ctxtLoader);
      } else {
       if (DEBUG)
        System.out.println("using bootstrap loader");
        init(null);
       }
     }
     



    10.没有用的变量。
     java.util.logging.LogManager中有如下变量定义。
     private final static Handler[] emptyHandlers = {};
     上面的代码是没有用到的。

     Eclipse会有警告,黄色的感叹号还是比较烦人的。

    相关阅读

    我的CSDN博客专栏  OpenJDK源码研究笔记

    OpenJDK源码研究过程中整理的学习笔记。 OpenJDK是GPL许可(GPL-licensed)的Java平台的开源实现。

    原文参见http://FansUnion.cn/articles/3174(小雷网-FansUnion.cn)

  • 相关阅读:
    国家语言,语言代码,locale id对应表
    SpringMVC,SpringBoot文件下载
    lombok使用基础教程
    博客园主题修改中用到的css属性
    Hexo next博客添加折叠块功能添加折叠代码块
    IntelIj IDEA运行JUnit Test OutOfMemoryError
    Spring Boot-JPA、Hibernate、Spring data jpa之间的关系
    IntelliJ IDEA-设置字体大小
    win10-mysql卸载干净
    IntelliJ IDEA Check out from git
  • 原文地址:https://www.cnblogs.com/qitian1/p/6463450.html
Copyright © 2011-2022 走看看