`

effective java (六:枚举和注解)

    博客分类:
  • Java
 
阅读更多

枚举

 

什么时候需要使用枚举?

当程序中需要使用到一组常量(整型,字符串)时,就应该使用枚举对这些常量进行封装。

如,星期一到星期天、性别分男和女等

 

使用枚举可以带来哪些好处:

类型安全,防止传入错误的参数值

可读性好,比int值强

不易出错,比硬编码字符串到程序各个角落好

枚举实例可以具备行为,操作起来更加方便

 

使用枚举替换int常量和字符串常量

 

	public enum Sex {
		MALE, FEMALE;
	} 

 

用实例域替代枚举自身的序数

 

如果需要使用枚举常量的序数,最好自己定义,不要使用默认的ordinal实现

 

public enum Priority {
		STEP_A(0, "洗脸"), 
		STEP_B(1, "刷牙"), 
		STEP_C(2, "抽烟"), 
		STEP_D(2, "WC"), 
		STEP_E(3, "上班");
		
		private int ordinal;
		private String task;
		
		Priority(int ordinal, String task) {
			this.ordinal = ordinal;
			this.task = task;
		}
		
		public int getOridnal() {
			return this.ordinal;
		}
		
		@Override
		public String toString() {
			return this.ordinal + ": " + this.task;
		}
	}
	
	//test
	public static void main(String[] args) {
		for(Priority p : Priority.values()) {
			System.out.println(p);
		}
	}

  

 

EnumSet

通过集合接收几个枚举常量

 

package effective.chapter6;

import java.util.EnumSet;

public class Text {
	public enum Style {
		BOLD, ITALIC, UNDERLINE, STRIKETHROUGH;
	}
	
	public static void applyStyle(EnumSet<? extends Style> styles) {
		for(Style s : styles) {
			System.out.println("apply style: " + s);
		}
	}
	
	//test
	public static void main(String[] args) {
		Text.applyStyle(EnumSet.of(Style.BOLD, Style.STRIKETHROUGH));
	}
}

 

 

EnumMap

枚举类型作为Map的key进行使用

 

描述两个阶段映射到一个阶段过渡

package effective.chapter6;

import java.util.EnumMap;
import java.util.Map;

/**
 * 嵌套枚举定义
 */
public enum Phase {
	SOLID("固体"), LIQUID("液体"), GAS("汽体");
	
	private String status;
	
	Phase(String status) {
		this.status = status;
	}
	
	@Override
	public String toString() {
		return status;
	}
	
	//不同阶段转换的过程
	public enum Transition {
		MELT(SOLID, LIQUID), 
		FREEZE(LIQUID, SOLID), 
		BOIL(LIQUID, GAS);
		
		private Phase src;
		private Phase dst;
		Transition(Phase src, Phase dst) {
			this.src = src;
			this.dst = dst;
		}
		
		//key: 起始状态
		//value: [key:结束状态,value:转变过程]
		private static final Map<Phase, Map<Phase,Transition>> m = 
				new EnumMap<Phase, Map<Phase,Transition>>(Phase.class);
		
		static {
			for(Phase p : Phase.values())
				m.put(p, new EnumMap<Phase,Transition>(Phase.class));
			for(Transition trans : Transition.values())
				m.get(trans.src).put(trans.dst, trans);
		}
		
		public static Transition from(Phase src, Phase dst) {
			return m.get(src).get(dst);
		}
		
		@Override
		public String toString() {
			return this.src + "->" + this.dst;
		}
		
	}
}

 

public class TestNestEnum {
	public static void main(String[] args) {
		Transition trans = Phase.Transition.from(Phase.SOLID, Phase.LIQUID);
		System.out.println(trans);
	}
}

 

结果:固体->液体

 

通过接口扩展枚举的功能

 

public interface Operation {
	double aplly(double x, double y);
}

 

public enum BasicOperation implements Operation {
	PLUS("+"){
		@Override
		public double aplly(double x, double y) {
			return x + y;
		}
	},
	MINUS("-"){
		@Override
		public double aplly(double x, double y) {
			return x - y;
		}
	},
	TIMES("*"){
		@Override
		public double aplly(double x, double y) {
			return x * y;
		}
	},
	DIVIDE("/"){
		@Override
		public double aplly(double x, double y) {
			return x / y;
		}
	},
	EXP("^") {
		@Override
		public double aplly(double x, double y) {
			return Math.pow(x, y);
		}
	},
	REMAINDER("%"){
		@Override
		public double aplly(double x, double y) {
			return x % y;
		}
	};
	
	private final String symbol; 

	BasicOperation(String symbol) {
		this.symbol = symbol;
	}
	
	@Override
	public String toString(){
		return symbol;
	}

	@Override
	public double aplly(double x, double y) {
		throw new RuntimeException("You must implements method in each enum instance!");
	}
}

 

class TestEnumInterface {
	public static void main(String[] args) {
		double x = 2.17;
		double y = 3.02;
		//数组转换为集合
		testEnum(Arrays.asList(BasicOperation.values()), x, y);
	} 
	
	//泛型参数接收枚举集合
	public static void testEnum(Collection<? extends Operation> opSet, double x, double y) {
		for(Operation op : opSet)
			System.out.printf("%f %s %f = %f%n", x, op, y, op.aplly(x, y));
	}
}

 

结果:

2.170000 + 3.020000 = 5.190000
2.170000 - 3.020000 = -0.850000
2.170000 * 3.020000 = 6.553400
2.170000 / 3.020000 = 0.718543
2.170000 ^ 3.020000 = 10.377874
2.170000 % 3.020000 = 2.170000

 

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 

注解

 

标记注解

package effective.chapter6;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)//配置‘@AnnoTest’应该被保留到运行阶段,在运行阶段通过反射定位此注解
@Target(ElementType.METHOD)//配置‘@AnnoTest’可使用的目标:用在方法上,而不是用在字段或者类上
public @interface MyAnno {

}

 

package effective.chapter6;

/**
 * 将注解标注到方法上
 */
public class Sample {
	@MyAnno
	public static void m1() {}
	
	public static void m2() {}
	
	@MyAnno
	public static void m3() {
		throw new RuntimeException("Boommmm");
	}
	
	public static void m4() {}
	
	@MyAnno
	public void m5() {}
	
	public void m6() {}
	
	@MyAnno
	public static void m7() {
		throw new RuntimeException("Boommmm again");
	}
	
	public static void m8(){}
	
}

 

package effective.chapter6;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 读取注解,只处理那些标记了特定注解的方法
 * 在Sample类中使用@MyAnno注解对若干方法进行标记
 * 1.反射Sample类中的方法
 * 2.判断方法是否被@MyAnno标记了
 * 3.如果标记了,则以静态方法反射调用此方法
 * 4.统计被正确调用的静态方法个数,与出现异常的方法个数
 * 5.未标记@MyAnno注解的方法不会得到执行
 */
public class Test {
	public static void main(String[] args) throws Exception {
		int tests = 0;
		int passed = 0;
		
		Class<?> testClass = Class.forName("effective.chapter6.Sample");
		for(Method m : testClass.getDeclaredMethods()) {
			//判断方法上的注解是否为@MyAnno
			if(m.isAnnotationPresent(MyAnno.class)) {
				tests++;
				try{
					//反射调用静态方法
					m.invoke(null);
					passed++;
				} catch (InvocationTargetException wrappedExc) {
					Throwable exc = wrappedExc.getCause();
					System.out.println(m + "failed:" + exc);
				} catch (Exception e) {
					System.out.println("Invalid @MyAnno:" + m);
				}
			}
		}
		
		System.out.printf("passed: %d, failed %d%n", passed, tests - passed);
	}
}

 

注解中定义数组参数

package effective.chapter6;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//配置‘@AnnoTest’应该被保留到运行阶段,在运行阶段通过反射定位此注解
@Retention(RetentionPolicy.RUNTIME)
//配置‘@AnnoTest’可使用的目标:用在方法上,而不是用在字段或者类上
@Target(ElementType.METHOD)
public @interface MyAnno {
	Class<? extends Exception>[] values();//接收一组异常类
}


 

package effective.chapter6;

import java.util.ArrayList;
import java.util.List;

/**
 * 将注解标注到方法上
 * 给注解的数组参数添加配置
 */
public class Sample {
	
	@MyAnno(values = {IndexOutOfBoundsException.class, NullPointerException.class})
	public static void badMethod() {
		List<String> list = new ArrayList<String>();
		list.addAll(5,null);
	}
	
}

 

package effective.chapter6;

import java.lang.reflect.Method;

/**
 * 对抛出特定异常的方法进行测试
 */
public class Test {
	public static void main(String[] args) throws Exception {
		int tests = 0;
		int passed = 0;
		
		Class<?> testClass = Class.forName("effective.chapter6.Sample");
		for(Method m : testClass.getDeclaredMethods()) {
			//判断方法上的注解是否为@MyAnno
			if(m.isAnnotationPresent(MyAnno.class)) {
				tests++;
				try{
					//反射调用静态方法
					m.invoke(null);
					System.out.printf("Tests %s failed: no exception%n", m);
				} catch (Throwable wrappedExc) {
					Throwable excCause = wrappedExc.getCause();
					Class<? extends Exception>[] excTypes = m.getAnnotation(MyAnno.class).values();
					int oldPassed = passed;
					for(Class<? extends Exception> excType : excTypes) {
						if(excType.isInstance(excCause)) {
							passed++;
							break;
						}
					}
					if(passed == oldPassed)
						System.out.printf("Test %s failed: %s %n", m, excCause);
					else
						System.out.println("Test ok!");
				} 
			}
		}
		System.out.printf("passed: %d, failed %d%n", passed, tests - passed);
	}
}

 

 

建议:坚持使用@overrider注解,避免非法错误!

 

 

 

分享到:
评论

相关推荐

    2021年EFFECTIVEJAVA读书笔记.docx

    本文总结了Effective Java 中关于枚举与注解的知识点,涵盖了枚举类型的优点、使用指南、避免使用 int 常量、使用 EnumSet 和 EnumMap 等。 枚举类型的优点 枚举类型提供了编译时类型安全、自动命名空间隔离、可以...

    Effective Java第三版1

    《Effective Java》是Java编程领域的一本经典著作,由Joshua Bloch撰写,它提供了许多最佳实践和设计原则,帮助开发者写出更高效、更可维护的代码。第三版延续了这一传统,对Java语言的新特性进行了更新,并给出了...

    Effective-Java:Effective Java中文版第二版示例代码

    这些知识点都是基于《Effective Java》第二版中的主要观点,通过阅读和实践书中的示例代码,可以深入理解并应用到实际项目中,从而提升Java编程的技能水平。同时,书中还涵盖了其他很多话题,如序列化、注解、反射等...

    Effective Java.zip

    - 注解:解释注解的元数据功能,如何创建自定义注解以及处理注解的反射API。 5. **第7章 Lambda和Stream** - Lambda表达式:介绍Java 8引入的Lambda表达式,简化函数式编程。 - Stream API:讲解如何使用Stream...

    《Effective Java》读书分享.pptx

    其他知识点还包括泛型、枚举和注解、Lambda 和 Stream、方法、通用编程、异常、并发、序列化等。这些知识点都是 Java 编程语言的核心内容,了解和掌握这些知识点对于编写高质量的 Java 代码至关重要。 《Effective ...

    EffectiveJava:有效的 Java 示例

    《EffectiveJava》是Java开发领域的经典著作,由Joshua Bloch撰写,提供了许多关于如何编写高效、可维护和设计良好的Java代码的实用建议。这本书的第2版在原有的基础上进行了更新,以适应Java语言的新发展。现在,...

    effecctivejava 第三版中文

    《Effective Java》是Java编程领域的一本经典著作,由Joshua Bloch撰写,现在已经更新到第三版。这本书深入探讨了如何编写高效、可维护且设计良好的Java代码,是每一个Java开发者提升技能的重要参考资料。以下是对该...

    Effective-Java-2nd-Edition-(May-2008).zip_effective java

    3. **枚举代替常量类**:书中推荐使用枚举类型替代传统的公共静态final变量,因为枚举提供了更强的类型安全性和更丰富的功能,如枚举方法和枚举实例的集合操作。 4. **避免使用原始类型数组**: Bloch提倡使用泛型...

    effectiveJava的笔记

    《Effective Java》是Java开发领域的经典著作,由Joshua Bloch编写,旨在提供一系列实用的编程准则和最佳实践。这本书的第三版包含了大量更新,涵盖了Java语言和平台的新发展,如Java 8和Java 9的新特性。以下是对...

    Java-Effective:Java Effective 2nd Edition书中的源代码

    8. **枚举和注解**: - **使用枚举代替int常量**:枚举提供更多的功能,如方法、常量等。 - **注解的使用**:注解用于元数据,增强了代码的可读性和可维护性,例如`@Override`、`@Deprecated`。 9. **最后,性能...

    Effective Java 第三版

    这些规则和建议基于作者多年的经验,涵盖了广泛的主题,包括集合、泛型、枚举、注解、方法设计、并发编程等方面。 在描述中提到的EPUB是一种开放性的电子书标准格式,它支持多种功能,但这些功能在不同阅读设备和...

    Effective.Java_Java8_并发_java_effectivejava_

    目录:一、创建和销毁对象 (1 ~ 7)二、对于所有对象都通用的方法 (8 ~ 12)三、类和接口 (13 ~ 22)四、泛型 (23 ~ 29)五、枚举和注解 (30 ~ 37)六、方法 (38 ~ 44)七、通用程序设计 (45 ~ 56)八、异常 ...

    java四大名著pdf

    作者 Bruce Eckel 提倡使用面向对象的思维方式,书中涵盖了泛型、枚举、注解、Lambda表达式等现代Java特性,帮助读者理解并掌握高级编程技巧。 3. 《Effective Java》:由Joshua Bloch 编著,是Java程序员的必备...

    LF_EffectiveJava:买的书籍看完必须把原始码运行完,加上自己的理解注释

    在LF_EffectiveJava中,可以看到如何创建枚举类型,以及如何为枚举添加方法和实现接口。 2. **构造器与工厂方法**:书中提倡使用工厂方法来创建对象,因为它可以提供更好的封装和灵活性。项目中的代码可能包含了...

    最新的java程序员不可不学的java基础教程

    10. **枚举与注解**:枚举类型提供了一种安全的常量表示方式,而注解则为编译器和运行时提供元数据,这两者都极大地丰富了Java语言的表达能力。 在《Effective Java 第二版》这本书中,作者深入浅出地介绍了许多...

    effecive java 中文版 第二版

    通过以上对“Effective Java 中文版 第二版”的核心知识点的总结,我们可以看到这本书覆盖了Java编程语言的各个方面,包括面向对象设计原则、类与接口的设计、对象的创建与销毁、枚举类型与注解、泛型与集合框架以及...

    effectice java第二版

    4. **枚举和注解**:介绍了枚举类型在Java中的强大功能,如枚举常量、枚举方法、枚举开关语句等,并讲解了自定义注解的创建和使用,以及元注解的应用。 5. **方法**:提倡使用重载而非覆盖,解释了如何有效地使用...

    java初学者应该阅读的书籍

    ### 第二本书:《Effective Java》(《高效Java》) #### 知识点概述 - **编程规范**:推荐最佳实践,如使用final修饰不可变类。 - **设计模式**:单例模式、工厂模式等经典设计模式的应用。 - **泛型与注解**:...

Global site tag (gtag.js) - Google Analytics