Lambda表达式 & 枚举
新特性1:Lambda表达式概述
- JDK1.8开始引入Lambda表达式,支持函数式编程。
- 函数式编程可以避免面向对象编程中的一些繁琐问题。
- Lambda表达式是双刃剑,简化代码但可能降低可读性。
写Lambda表达式的场景
- 必须有函数接口(只有一个抽象方法的接口)。
- 依赖于类型推断机制,编译器可以根据上下文推断参数类型。
Lambda表达式的优点
- 匿名函数,可以传递代码。
- 代码更简洁、灵活。
- 提升了Java的语言表达能力。
Lambda基本语法
- 使用
->
操作符,分为参数列表和Lambda体。 - 参数列表对应接口中的形参,Lambda体对应方法体。
Lambda表达式分类
- 无参数,无返回值
- 有一个参数,无返回值
- 单个参数时,可以省略小括号
- 两个以上参数,有返回值,多条语句
- 单条语句时,可以省略
return
和大括号 - 参数类型可以省略,由编译器推断
Java内置函数式接口
- Predicate
:断言型接口, boolean test(T t);
传T类型的参数返回boolean值 - Function<T,R>:函数型接口,
R apply(T t);
传T类型的参数返回T类型的值 - Supplier
:供给型接口, T get();
无参返回T类型的值 - Consumer
:消费型接口, void accept(T t);
传T类型的参数不返回
Lambda用法再简洁之方法引用
- 对象引用:
对象引用::实例方法名
- 类:
类名::静态方法名
- 类:
类名::实例方法名
- 构造方法引用:
类名::new
- 数组引用:
元素类型[]::new
误区
- Lambda表达式不是匿名内部类,而是通过
invokedynamic
指令调用。
小结
- 优点:减少代码量,节省内存。
- 缺点:可读性差,不易调试。
新特性2 枚举
枚举概述
- 枚举类型用于管理有限常量数据。
- 提高代码可读性和简洁性。
JDK1.5之前使用枚举
- 创建枚举类的属性,必须是私有常量。
- 构造方法私有化。
- 提供公共静态方法获取枚举对象。
- 提供公共方法获取属性。
- 重写
toString()
方法。
JDK1.5之后使用枚举
- 枚举对象放在开头。
- 枚举类属性为私有常量。
- 构造方法私有化。
- 提供公共方法获取属性。
- 重写
toString()
方法。
枚举类实现接口
- 枚举可以单独实现接口。
lambda代码示例
断言型接口使用
public class test6 {private static final List<Staff> list = Arrays.asList(new Staff("李刚", 18, 35000),new Staff("钱志强", 13, 20000),new Staff("江川", 24, 50000),new Staff("祝帅", 16, 21000),new Staff("吴问强", 8, 8000));public static void main(String[] args) {//这里的s代表传入Predicate接口方法的参数,后面是s.getSalary()>10000的返回值panduan(list,s->s.getSalary()>10000);}public static void panduan(List<Staff> list,Predicate<Staff> predicate){ArrayList<Staff> list2 = new ArrayList<>();for (Staff s : list) {if(predicate.test(s)) {list2.add(s);}}for (Staff staff : list2) {System.out.println(staff);}}
}
函数型接口及构造方法简化实例
package com.shujia.day20;import java.util.function.Function;class test1{private String naem;public test1(String naem) {this.naem = naem;}public String getNaem() {return naem;}public void setNaem(String naem) {this.naem = naem;}@Overridepublic String toString() {return "test1{" +"naem='" + naem + '\'' +'}';}
}public class test5 {public static void main(String[] args) {show(s->new test1(s));//变量->new 类名(变量) 当变量一致时可以缩写成 类名::newshow(test1::new);}//函数型接口public static void show(Function<String,test1> function){System.out.println(function.apply("李刚"));}
}
供给型接口实例
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.function.Supplier;/*java内置函数式接口:供给型接口只有函数式接口【有且仅有一个抽象方法】才可以被@FunctionalInterface注解所修饰@FunctionalInterfacepublic interface Supplier<T> {T get();}*/
public class Demo {public static void main(String[] args) {//随机生成10个1-100的数据到集合返回List<Integer> list = getList(() -> new Random().nextInt(100) + 1);for (Integer i : list) {System.out.println(i);}}public static List<Integer> getList(Supplier<Integer> supplier){ArrayList<Integer> list = new ArrayList<>();for(int i=1;i<11;i++){list.add(supplier.get());}return list;}}
消费型接口实例
import java.util.function.Consumer;/*java内置函数式接口:消费型接口只有函数式接口【有且仅有一个抽象方法】才可以被@FunctionalInterface注解所修饰@FunctionalInterfacepublic interface Consumer<T> {void accept(T t);}*/
public class Demo {public static void main(String[] args) {Staff s = new Staff("sj1001", "李刚", 18, 35000);fun1(s, liGang -> System.out.println("员工编号:" + liGang.getId() + ", 姓名:" + liGang.getName() + ", 年龄:" + liGang.getAge() + ", 薪资:" + liGang.getSalary()));}public static void fun1(Staff staff, Consumer<Staff> consumer) {consumer.accept(staff);}
}
类简洁用法
// List<Staff> staffList = fun1(staffs -> Arrays.asList(staffs), s1, s2, s3, s4, s5);/*** 假如 Lambda 表达式符合如下格式:* ([变量1, 变量2, ...]) -> 类名.静态方法名([变量1, 变量2, ...])* 我们可以简写成如下格式:* 类名::静态方法名*/List<Staff> staffList = fun1(Arrays::asList, s1, s2, s3, s4, s5);
对象引用
/*** 假如 Lambda 表达式符合如下格式:* ([变量1, 变量2, ...]) -> 对象引用.方法名([变量1, 变量2, ...])* 我们可以简写成如下格式:* 对象引用::方法名*/
show2("hello","ligang",(s1,s2)->demo2.show(s1,s2));show2("hello","ligang",demo2::show);
数组引用
interface Inter{int[] fun(int i);
}
package com.shujia.day20;
枚举
/*1. 创建枚举类的属性(成员遍历),必须是作为私有常量出现2. 必须将构造方法私有化,这是为了保证类的对象是有限个的目的3. 提供公共的静态的final方法给外界获取枚举类中多个对象4. 提供公共的获取属性的方法5. 重写toString()方法*/
class Season{//1. 创建枚举类的属性(成员遍历),必须是作为私有常量出现private String name;private String info;//2. 必须将构造方法私有化,这是为了保证类的对象是有限个的目的private Season(String name, String info){this.name = name;this.info = info;}//3. 提供公共的静态的final方法给外界获取枚举类中多个对象public static final Season SPRING = new Season("春天","春暖花开");public static final Season SUMMER = new Season("夏天","烈日炎炎");public static final Season AUTUMN = new Season("秋天","秋高气爽");public static final Season WINTER = new Season("冬天","白雪皑皑");//4. 提供公共的获取属性的方法public String getName() {return name;}public void setName(String name) {this.name = name;}public String getInfo() {return info;}public void setInfo(String info) {this.info = info;}@Overridepublic String toString() {return "Season{" +"name='" + name + '\'' +", info='" + info + '\'' +'}';}
}public class SeasonDemo1 {public static void main(String[] args) {Season spring = Season.SPRING;Season summer = Season.SUMMER;}
}public class Demo {public static void main(String[] args) {
// show(7, i->new int[i]);/*** 假如我们的 Lambda 表达式符合如下格式:* (变量) -> new 元素类型[变量]* 我们就可以简写成如下格式:* 元素类型[] :: new*/show(7, int[]::new);}public static void show(int i,Inter inter){int[] ints = inter.fun(i);System.out.println(ints.length);}
}
package com.shujia.day20;import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;public class StudentDemo {public static void main(String[] args) throws Exception{//通过反射获取一个class文件对应Class对象//方式1:在已经有对象的前提下获取
// Student student = new Student();
// Class<? extends Student> c1 = student.getClass();
// Class<? extends Student> c2 = student.getClass();
// System.out.println(c1==c2);//方式2:可以直接通过类名的方式获取
// Class<Student> c1 = Student.class;
// Class<Student> c2 = Student.class;
// System.out.println(c1==c2);//方式3:Class.forName()Class<?> c1 = Class.forName("com.shujia.day20.Student");
// Class<?> c2 = Class.forName("com.shujia.day20.Student");
// System.out.println(c1==c2);// 获取类中的构造方法并使用// getConstructor() 只能获取某一个公共构造方法// public Constructor<T> getConstructor(Class<?>... parameterTypes)Constructor<?> cons1 = c1.getConstructor();
// System.out.println(cons1);
// Constructor<?> cons2 = c1.getConstructor(String.class,String.class);
// System.out.println(cons2);Constructor<?> cons2 = c1.getDeclaredConstructor(String.class, String.class);System.out.println(cons2);Constructor<?> cons3 = c1.getDeclaredConstructor(String.class);System.out.println(cons3);//如何使用获取到的构造方法呢?//public T newInstance(Object ... initargs)Object o = cons1.newInstance();System.out.println(o);cons3.setAccessible(true);Object o1 = cons3.newInstance("1001");System.out.println(o1);// 获取类中的成员变量并使用//getField 只能获取公共的成员变量Field like = c1.getField("like");
// Field id = c1.getField("id");Field id = c1.getDeclaredField("id");// 给对象o1中成员变量like进行赋值操作like.set(o1, "骑自行车");System.out.println(o1);id.setAccessible(true);id.set(o1,"1002");System.out.println(o1);// 获取类中的成员放啊并使用Method fun1 = c1.getMethod("fun1");System.out.println(fun1);Method fun11 = c1.getMethod("fun1",String.class);System.out.println(fun11);
// Method fun3 = c1.getMethod("fun3");
// System.out.println(fun3);Method fun3 = c1.getDeclaredMethod("fun3");System.out.println(fun3);//使用成员方法fun1.invoke(o1);fun3.setAccessible(true);fun3.invoke(o1);}
}