本次smtpMTA的编写主要是参考了github上的项目,在读源码,以及自己编写的过程中学到了一些知识,整理一下

枚举类的使用

枚举类适用于一些有限情况的同类型的枚举,构造的时候同样可以包括一些基本的信息,其实枚举类也是一种普通的类,可以有自己的构造器(必须是private,无法从外部调用,只在构造枚举值时使用,(这一点和单例模式的实现很像)),所有的实例都是public static final的,我们的枚举值其实就是一个一个的实例。

HashMap的使用

使用HashMap可以做一些很方便的键值查找,并且效率较高,关于HashMap的具体深入分析,可以看另一篇文章。对一些我们需要使用的static的数据结构,我们可以利用static{}块进行初始化。

关于正则表达式的使用

java的正则表达式主要集中在Pattern和Matcher这两个包中

主要方法

使用Pattern.compile(String regex)来将一个正则表达式的字符串变异成一个Pattern实例。 Pattern.matches()方法用于字符串快速完全匹配正则表达式。 pattern.matcher(String lineForMatch)返回一个Matcher实例,Pattern类只能做一些简单的匹配操作,要想得到更强更便捷的正则匹配操作,那就需要将Pattern与Matcher一起合作.Matcher类提供了对正则表达式的分组支持,以及对正则表达式的多次匹配支持.

matcher进行分组操作

matcher.find返回匹配到的字符串 matcher.start(int i)可以找到第i个分组起始位置的字符index matcher.end(int i)可以找到第i个分组结束位置的字符index matcher.group(int i)返回匹配到的第i个分组。

关于toArray

collectioin.toArray()查看源码可以看到

public Object[] toArray(){
  return Arrays.copyOf(elementData,size);
}

所以这里是对原数组进行了copyOf的操作,没有改变原数组,再来看看重载的方法

public <T> T[] toArray(T[] a) {
    if (a.length < size)
        // Make a new array of a's runtime type, but my contents:
        return (T[]) Arrays.copyOf(elementData, size, a.getClass());
    System.arraycopy(elementData, 0, a, 0, size);
    if (a.length > size)
        a[size] = null;
    return a;
}

可以看到这里,如果T[] a的长度小于Array的长度,就会执行操作(T[]) Arrays.copyOf(elementData, size, a.getClass());,将其中的类型都变成了a的类型,并且也改变了容器的类型。所以这里如果我们要将一个字符类型的list转换成一个字符类型的数组,可以这样实现 x.toArray(new String[0]);

关于线程池

用这个方法可以新建一个线程池实例

ExecutorService executorService = Executors
          .newCachedThreadPool();

当线程把task交给线程池后,该线程就会继续执行与运行任务无关的其它任务;

主要方法

executorService.execute(Runnable),以异步的方式执行这个Runable,无法获得返回值 executorService.submit(Runnable),提交这个Runable给线程池,可以返回一个Future,调用future.get()如果任务结束,则返回null,这里get()方法用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回; executorService.submit(Callable),call方法可以有一个返回值,可以在Future中future.get()调用。

补充

后来在翻看java开发手册的时候发现:(强制)线程池不允许使用Exeutors创建,而是通过ThreadPoolExecutor的方式创建

Excutors返回的线程池的弊端:允许的队列长度是Interger.MAX_VALUE,可能会堆积大量的请求,导致OOM(OutOfMemoryError)

这里理一下线程池 ,可以看一下底层线程池的实现

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

这里的问题就出在LinkedBlockingQueue上,LinkedBlockingQueue是一个用链表实现的有界阻塞队列,容量可以选择进行设置,默认是Integer.MAX_VALUE。这里就会导致线程的创建太多,从而导致OOM,阿里巴巴java开发手册中提倡用ThreadPoolExcutor的方式来创建线程池,这里就指定队列的大小,从而防止无限创建线程,如果超出这个限制数,就会抛出java.util.concurrent.RejectedExecutionException.

new ThreadPoolExecutor(10, 10,
        60L, TimeUnit.SECONDS,
        new ArrayBlockingQueue(10));

调试

在dubug时idea中可以捕获某种特定的异常。

一些代码规范(根据阿里巴巴Java开发手册)

  1. Object的equals方法容易抛空指针异常,应使用常量或确定有值的对象来调用equals
    "test".equals(object);
    
  2. 多次字符串连接的方式使用StringBuilder的append方法进行拓展

参考文章:https://zhuanlan.zhihu.com/p/32867181