枚举类特点
- 枚举类很安全,不能被实例化对象,甚至用反射都无法创建对象;
- 可以使用name()和oridnal()方法来返回枚举对象的实例名称和序数(从0开始);
- 所有的枚举类都有静态方法:values可以获取当前枚举类中的所有实例;
- 所有的枚举类都有静态方法:valuesOf可以将String类型的字符串转换为枚举类型的对象;
- 枚举常量必须最先声明,并且常量之间需要用逗号隔开,最后一个常量用分号;
- 枚举常量之后若使用{},则表示当前枚举类的匿名内部类;
- 使用switch操作枚举。
public class EnumDemo {
public static void main(String[] args) {
//用Integer表示星期几业务含义不明确
Employee e = new Employee();
e.setRestDay(WeekDay.SUN);
if (e.getRestDay() == WeekDay.SAT || e.getRestDay() == WeekDay.SUN)
System.out.println("周末休息");
else System.out.println("周一到周五休息");
System.out.println("-------------------------");
System.out.println(WeekDay.SAT.name());
System.out.println(WeekDay.SAT.ordinal());
System.out.println("-------------------------");
WeekDay[] days = WeekDay.values();
for (WeekDay day : days){
System.out.println(day);
}
System.out.println("-------------------------");
WeekDay day = WeekDay.valueOf("SUN");
System.out.println(day);
}
}
在枚举类中,底层操作就是创建一个一个的对象的实例:
public class WeekDay2 {
public static final WeekDay2 MON= new WeekDay2();//Monday
public static final WeekDay2 TUE= new WeekDay2();//Tuesday
public static final WeekDay2 WED= new WeekDay2();//Wednesday
public static final WeekDay2 THU= new WeekDay2();//Thursday
public static final WeekDay2 FRI= new WeekDay2();//Friday
public static final WeekDay2 SAT= new WeekDay2();//Saturday
public static final WeekDay2 SUN= new WeekDay2();//Sunday
//防止创建新的对象
private WeekDay2(){}//实际上枚举类Enum中并没有无参数构造器,
//只有一个带有String和int的构造器,分别表示枚举对象的名称和序数
}
Lambda表达式
基本语法:参数列表->表达式
- 参数列表
- 如果没有参数,直接用()表示,()不能省略;
- 如果只有一个参数,并且参数写了类型,参数外面一定要加();
- 如果只有一个参数,并且参数不写类型,这个参数外面可以不用加();
- 如果有两个及以上的参数,不管书否写参数类型,都必须加();
- 如果参数要加修饰符或者标签,参数一定要加上完整的类型;
public class LambdaTest1 { class User { public String name; public int score; @Override public String toString() { return "User [name=" + name + ", score=" + score + "]"; } public User(String name, int score) { this.name = name; this.score = score; } } @Test public void testOldUse1() { User[] us = new User[] { new User("张三", 90), new User("李四", 95), new User("王五", 98) }; //sort Arrays.sort(us, new Comparator<User>() { @Override public int compare(User o1, User o2) { return Integer.compare(o1.score, o2.score); } }); System.out.println(Arrays.toString(us)); } @Test public void testNewUse1() { User[] us = new User[] { new User("张三", 90), new User("李四", 95), new User("王五", 98) }; //sort //Lambda表达式 Arrays.sort(us, (User o1, User o2) -> { return Integer.compare(o1.score, o2.score); }); System.out.println(Arrays.toString(us)); } @Test public void testNewUse2() { User[] us = new User[] { new User("张三", 90), new User("李四", 95), new User("王五", 98) }; //sort //Lambda表达式 Arrays.sort(us, (User o1, User o2) -> Integer.compare(o1.score, o2.score)); System.out.println(Arrays.toString(us)); } @Test public void testNewUse3() { User[] us = new User[] { new User("张三", 90), new User("李四", 95), new User("王五", 98) }; //sort //Lambda表达式 Arrays.sort(us, (o1, o2) -> Integer.compare(o1.score, o2.score)); System.out.println(Arrays.toString(us)); } @Test public void testOldUse2() { new Thread(new Runnable() { @Override public void run() { System.out.println("Hello Lambda"); } }).start(); } @Test public void testOldUse3() { new Thread(() -> System.out.println("Hello Lambda")).start(); } @Test public void testOldUse4() { Runnable run = new Runnable() { @Override public void run() { System.out.println("Hello Lambda!"); } }; new Thread(run).start(); } @Test public void testNewUse5() { Runnable run = () -> System.out.println("Hello Lambda!"); new Thread(run).start(); new Thread(run).start(); } }
- 表达式
- 如果表达式只有一行,那么可以直接写,不需要加{};
- 如果表达式有多行,需要用代码块{}表示;
- 如果表达式是代码块,并且需要返回值,那么在代码块中必须返回一个返回值;
- 如果只有单行的情况下,并且方法需要返回值,这时不能有return,编译器会自动帮我们推导return;
public class LambdaTest2 {
@Test
public void test1() {
new Thread(() -> System.out.println("Hello Lambda")).start();
}
public static void main(String[] args) {
Frame f = new Frame();
f.setSize(100, 100);
Button btn = new Button("lambda");
btn.addActionListener(e -> System.out.println("Lambda"));
f.add(btn);
f.setVisible(true);
}
@Test
public void test2() {
String[] strs = new String[] { "Lambdalalala", "Cherry", "Bubbui",
"BBC" };
Arrays.sort(strs, (final String s1, final String s2) -> {
if (s1 != null && s2 != null)
return Integer.compare(s1.length(), s2.length());
return -1;
});
System.out.println(Arrays.toString(strs));
}
}
lambda表达式中的变量
- 参数;
- 局部变量;
- 自由变量(既不是参数也不是局部变量)
结论:lambda表达式中的自由变量会被保存,无论什么时候执行lambda表达式,都可以直接使用。
- 自由变量在lambda表达式中不能被修改(在底层已经被用final修饰);(操作自由变量的代码块,称为闭包)
- 参数和局部变量的使用方式和普通的变量使用方式相同;
- lambda表达式中的this指向创建lambda表达式的方法中的this;
public class LambdaTest3 {
/**
* lambda表达式中this指向创建lambda表达式的方法中的this
* @param content
* @param times
*/
public void repeatPrint(String content, int times) {
System.out.println(this);//com.Bryan._06_lambda.LambdaTest3@514713
Runnable run = ()->{
System.out.println(this);//com.Bryan._06_lambda.LambdaTest3@514713
};
new Thread(run).start();
}
public void repeatPrint2(String content, int times) {
Runnable run = new Runnable(){
@Override
public void run() {
System.out.println(this);//com.Bryan._06_lambda.LambdaTest3$1@145df5f
}
};
new Thread(run).start();
}
@Test
public void testVar(){
this.repeatPrint("Hello", 5);
}
}
函数式接口
- 我们能够写lambda表达式的地方:一个接口,且里面只有一个抽象方法;
- 在Java中,把只有一个抽象方法的接口称为函数式接口,如果一个接口是函数式接口,我们可以在接口上添加@functionalInterface标签,表明这是一个函数式接口;(检查,文档)
- 无论是否标识@functionalInterface,只要满足函数式接口的接口,Java都会识别为函数式接口;
- 简化函数式接口的使用是JAVA中提供lambda表达式唯一的作用;
- 可以用接口直接引用一个lambda表达式;
- 函数式接口里可以写Object对象中的方法;
- lambda表达式中的异常处理:lambda表达式中产生的异常要么直接在代码块中处理,要么在接口的方法声明抛出。
public class LambdaTest4{
public void wrapWork(IMyWork work){
System.out.println("Do some wrap work...");
try {
work.dowork();
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void test() throws Exception{
IMyWork work = () -> {
System.out.println("haha");
Thread.sleep(1000);
};
this.wrapWork(work);
}
}
@FunctionalInterface
public interface IMyWork {
void dowork() throws Exception;
boolean equals(Object o);
}
方法引用
- 类::静态方法
- 对象::方法
- 对象::静态方法
public class LambdaTest5 {
@Test
public void test1() {
Integer[] is = new Integer[]{2,2,8,4,1,4,7,3};
//Arrays.sort(is,(x,y) -> Integer.compare(x, y));
//也是lambda表达式,方法引用(类::静态方法)
Arrays.sort(is,Integer::compare);
System.out.println(Arrays.toString(is));
}
public int compare(int x,int y){
return Integer.compare(x, y);
}
@Test
public void test2(){
LambdaTest5 lt = new LambdaTest5();
Integer[] is = new Integer[]{2,2,8,4,1,4,7,3};
//方法引用(对象::方法)
//Arrays.sort(is,lt::compare);
//Arrays.sort(is,this::compare);
List<Integer> list =Arrays.asList(2,2,8,4,1,4,7,3);
//list.forEach(x->System.out.println(x));
list.forEach(System.out::println);
//System.out.println(Arrays.toString(is));
}
}
构造器引用(需要一个无参构造方法)
- 类::new
- 构造器引用对应的函数式接口里面的方法格式一定是:返回一个对象/方法没有参数
public class LambdaTest5 {
@Test
public void test1() {
Integer[] is = new Integer[] { 2, 2, 8, 4, 1, 4, 7, 3 };
//Arrays.sort(is,(x,y) -> Integer.compare(x, y));
//也是lambda表达式,方法引用(类::静态方法)
Arrays.sort(is, Integer::compare);
System.out.println(Arrays.toString(is));
}
public int compare(int x, int y) {
return Integer.compare(x, y);
}
@Test
public void test2() {
LambdaTest5 lt = new LambdaTest5();
Integer[] is = new Integer[] { 2, 2, 8, 4, 1, 4, 7, 3 };
//方法引用(对象::方法)
//Arrays.sort(is,lt::compare);
//Arrays.sort(is,this::compare);
List<Integer> list = Arrays.asList(2, 2, 8, 4, 1, 4, 7, 3);
//list.forEach(x->System.out.println(x));
list.forEach(System.out::println);
//System.out.println(Arrays.toString(is));
}
public <T> List<T> asList(IMyCreator<List<T>> creator, T... a) {
List<T> list = creator.create();
for (T t : a)
list.add(t);
return list;
}
@Test
public void test3() {
//构造方法引用
//类::new
//List<Integer> list = Arrays.asList(2, 2, 8, 4, 1, 4, 7, 3);
List<Integer> list = this.asList(() -> {return new ArrayList();} , 2, 2, 8, 4);
List<Integer> list2 = this.asList(ArrayList::new , 2, 2, 8, 4);
list.forEach(System.out::println);
System.out.println(list.getClass());
}
}
接口的默认方法
- 可以实现多继承;
- 解决冲突:
- 如果两个接口中有相同方法签名的默认方法,子类必须实现冲突的方法,指定使用某一个父接口中的默认实现;
- 如果父类里面有何接口中一个默认方法有相同的方法签名,那么使用父类里的方法;
- 永远不要期望用接口里面的默认方法来改变Object对象里面的方法;
- 接口里面可以直接写接口的静态方法了;
- 常见的一些模式被取代
- 工具类
- 适配器模式