JAVASE23天从入门到精通_Day23

枚举的概述

枚举是 Java 中一种特殊的类(类型),它可以定义固定数量的枚举实例(此类的对象),例如: 性别、交通信号灯、季节等等 -> enum

枚举类的对象不是new出来的, 而是一一罗列出来的. -> 数量有限

类的对象只有有限个,确定的

  • 星期:Monday(星期一)、… 、Sunday(星期天)
  • 性别:Man(男)、Woman(女)
  • 季节:Spring (春天)、Summer(夏天)、Autumn(秋天)、Winter(冬天)
  • 支付方式:Cash(现金)、WeChatPay(微信)、Alipay(支付宝)、BankCart(银行卡)、CreditCart(信用卡)
  • 就职状态:Busy、Free、Vocation、Dimission
  • 订单状态:Nonpayment(未付款)、Paid(已付款)、FulFilled(已配货)、Delivered(已发货)、Return(退货)、Checked(已确认)
为什么要使用枚举

假设我们要定义一个人类,人类中包含姓名和性别。通常会将性别定义成字符串类型,效果如下:

public class Person {
    private String name;
    private String sex;

    public Person() {
    }

    public Person(String name, String sex) {
        this.name = name;
        
              this.sex = sex;
        
    }
	
    // 省略get/set/toString方法
    
}
public class Demo01 {
    public static void main(String[] args) {
        Person p1 = new Person("张三", "男");
        Person p2 = new Person("张三", "abc"); // 因为性别是字符串,所以我们可以传入任意字符串,但事实上性别只能是‘男’或者‘女’
    }
}

不使用枚举存在的问题:可以给性别传入任意的字符串,导致性别是非法的数据,不安全。

问题解决:

//定义一个枚举类型
public enum Gender{
    //Sex类中只有2个对象
    MALE,//男
    FEMALE;//女
}
public class Person {
    private String name;
    private Gender gender;

    public Person() {
    }

    public Person(String name, Gender gender) {
        this.name = name;
        this.gender = gender;
    }
	
    // 省略get/set/toString方法
}

public class Demo01 {
    public static void main(String[] args) {
        Person p1 = new Person("张三", Gender.MALE);
        Person p2 = new Person("张三", Gender.FAMALE); 
    }
}
枚举类的使用

枚举的实现方式

  • JDK1.5之前需要自定义普通类
  • JDK1.5及以后新增的enum关键字用于定义枚举类 -> 枚举从JDK5版本有的

需求: 定义一个方法,方法的参数传递“一年四季中的某一个季节”,根据不同的季节,打印对不同季节的描述

定义枚举类的做法
枚举类的定义:
        public enum 类名{
            //枚举项的名称全部大写 : 规范
            //枚举项都是此类的对象
            枚举项1,
            枚举项2,
            ...
            枚举项n;
        }
    枚举对象的使用:
        枚举类类名.枚举项;
 public enum SeasonEnum {
     //这四个枚举项是SeasonEnum枚举类的对象,只有四个!!
    SPRING,
    SUMMER,
    AUTUMN,
    WINTER;
}

 //通过枚举类 可以这样写
    public static void printSeasonByEnum(SeasonEnum seasonEnum){
        switch (seasonEnum){
            case SPRING:
                System.out.println("春暖花开");
                break;
            case SUMMER:
                System.out.println("夏日炎炎");
                break;
            case AUTUMN:
                System.out.println("硕果累累");
                break;
            case WINTER:
                System.out.println("雪花飘飘");
                break;

        }
    }
 public static void main(String[] args) {        //使用枚举类,作为方法的参数        printSeasonByEnum(SeasonEnum.AUTUMN); }
案例应用
  1. 定义枚举:MALE表示男,FEMALE表示女
enum Sex {
    MALE, FEMALE; // 男,女
}
  1. Perosn中的性别有String类型改为Sex枚举类型
public class Person {
    private String name;
    private Sex sex;

    public Person() {
    }

    public Person(String name, Sex sex) {
        this.name = name;
        this.sex = sex;
    }
    // 省略get/set/toString方法
}
  1. 使用时只能传入枚举中的固定值
public class Demo02 {
    public static void main(String[] args) {
        Person p1 = new Person("张三", Sex.MALE);
        Person p2 = new Person("张三", Sex.FEMALE);
        Person p3 = new Person("张三", "abc");//这样写就不可以,只能是固定的枚举类型的对象
    }
}
枚举中添加成员变量和成员方法和构造方法

枚举的本质是一个类,所以枚举中还可以有成员变量,成员方法等。

例如:定义一个交通信号灯,分别有红灯,绿灯,黄灯,并对每一个信号灯加以说明: 比如 红灯停,绿灯行,黄灯亮了等一等 ,

public enum Light {
    //1.枚举类必须先定义对象  (类似调用类的无参构造器对象 )
    RED("红灯停"),GREEN("绿灯行"),YELLOW("黄灯亮了等一等");
    
    //2.在枚举中定义属性 和 方法
    String colorDesc;

    public String getColorDesc() {
        return colorDesc;
    }

    public void setColorDesc(String colorDesc) {
        this.colorDesc = colorDesc;
    }

    //3.通过构造器给不同的枚举对象传参
    private Light(String colorDesc){
        this.colorDesc = colorDesc;
    }
}
  public static void main(String[] args) {
        System.out.println(Light.GREEN);
        //枚举对象的方法
        System.out.println(Light.GREEN.getColorDesc());
        //遍历所有的枚举对象 (values() 方法来自父类 Enum类)
        Light[] values = Light.values();
        for(Light light : values){
            System.out.println(light.name() + "---" + light.getColorDesc() );
        }

         Light light = Light.valueOf("GREEN");
         System.out.println("根据字符串返回一个枚举对象:"+light);
    }
枚举类的常用方法
常用方法解释返回类型
枚举类.values()返回枚举类的所有对象,是一个对象数组对象数组
枚举类.valueOf(String)根据字符串返回对应的枚举类型枚举类型
枚举对象.ordinal()返回该对象在枚举类中的序号int
枚举对象.name()返回该对象的枚举名称Stirng
函数式接口
函数式接口: 是一个接口中有且仅有一个抽象方法的接口;
	只约束了抽象方法的个数 : == 1
    没有要求默认方法,静态方法的个数
    
注解 : @FunctionalInterface   

已经学过的函数式接口:
	Runnable  -> void run()
    Callable<T> -> T call()
	Comparable<E> -> int compareTo(E o)
    Comparator<E> -> int compare(E o1,E o2)  
    FileFilter -> boolean accept(File filename)   
        
函数式接口是Lambda表达式的使用前提;        
面向函数式编程思想
面向过程 : 凡事必躬亲
面向对象 : 自己的事情别人做,懒人思维
	1. 创建对象
	2. 对象调方法
面向函数 : 	基于面向对象的升级
	忽略了对象,只关注对象做什么
	//省去了子类对象的创建,省去了重写方法的声明格式,全神贯注在重写方法的方法体!
Lambda表达式
Lambda表达式 :
	1. 函数式接口是Lambda表达式的使用前提; 
	2. Lambda表达式运用的编程思想是 面向函数式编程
	3. Lambda表达式是对匿名内部类格式的简写 (使用范围没有匿名内部类广)
        
匿名内部类 :
	//适用场景
    new 接口/抽象父类/普通父类(){
		//接口,抽象父类,普通父类的某个不知类名的子类的类主体
    }

Lambda表达式:
	//适用场景
    new 函数式接口(){
		//函数式接口的某个不知类名的子类的类主体
    }

能用Lambda的地方一定能用匿名内部类,能用匿名内部类的地方不一定能用Lambda
//Lambda能不能用主要看new的是不是一个函数式接口,如果是就能用!!
Lambda表达式的格式
    通用Lambda格式:
        (重写方法的形参列表) -> {
            重写方法的方法体;
        }
	简化格式:
 		1. 当重写方法的方法体内,有且仅有一句代码的时候,可以省略重写方法的
                大括号,分号,return关键字
                要省都省 ,要不省都不省
        2. 所有的方法形参类名可以省略,所有方法形参的名称可以改,改完方法内的变量也要改名字
        3. 当形参的个数有且仅有一个的时候 可以省略包裹形参的小括号
方法引用
方法引用 : method reference

Lambda是匿名内部类的简写 -> 必须是函数式接口
方法引用是Lambda表达式的简写 
	1. 必须满足Lambda的使用条件
	2. 要求重写的方法内有且仅有一句代码
	3. 这一句话必须是:
		a.对象调方法 :  对象名::方法名
		b.类名调用静态方法 : 类名::静态方法名
		c.创建对象 : 类名::new
		d.创建数组 : 数组类型::new
		
方法引用的大致格式  ::
方法引用案例
@FunctionalInterface
interface InterA{
    public abstract void print(String str);
}

@FunctionalInterface
interface InterB{
    public abstract int change(String str);
}

@FunctionalInterface
interface InterC{
    public abstract Date get();
}

@FunctionalInterface
interface InterD{
    public abstract int[] get(int length);
}
Stream流
stream流:对集合的一种新的操作方式
流: 流水线
体验Stream流
 //创建一个集合,存储多个字符串元素
        ArrayList<String> list = new ArrayList<String>();

        list.add("林青霞");
        list.add("张曼玉");
        list.add("王祖贤");
        list.add("柳岩");
        list.add("张敏");
        list.add("张无忌");

        //把集合中所有以"张"开头的元素存储到一个新的集合
        ArrayList<String> zhangList = new ArrayList<String>();

        for(String s : list) {
            if(s.startsWith("张")) {
                zhangList.add(s);
            }
        }

//        System.out.println(zhangList);

        //把"张"开头的集合中的长度为3的元素存储到一个新的集合
        ArrayList<String> threeList = new ArrayList<String>();

        for(String s : zhangList) {
            if(s.length() == 3) {
                threeList.add(s);
            }
        }

//        System.out.println(threeList);

        //遍历上一步得到的集合
        for(String s : threeList) {
            System.out.println(s);
        }
进Stream流的方法(进工厂)
    1. 单列集合
        Stream<E> stream()  --> 来自于Collection<E>
    2. 数组
        static Stream<数组元素类型> stream(一维数组)  -->来自于Arrays
    3. 一组同类型的数据
        static <T> Stream<T> of(T... values)  --> 来自于Stream接口
    4. 双列集合 不能直接进流
        a. 双列集合中 : Set<K> keySet() 获取键集 --> 键集转流
        b. 双列集合中 : Collection<V> values() 获取值集 --> 值集转流
        c. 双列集合中 : Set<Map.Entry<K,V>> entrySet() 获取键值对集合 --> 键值对集合转流
对数据进行加工的方法(进车间)
过滤车间
Stream接口中的 : Stream<T> filter(Predicate<? super T> predicate)  
    	filter: 方法具备过滤的功能 -> 缺 过滤条件!!
            
Predicate<? super T> : 判断性接口(函数式接口) -> 提供过滤的条件的!!
    抽象方法: 	boolean test(T t)  
跳过车间
Stream接口中的 : Stream<T> skip(long n)  
    跳过流中的 前 n 个数据 生成新的流对象
截取车间
Stream接口中的 : Stream<T> limit(long maxSize)  
    保留流中的 前 maxSize 个数据 生成新的流对象
去重车间
Stream接口中的 :  Stream<T> distinct()
    把流中的重复元素进行去重操作,返回去重后的新流对象 (依照equals方法进行去重)
合并车间
Stream接口中的 : static <T> Stream<T> concat(Stream<T> a, Stream<T> b)  
    把a流和b流中的数据进行合并,生成新的流对象
转换车间
Stream接口中的 :  <R> Stream<R> map(Function<T,R> mapper)  
    map方法具备转换的能力 -> 缺 如何转换
    
Function<T,R> 接口 带有转换功能
	抽象方法 :  R apply(T t)
出流方法(出工厂)
遍历出厂
Stream接口中的 :  void forEach(Consumer<? super T> action) 
    forEach 方法类似循环,循环在遍历流,拿到每个数据 -> 流中数据拿到后,做什么???
    
Consumer<? super T> 函数式接口 -> 消费性接口    
	有且仅有一个抽象方法 : void accept(T t) -> 重写后的方法体就是在使用流中数据 t
统计出厂
Stream接口中的 :  long count()  
    	统计最终流中有几个元素
收集出厂 ***
<R,A> R collect(Collector<T,A,R> collector)  
    Collector是一个接口,且接口中不止一个抽象方法,用起来非常的麻烦!!
    所以 借助工具类  : Collectors

1. 收集成List集合 -> 元素可重复
	static <T> Collector<T,?,List<T>> toList()  
2. 收集成Set集合 -> 元素不能重复
	static <T> Collector<T,?,Set<T>> toSet()  
3. 收集成双列集合 -> 想办法把流中的单列数据转换成键和值???
    static  Collector toMap(Function<T,K> keyMapper, Function<T,V> valueMapper)  
        //转成双列集合的时候不允许流中有 重复元素
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值