java 枚举_Java新特性之枚举、注解、lambda表达式

导语: Java语言自诞生起,经历了两次较大的革新:第一次是在2004年,Java5引入了枚举类型、注解和泛型;第二次是在2014年,Java8引入了lambda表达式。本文就重点介绍一下枚举、注解和lambda表达式。

枚举

定义枚举类型

Java5使用关键字enum来表示枚举类型。定义一个枚举很简单,如下所示:

public enum Season{SPRING,SUMMER,AUTUMN,WINTER;}

上述代码创建了一个名为Season的枚举类型,它的四个成员分别为:SPRING,SUMMER,AUTUMN,WINTER。枚举类型的实例都是常量,故按照Java命名规则,其成员都应该大写。

创建枚举实例

Season season=Season.SPRING;

上述代码创建了一个枚举的引用,并将Season中的SPRING赋给该实例。

枚举常用方法

values()方法用于返回在枚举中按照声明顺序产生的常量值组成的数组。
ordinal()方法返回某个枚举常量的索引(从0开始)。

案例:

//values()是枚举的数组(按照枚举中定义的顺序构成的数组) for(Season s:Season.values()){  //ordinal()是当前枚举成员的下标(索引) System.out.println(s.ordinal()+":"+s);  }

为了加深对枚举的熟悉程度,这里写一个小练习,用enum来模拟交通信号灯。
代码如下:

public enum TrafficLight { RED,GREEN,YELLOW;}public class TestLight { private TrafficLight light=TrafficLight.RED; public void change(){ switch(light){ case RED: //对于枚举,在case中不能写成TrafficLight.RED,只能写RED this.light=TrafficLight.GREEN; break; case GREEN: this.light= TrafficLight.YELLOW; break; case YELLOW: this.light=TrafficLight.RED; break; default: break; } } @Test public void test(){ int i; for(i=0;i<10;++i){ System.out.println(this.light); change(); } }}

注意: 在case中,枚举成员不能写成Season.RED,必须写成RED。

enum构造方法

枚举也可以有构造方法,这样在定义枚举的成员变量的时候,就可以用构造方法来进行初始化。注意:

  1. 枚举的构造方法只能用private来修饰,否则报错。
  2. 枚举的常量必须在最前面定义,并以;隔开。

在enum中定义构造方法和普通方法:

public enum Orientation { NORTH("北京"),SOUTH("南京"),WEST("西藏"),EAST("上海"); private String city; private Orientation(String city){ // 枚举中的构造方法必须是private修饰,否则报错 this.city=city; } public String getCity() { return city; }}@Test public void test2(){ Orientation o1=Orientation.NORTH; Orientation o2=Orientation.SOUTH; Orientation o3=Orientation.WEST; Orientation o4=Orientation.EAST; System.out.println(o1.getCity()); System.out.println(o2.getCity()); System.out.println(o3.getCity()); System.out.println(o4.getCity()); }

EnumMap的使用

EnumMap是一种特殊的Map,它要求所有的键都必须来自同一个枚举。
请看EnumMap使用的案例:

//EnumMap使用 @SuppressWarnings({"unchecked","unused"}) @Test public void test3(){ //创建的EnumMap实例的键为Orientation枚举类型,值为String类型,参数为键类型的Class对象 EnumMap enumMap=new EnumMap(Orientation.class); enumMap.put(Orientation.NORTH,"beijing"); enumMap.put(Orientation.SOUTH,"nanjing"); enumMap.put(Orientation.WEST,"xizang"); enumMap.put(Orientation.EAST,"shanghai"); for(Orientation o:Orientation.values()){ System.out.println(enumMap.get(o)); } System.out.println(); for(String str:enumMap.values()){ System.out.println(str); } }

注解

注解(Annotation,又称元数据),它是在Java5引入的重要概念。注解是写在代码里的特殊标记,它以标准化和结构化的方式,采用能被编译器检查、验证的格式存储有关程序的额外信息。

注解的分类

按照生成方式和功能的不同,Java的注解可以分为三大类:

  • 内置注解
  • 自定义注解
  • 元注解

内置注解

内置注解就是Java内部已经写好的注解,程序员可以直接在代码中使用。
Java5预定义了3种标准注解,具体如下:
@Override
该注解表示当前方法是重写的父类中的方法,如果方法名写错了或者返回类型等错误,那么编译器就会报错。
例如,下面的代码中:

public class Father { public void fun1(){ System.out.println("this is father's fun1()"); }}public class Son extends Father { @Override public void fun2(){ //此处会报错,因为方法fun2()不是重写的父类中的方法,要把fun2()改成fun1() }}

报错的截图如下:

1c66370005c7c76a28aaa2611d90d31a.png

@Deprecated
该注解表示某个类或方法已经过时,当使用已经过时的类或方法时,编译器会发出警告(注意: 是警告,不会报错)。过时的意思是该类或方法已经不合时宜,已经不建议使用,已经有新的类或方法取代它们了。

public class Father { @Deprecated public void fun2(){ System.out.println("fun2方法已经过时!"); } public static void main(String[] args) { Father father=new Father(); father.fun2(); //使用fun2方法,会在fun2上画删除线 }}

上述代码中,在fun2方法上加了@Deprecated注解,这表示fun2方法已经过时,不建议使用,所以在使用fun2方法时,会出现删除线的标志,具体截图如下:

3c80030c1ad1fb456339ba243270c042.png

SuppressWarnings

该注解用于关闭指定的编译器警告信息。例如:

List list=new ArrayList();

这句代码没有写泛型,那么就会出现警告信息。可以使用@SuppressWarnings(“unchecked”)注解来消除警告信息。

@SuppressWarnings注解里有一个名为value的String类型的数组,该数组用于接收像unchecked这类关键字,故注解@SuppressWarnings()里面参数的完整写法为@SuppressWarnings(value={“xxx”,“xxx”}),也可以简写为@SuppressWarnings({“xxx”,“xxx”})。当只有一个参数时,可以写成@SuppressWarnings(“xxx”)

常用@SuppressWarnings("…")关键字举例

unchecked 消除没有进行类型检查操作的警告。

unused 消除程序元素没有被使用的警告。

自定义注解

自定义注解就是程序员自己定义的注解。

自定义注解的写法

public @interface MyAnnotation{......}

注意:

在自定义注解里写成员变量,要接括号,例如:public int id();

程序员自己定义一个接口继承Annotation是不会被编译器当做注解的,所以要想自定义注解只能写成@interface xxx{}

@interface xxx,这样写之后编译器会自动继承Annotation接口。

下面写一个完整的自定义注解,代码如下:

public @interface MyAnnotation { public int id(); //name有一个默认值,如果在使用该注解时没有给name赋值,那么就会使用默认值 public String name() default "xurenyi";}

元注解

元注解就是给注解本身进行的注解。Java8在java.lang.Annotation包下提供了6个元注解:

@Target

该注解表示被修饰的注解能用于哪些元素类型。它有一个参数ElementType用于表示适用的元素类型,其值有CONSTRUCTOR(构造函数)、METHOD(方法)、PACKAGE(包)、PRAMETER(参数)、TYPE(类、接口、注解类型、枚举)、FIELD(成员变量)、LOCAL_VARIABLE(局部变量)、ANNOTATION_TYPE(标准注解)。

@Target注解中也有一个名为value的ElementType类型的数组,故参数的写法同@SuppressWarnings注解。

该注解用法如下:

@Target({ElementType.METHOD,ElementType.CONSTRUCTOR,ElementType.PARAMETER,ElementType.TYPE,ElementType.PACKAGE})public @interface MyAnnotation { public int id(); //name有一个默认值,如果在使用该注解时没有给name赋值,那么就会使用默认值 public String name() default "xurenyi";}

@Retention

表示被修饰注解的保存级别。参数RetentionPolicy表示保存级别。RetentionPolicy的取值有:SOURCE(只保留在源代码中,编译时直接丢弃)、 CLASS(保留在class文件中,但运行时jvm不能获取注解信息。)、RUNTIME(保留在class文件中,并且运行时jvm可以获取注解信息)。

该注解的用法如下:

@Retention(RetentionPolicy.RUNTIME) //保存级别public @interface MyAnnotation { public int id(); //name有一个默认值,如果在使用该注解时没有给name赋值,那么就会使用默认值 public String name() default "xurenyi";}

@Documented

指定被修饰的注解将被javadoc或其他类似工具提取成文档。

@Inherited

表示被修饰的注解具有继承性。也就是,加入某个类被@XXX注解修饰了,那么当有子类继承该类时,子类也自动会被@XXX注解修饰。

@Repeatable

这是Java8新增的重复注解。

Type Annotation

类型注解,是Java8新增的元注解,可以用在任何用到类型的地方。

在代码中,我们可以使用反射来读取注解信息,案例如下:

public @interface MyAnnotation { public int id(); //name有一个默认值,如果在使用该注解时没有给name赋值,那么就会使用默认值 public String name() default "xurenyi";}public class TestEnumAnnotation { public static void main(String[] args) throws NoSuchMethodException { TestEnumAnnotation ea=new TestEnumAnnotation(); // 获得TestEnumAnnotation的Class类对象 //Class clazz= (Class) ea.getClass(); Class clazz=TestEnumAnnotation.class; // 获得testMyAnnotation()方法 Method method=clazz.getMethod("testMyAnnotation"); // 如果注解MyAnnotation存在于方法method中 if(method.isAnnotationPresent(MyAnnotation.class)){ // 获取方法中的注解 MyAnnotation annotation = method.getAnnotation(MyAnnotation.class); // 获取注解中的变量 int id=annotation.id(); String name=annotation.name(); System.out.println(id+":"+name); } }//测试自定义注解 @MyAnnotation(id=25,name="张三李四王五") public void testMyAnnotation(){ System.out.println("这是在测试自定义注解。。。。"); }}

lambda表达式

lambda表达式简介

lambda是Java8的新特色,它的写法为:参数列表->lambda表达体 箭头的左边是参数列表,如果没有参数,可以直接写一对括号;箭头右边是lambda表达体,可以理解为lambda的具体实现。

简单lambda表达式举例

()->23.6这个lambda表达式会返回23.6,相当于double myVal(){return 23.6;};这个方法。

当lambda需要参数时,那么就需要在左侧的参数列表中指定。例如,(value)->(value%2)==0,这个lambda表达式的意思为:当value是偶数时,则返回true,否则返回false。

函数式接口

函数式接口是只有一个抽象方法的接口。例如:

// 函数式接口:只有一个(且只能有一个)抽象方法的接口@FunctionalInterface //指定该接口是函数式接口public interface MyVal { double getVal();}

接口MyVal就是一个函数式接口,因为它只有一个抽象方法。代码中的@FunctionalInterface注解用于指定某个接口是函数式接口。

lambda表达式与函数式接口的应用

@Test public void test1(){ // lambda表达式在函数式接口中的应用(1) MyVal myVal=()->24.6; System.out.println(myVal.getVal()); }

当把lambda表达式()->24.6赋给接口myVal引用后,该lambda表达式会自动创建一个实现了接口抽象方法的类的实例。接口中的抽象方法由lambda表达式来实现。

lambda表达式与匿名内部类

lambda表达式是匿名内部类的一种简化。

什么是匿名内部类

匿名内部类,顾名思义,就是没有名字的内部类。接下来,结合一段代码来讲解一下什么是匿名内部类:

public class AnonymousTest {public void fun1(){ System.out.println("this is anonymous's fun1()"); }  // 匿名内部类介绍 @SuppressWarnings("unused") @Test public void test2(){ AnonymousTest anonymousTest=new AnonymousTest(){ @Override public void fun1(){ System.out.println("this is son's fun1()"); } public void fun2(){ System.out.println("........."); } }; anonymousTest.fun1(); }}

上述代码中的AnonymousTest anonymousTest=new AnonymousTest(){......}代码片段就产生了一个匿名内部类。{......}中就是匿名内部类的具体代码,而anonymousTest就是该匿名内部类的父类。

lambda表达式与匿名内部类的应用

分别使用匿名内部类和lambda表达式来实现同一个功能(字符串逆序输出)

public class AnonymousTest { public static void main(String[] args) { AnonymousTest anonymousTest=new AnonymousTest(); // 使用匿名内部类来实现 anonymousTest.display("qishiyi", new MyStringFunction(){ public String reverse(String str){ int i; String result=""; for(i=str.length()-1;i>=0;--i){ result=result+str.charAt(i); } return result; } }); }  public void display(String str,MyStringFunction myStringFunction){ System.out.println(myStringFunction.reverse(str)); }}
@Test public void test1(){ AnonymousTest anonymousTest=new AnonymousTest(); // 使用lambda表达式来实现 anonymousTest.display("xurenyi",(str)->{ int i; String result=""; for(i=str.length()-1;i>=0;--i){ result=result+str.charAt(i); } return result; }); }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值