1.泛型
通过引入泛型,我们将获得编译时类型的安全和运行时更小地抛出ClassCastExceptions的可能。
// new HashMap<String, Object> 此处需要指定map的类型
Map<String, Object> map = new HashMap<String, Object>(2);
2.foreach,更简洁的for循环
// 这种for循环更具可读性
for (Object obj: Objects) {
// code
}
3.自动拆箱装箱
自动装箱就是Java自动将原始类型值转换成对应的对象,比如将int的变量转换成Integer对象,这个过程叫做装箱,反之将Integer对象转换成int类型值,这个过程叫做拆箱。因为这里的装箱和拆箱是自动进行的非人为转换,所以就称作为自动装箱和拆箱。
原始类型byte,short,char,int,long,float,double和boolean对应的封装类为Byte,Short,Character,Integer,Long,Float,Double,Boolean。
// 手动拆装箱 - before autoboxing
Integer iObject = Integer.valueOf(3);
int iPrimitive = iObject.intValue();
// java5之后 - after java5
Integer iObject = 3; // 自动拆装箱 - primitive to wrapper conversion
int iPrimitive = iObject;
4.枚举
创建枚举类型要使用 enum 关键字,隐含了所创建的类型都是 java.lang.Enum 类的子类(java.lang.Enum 是一个抽象类)。枚举类型符合通用模式 Class Enum
package com.xxx.test;
public enum EnumTest {
MON, TUE, WED, THU, FRI, SAT, SUN;
}
// 上面这段代码实际上调用了7次 Enum(String name, int ordinal):
new Enum<EnumTest>("MON",0);
new Enum<EnumTest>("TUE",1);
new Enum<EnumTest>("WED",2);
...
5.静态导入(static import)
静态导入使代码更易读。通常,你要使用定义在另一个类中的常量(constants)时,需要使用静态导入来导入这个类或者常量。
// 静态导入枚举MON
import static com.xxx.test.EnumTest.MON;
// 此处可以直接使用枚举
switch (MON) {
case MON:
break;
case TUE:
break;
default:
break;
}
6.元数据(metadata)
元数据是关于数据的数据。在编程语言上下文中,元数据是添加到程序元素如方法、字段、类和包上的额外信息,对数据进行说明描述的数据;元数据特征志于使开发者们借助厂商提供的工具可以进行更简易的开发。
注解Annotation就是Java平台的元数据,是 J2SE5.0新增加的功能,该机制允许在Java 代码中添加自定义注释,并允许通过反射(reflection),以编程方式访问元数据注释。通过提供为程序元素(类、方法等)附加额外数据的标准方法,元数据功能具有简化和改进许多应用程序开发领域的潜在能力,其中包括配置管理、框架实现和代码生成。
在程序开发中,我们常用的注解有@Service、@Override、@Autowired、@Controller…
// 注解
public @interface MyAnnotation {
// 定义公共的final静态属性
int age = 24;
// 定义公共的抽象方法
String name();
}
7.线程池
有关Java5线程新特征的内容全部在java.util.concurrent下面,里面包含数目众多的接口和类。
java.uitl.concurrent.ThreadPoolExecutor类是线程池中最核心的一个类,因此如果要透彻地了解Java中的线程池,必须先了解这个类。下面我们来看一下ThreadPoolExecutor类的具体实现源码。
// 在ThreadPoolExecutor类中提供了四个构造方法:
public class ThreadPoolExecutor extends AbstractExecutorService {
.....
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue);
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory);
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler);
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler);
...
}
从上面的代码可以得知,ThreadPoolExecutor继承了AbstractExecutorService类,并提供了四个构造器,事实上,通过观察每个构造器的源码具体实现,发现前面三个构造器都是调用的第四个构造器进行的初始化工作。
下面解释下一下构造器中各个参数的含义:
* corePoolSize:核心池的大小,这个参数跟后面讲述的线程池的实现原理有非常大的关系。在创建了线程池后,默认情况下,线程池中并没有任何线程,而是等待有任务到来才创建线程去执行任务,除非调用了prestartAllCoreThreads()或者prestartCoreThread()方法,从这2个方法的名字就可以看出,是预创建线程的意思,即在没有任务到来之前就创建corePoolSize个线程或者一个线程。默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;
* maximumPoolSize:线程池最大线程数,这个参数也是一个非常重要的参数,它表示在线程池中最多能创建多少个线程;
* keepAliveTime:表示线程没有任务执行时最多保持多久时间会终止。默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,直到线程池中的线程数不大于corePoolSize,即当线程池中的线程数大于corePoolSize时,如果一个线程空闲的时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。但是如果调用了allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用,直到线程池中的线程数为0;
* unit:参数keepAliveTime的时间单位,有7种取值,在TimeUnit类中有7种静态属性:
TimeUnit.DAYS; // 天
TimeUnit.HOURS; // 小时
TimeUnit.MINUTES; // 分钟
TimeUnit.SECONDS; // 秒
TimeUnit.MILLISECONDS; // 毫秒
TimeUnit.MICROSECONDS; // 微妙
TimeUnit.NANOSECONDS; // 纳秒
* workQueue:一个阻塞队列,用来存储等待执行的任务,这个参数的选择也很重要,会对线程池的运行过程产生重大影响,一般来说,这里的阻塞队列有以下几种选择:
ArrayBlockingQueue;
LinkedBlockingQueue;
SynchronousQueue;
ArrayBlockingQueue和PriorityBlockingQueue使用较少,一般使用LinkedBlockingQueue和Synchronous。线程池的排队策略与BlockingQueue有关。
* threadFactory:线程工厂,主要用来创建线程;
* handler:表示当拒绝处理任务时的策略,有以下四种取值:
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
8.Java Generics
对于一个Collection类库中的容器类实例,可将任意类型对象加入其中(都被当作Object实例看待);从容器中取出的对象也只是一个Object实例,需要将其强制转型为期待的类型,这种强制转型的运行时正确性由程序员自行保证。 JDK1.5中Collection类库的大部分类都被改进为Generic类。
对于程序中的使用,俺就举一个自己封装的栗子吧;在开发中,我们总会发现,自己重复性的调用一些功能一摸一样的mapper和service方法,比如,根据ID查询当前对象实体、根据ID删除当前对象、分页查询等…;这时,就轮到我们的Generics泛型登场了。
package com.xxx.common.entity;
public abstract class BaseEntity extends Entity {
private static final long serialVersionUID = xxxL;
protected String orderBy;
private String version = "1.0.0";
}
package com.xxx.common.dao;
import com.github.pagehelper.Page;
import com.xxx.common.entity.BaseEntity;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
public interface BaseMapper<T extends BaseEntity, ID extends Serializable> {
int createEntity(T var1);
int updateEntity(T var1);
int deleteById(ID var1);
T queryById(ID var1);
List<T> queryListByEntity(T var1);
Page<T> pageQueryEntity(T var1);
long pageQueryEntityCount(T var1);
}
到这里JDK5中几个比较常用的新特性就讲完了,感谢网络上的大神们,站在巨人肩膀上的孩子总归会看得更远,走得更远。
PS:接下来下一篇应该看JDK6的新特性了,期待ing。
扫描下面二维码,关注我的公众号哦!!!