java新特性
JDK1.5新特性
1. 泛型(Generics)
2. 静态导入:
格式: import static要导入的包名
作用:不用再写类.静态方法,直接写此类的静态方法即可,注意就是导入的包名必须精确到要导入某个类,而且必须是此类的静态方法,非静态不可以这样做
例如:
static importjava.lang.Math;
如:double a=abs(12.36);
int b=max(2,3);
上面两个都没写类,这是在jdk1.5以后是可取的
3. 增强for循环
增强for循环也叫for-each循环,简化了集合与数组的遍历
语法:for (类型名变量名:数组(集合)变量名){
code;
};
我们通过代码演示看看,增强for循环在集合和数组的用法:
importjava.util.ArrayList;
importjava.util.Iterator;
publicclass SuperFor {
public static void main(String[] args){
arr_1();
arr_2();
list();
}
/*
*一维数组遍历
*/
public static void arr_1() {
int[] arr=newint[]{1,2,3,4,5};
//旧式遍历
for (inti=0;i<arr.length;i++){
System.out.println(arr[i]);
}
System.out.println("-----------------");
//新式遍历,增强for循环
for (int elements:arr){
System.out.println(elements);
}
}
/*
* 二维数组遍历
*/
public static void arr_2(){
int[][] arr={{1,2,3},{2,3,4},{4,5,6}};
for (int[] i:arr){
for (int arrs:i){
System.out.println(arrs);
}
}
}
/*
* 集合遍历,三种方式
*/
public static void list(){
ArrayList<String>list=new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
//旧式遍历1
for (Iterator<String>it=list.iterator();it.hasNext();){
System.out.println(it.next());
}
System.out.println("-----------------");
//旧式遍历2
for (inti=0;i<list.size();i++){
System.out.println(list.get(i));
}
System.out.println("-----------------");
//新式遍历,增强for循环
for (String lists:list){
System.out.println(lists);
}
}
}
注意:当增强for循环遍历集合和数组时,如果需要访问集合或数组的下标,那么最好使用旧式的方式来实现循环或遍历,而不要使用增强的for循环,因为它丢失了下标信息。
4. 可变参数:
可变参数使程序员可以声明一个接受可变参数目参数的方法。
格式:声明方法(类型… 参数名);
比如int…等价于int[],可变参数不仅可以传类型参数,也可传一个数组。
代码演示如下:
public class CanChange {
public static void main(String[]args) {
sum_1(1,2,3,4);
sum_2("可变参数",1,2,3,4);
}
public static void sum_1(int... i)
{
for (int a:i){
System.out.println(a);
}
}
public static void sum_2(String str,int... i)
{
for (int a:i){
System.out.println(str+a);
}
}
}
所以可变参数本质上就是一个数组某个声明了可变参数的方法来说,我们既可以传递离散的值,也可以传递数组对象。但如果将方法中的参数定义为数组,那么只能传递数组对象而不能传递离散的值
注意:可变参数必须要作为方法参数的最后一个参数,即一个方法不可能具有两个或两个以上的可变参数。
5. 自动装箱和拆箱(Autoboxing/unboxing)
自动装箱:基本类型自动转为包装类(如:int->>Interger)
自动拆箱:包装类自动转为基本类型(如:iInterger->>int)
我们通过以下代码,可以看出自动装箱和拆箱的基本应用
public classBoxTest {
public static void main(String[] args) {
Integer a=100;
int b=100;
if (a==b){
System.out.println("a=b");
}else {
System.out.println("a!=b");
}
}
}
注意:当我们把a和b的值改为200,会打印a!=b;原因在于:Interger类有一个缓存,它会缓存介于-128~127之间的整数。而这个范围是byte类型范围,所以大于这个范围,等于byte新创了个对象,两个对象的地址是不一样的,所以打印a!=b;
枚举(Enumeration)
枚举基本概念:
jdk1.5引入了一个全新类型的“类“-枚举类型,引入了一个新关键字enum,被关键字修饰的名字就是枚举类型
格式如下:
public enum Color
{
Red, White, Blue
}
使用方法是:ColormyColor =Color.Red;
枚举的两个方法:
a) 类型数组[] values():获取枚举里的值
b) valueOf(String str):将一个字符串转化为对应的枚举类型的
我们来看看枚举的基本代码演示:
public enumColor {
White,Red,Blue;
}
public class EnumDemo {
public static void main(String[] args) {
Color c = Color.Red;
System.out.println(c);
System.out.println("--------------");
/*
* 遍历枚举里的每个值
*/
for (Color co:Color.values()){
System.out.println(co);
}
}
}
枚举的在switch语句的应用:
public enum OpConstant {
TURN_RIGHT,TURN_LEFT,SHOOT
}
public class OpConstantDemo {
public static void main(String[] args) {
demo(OpConstant.SHOOT);
}
public static void demo(OpConstant op){
switch (op) {
case TURN_RIGHT:
System.out.println("向左转");
break;
case TURN_LEFT:
System.out.println("向右转");
break;
case SHOOT:
System.out.println("射击");
break;
default:
break;
}
}
}
注意:我们所定义的每个枚举类型都继承自java.lang.Enum类,枚举中的每个成员默认都是publicstatic final的修饰;而每个枚举的成员其实就是你定义的枚举类型的一个实例(Instance),换句话说,当定义了一个枚举类型后,在编译时刻就能确定该枚举类型有几个实例,分别是什么?在运行期间我们无法再使用该枚举类型创建新的实例了,这些实例在编译期间就已经完全确定下来了。
我们看看如下代码演示下
public enum Coin {
//由于构造方法是带参数的,所以声明的时候就必须传个String参数
peen("hello"),nickel("world"),dime("welcome"),quarter("haha");
private String value;
public String getValue(){
return value;
}
//类似类的构造方法
Coin(String value){
this.value=value;
}
public static void main(String[] args) {
//通过其中的一个成员变量,获得其一的对象
Coin co=Coin.quarter;
//获得此对象的值
System.out.println(co.getValue());
}
}
小应用:用枚举来实现访问控制,只能让管理员进入
public class AccessControl {
public static void main(String[] args) {
Role r=Role.valueOf("ADMIN");
System.out.println(accessControl(r));
}
public static boolean accessControl(Role r) {
if (r == Role.ADMIN) {
return true;
} else if (r == Role.TEACHER) {
return false;
} else {
return false;
}
}
}
enum Role {
ADMIN, TEACHER, STUDENT
}
枚举集合
EnumSet是集合集成枚举的一个类,这个类有一些常用的方法:
a) abstract Iterator<E> iterator() : 返回的迭代器按其自然顺序 遍历这些元素
b) static <E extends Enum<E>>EnumSet of(E e,E…e): 创建一个最初包含指定元素的枚举 set。
c) static <E extends Enum<E>>EnumSet complementOf(EnumSet<E> s):创建一个其元素类型与指定枚举 set 相同的枚举 set,最初包含指定 set 中所不 包含的此类型的所有元素
d) static <E extends Enum<E>>EnumSet noneOf(Class<E>elementType):创建一个具有指定元素类型的空枚举 set。
我们代码演示下遍历枚举集合的演示:
import java.util.EnumSet;
import java.util.Iterator;
enum FontEnum {
RED,YELLOW,BLUE,BLACK
}
public class Test1 {
public static void main(String[] args) {
EnumSet<FontEnum> set=EnumSet.of(FontEnum.YELLOW, FontEnum.BLACK);
ergodic(set);
System.out.println("-------------");
System.out.println(EnumSet.complementOf(set));
}
public static void ergodic(EnumSet<FontEnum> set) {
for (Iterator<FontEnum> it = set.iterator();it.hasNext();) {
System.out.println(it.next());
}
}
/*
这里面是noneof方法使用
public static void main(String[] args) {
EnumSet<FontEnum> set=EnumSet.noneOf(FontEnum.class);
set.add(FontEnum.BLUE);
set.add(FontEnum.YELLOW);
ergodic(set);
}
*/
}
EnumMap也是枚举的一个典型的类:它的常用方法:
a) 构造方法:EnumMap(Class<K> keyType):创建一个具有指定键类型的空枚举映射。
b) V put(K key, V value):将指定值与此映射中指定键关联
c) V get(Object key):返回指定键所映射的值,如果此映射不包含此键的映射关系,则返回 null。
我们基本演示下EnumMap的用法:
import java.util.EnumMap;
import java.util.Map;
public class MapEnum {
publicstatic void main(String[] args) {
Map<Action,String>map=new EnumMap<Action,String>(Action.class);
map.put(Action.TURN_LEFT,"向右转");
map.put(Action.SHOOT,"射击");
map.put(Action.TURN_RIGHT,"向左转");
for(Action actions:Action.values()){
System.out.println(map.get(actions));
}
}
}
enum Action{
TURN_RIGHT,TURN_LEFT,SHOOT
}
注解(Annotation)
每一个注解都是一个类,使用每一个注解类都是创建一个实例,注解相当于一种标记。有什么标记,程序就做什么。
四个基本注解
@Override:用来指定方法重载的,它可以强制一个子类必须覆盖父类的方法
@Deprecated:它用于表示程序的类,方法等已过时,编译时会发生警告
@SupperessWarnning:取消指定的编译器警告
@SafeVarags:Java7新增注解,即堆污染(Heap pollution),即把一个不带泛型的变量赋给带泛型的变量就会发生污染。
元注解(Meta Annotation)
元注解都是修饰其他注解的定义
java中也提供了四种元注解
@Retention:指定的被修饰的Annotation可以保留多少时间
value值:
a) RetentionPolicy.Class:保留在class文件中,运行java时,不再保留,这是默认值
b) RetentionPolicy.Runtime:保留在class文件中,一直保留到运行时
c) RetentionPolicy.Source:只保留在源文件中,编译器直接丢弃
@Target指定修饰程序的什么成分
value值:
a) ElementType. ANNOTATION_TYPE:只能修饰注释
b) ElementType. CONSTRUCTOR:只能修饰构造方法
c) ElementType. FIELD:只能修饰成员变量
d) ElementType. LOCAL_VARIABLE:只能修饰局部变量
e) ElementType. METHOD:只能修饰方法
f) ElementType. PACKAGE:只能修饰包
g) ElementType. PARAMETER:可以修饰参数
h) ElementType. TYPE:可以修饰类,接口
@Documented:将会被javadoc工具提取成文档
@Inherited:将会具有继承性
自定义注解
当我们自定义注解时,总共有三个步骤:
a) 注解类,形式如下
@interface A{}
b) 应用了注解类,形式如下:
@A
class B{}
c) 对应用了注解类的类进行反射操作的类,形式如下:
Class C{
B.class.isAnnotationPresent(A.class)
A a=B.class.getAnnotation(A.class)
}
我们还可以为注解增加各种属性,代码演示如下:
我们先自定义一个注解类
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotionDemo {
//我们自定义一个值,默认是blue
String color()default "blue";
//这是Annotation默认设的值
String value();
//自定义数组的值,并放入默认数组的值
int[] array()default {1,3,4};
//自定义注释值
MetaAnnotation annoAttriute()default @MetaAnnotation("ly");
}
public @interface MetaAnnotation {
String value();
}
应用注解类
public class AnnotationTest {
@SuppressWarnings(value="unchecked")
public static void main(String[] args) {
System.runFinalizersOnExit(true);
if (AnnotationTest.class.isAnnotationPresent(AnnotionDemo.class)){
AnnotionDemo anno=AnnotationTest.class.getAnnotation(AnnotionDemo.class);
//打印设定color的值
System.out.println(anno.color());
//打印设定value值
System.out.println(anno.value());
//打印数组的长度
System.out.println(anno.array().length);
//打印注释的注释的值
System.out.println(anno.annoAttriute().value());
}
}
}
JDK1.7新特性
1. 二进制字面量,
可以用二进制来表示整数(byte,short,int和long)它可以使代码更容易理解,语法也非常简单:
语法:
byte nByte = (byte)0b0001;
short nShort = (short)0B0010;
int nInt = 0b0011;
long nLong = 0b0100L;
2. 数字字面量可以出现下划线
对于一些比较大的数字,我们定义起来总是不方面,经常缺少或者增加位数,我们使用jdk7提供的下划线可以出现在数字字面量
语法:
int a = 10_0000_0000;
long b = 0xffff_ffff_ffff_ffffl;
byte c = 0b0001_1000;
注意:你只能将下划线置于数字之间
3. switch 语句可以用字符串了
以下代码演示:
public class SwitchDemo {
public staticvoid main(String[] args) {
String str = "秋天";
switch (str) {
case "春天":
System.out.println("春天");
break;
case "夏天":
System.out.println("夏天");
break;
case "秋天":
System.out.println("秋天");
break;
case "冬天":
System.out.println("冬天");
break;
}
}
}
4. 泛型实例的创建可以通过类型推断来简化
创建一个泛型实例,不需要再详细说明类型,只需用<>,编译器会自动帮你匹配
//例如
Map<String, List<String>> myMap =new HashMap<String, List<String>>();
//可以简化为
Map<String, List<String>> myMap =new HashMap<>();
5. try-with-resources 语句
jdk7提供了try-with-resources,可以自动关闭相关的资源(只要该资源实现了AutoCloseable接口,jdk7为绝大部分资源对象都实现了这个接口)
static String readFirstLineFromFile(String path) throwsIOException {
try (
BufferedReader br =
new BufferedReader(new FileReader(path))) {
return br.readLine();
}
}
try 语句块中还可以同时处理多个资源,可以跟普通的try语句一样catch异常,有finally语句块
try (
java.util.zip.ZipFile zf =
newjava.util.zip.ZipFile(zipFileName);
java.io.BufferedWriter writer =
java.nio.file.Files.newBufferedWriter(outputFilePath,charset)
) {
}catch(…){
}finally{
}
Catch多个Exception,rethrow exception 改进了类型检测
很多时候,我们捕获了多个异常,却做了相同的事情,比如记日志,包装成新的异常,然后rethrow。这
时,代码就不那么优雅了,例如
catch (IOException ex) {
logger.log(ex);
throw ex;
catch (SQLException ex) {
logger.log(ex);
throw ex;
}
Jdk7允许捕获多个异常
catch (IOException|SQLExceptionex) {
logger.log(ex);
throw ex;
}
注意,catch后面的异常参数是final的,不能重新再复制
Rethrow Exception更具包容性的类型检测
当你重新抛出多个异常时,不再需要详细定义异常类型了,编译器已经知道你具体抛出的是哪个异常了。你
只需在方法定义的时候声明需要抛出的异常即可
public void call() throwsReflectiveOperationException, IOException {
try {
callWithReflection(arg);
} catch (final Exception e) {
logger.trace("Exception in reflection", e);
throw e;
}
}