枚举
枚举类型
数据类型的值是固定.
-
1:枚举类型的作用:限定变量的取值.
-
2:枚举优点:方便,安全性好.
-
3:枚举类型特点:是一种引用数据类型,继承自java.lang.Enum,是终止类,它的值是静态常量.
-
4:声明枚举类型语法:
public enum 类型名{ 值1,值2,值3...; //声明普通方法 访问修饰符 返回值类型 方法名(形参列表){ 方法体; [return 结果;] } //声明静态方法 访问修饰符 static 返回值类型 方法名(形参列表){ 方法体; [return 结果;] } }
-
5:使用枚举类型的语法:
-
1:用枚举类型作为变量的数据类型
枚举类型名 变量名=枚举类型名.值1;
-
2:调用枚举类型的普通方法:变量名.普通方法名(实参列表);
调用枚举类型的静态方法:变量名.静态方法名(实参列表);
枚举类型名.静态方法名(实参列表);
-
注解
是代码里的特殊标记,程序可以读取注解,一般用于替代配置文件.
-
1:常见注解:
@Override
@Deprecated -
2:定义注解
@interface关键字,注解中只能包含属性.
-
3:注解属性类型
String类型,基本数据类型,Class类型,枚举类型,注解类型,以上类型的一维数组.
-
4:元注解:用来描述注解的注解.
@Retention
@Target
Java8新特性
1.函数式编程
优点:省内存(少创建好多类和对象);代码简洁.
缺点:可读性较差.
public static void main(String[] args) {
Thread t1=new Thread(new Runnable() {
@Override
public void run() {
System.out.println("123");
}
});
//启动线程
t1.start();
//Java8新特性实现线程对象
Thread t2=new Thread(()->System.out.println("123"));
//启动线程
t2.start();
}
2.(重点)Lambda表达式:
适用条件:所有匿名内部类对象使用的地方都可以用lambda表达式.
2.1:lambda表达式基本语法:
函数式接口:一个接口中只有一个抽象方法,叫函数式接口.
eg: <函数式接口> <变量名> = (参数1,参数2…) -> { //方法体 };
2.2:lambda表达式注意事项:
Lambda引入了新的操作符:->(箭头操作符)->将表达式分成两部分
-
1:左侧:(参数1,参数2…)表示参数列表; 右侧:{}内部是方法体
-
2:形参列表的数据类型会自动推断,所以小括号只需要写形参参数名;
-
3:如果形参列表为空,只需保留();
-
4:如果形参只有1个,()可以省略,只需要参数的名称即可;
-
5:如果执行语句只有1句,且无返回值,{}可以省略,若有返回值,则若想省去{},则必须同时省略return,且执行语句也 保证只有1句;
-
6:lambda不会生成一个单独的内部类文件(省内存);
-
7:lambda表达式若访问了局部变量,则局部变量必须是final的,若是局部变量没有加final关键字,系统会自动添加,此 后在修改该局部变量,会报错。
2.3:lambda的使用:
lambda的案例使用1:
需求1:有一个员工集合,获取年龄大于25的员工信息
需求2:获取工资大于10000的员工信息
/**
* 过滤接口,函数式接口
*/
@FunctionalInterface
public interface MyFilter {
/**
* 根据员工属性过滤
*/
Boolean filterEmp(Employee emp);
}
/**
需求1:有一个员工集合,获取年龄大于25的员工信息
需求2:获取工资大于10000的员工信息
*/
public class Test1 {
public static void main(String[] args) {
List<Employee> emplist=new ArrayList<>();
emplist.add(new Employee("小王", 18, 2000.0));
emplist.add(new Employee("大王", 28, 20000.0));
emplist.add(new Employee("老王", 38, 12000.0));
emplist.add(new Employee("王宝强", 48, 200000.0));
System.out.println("年龄大于25岁所有员工信息:");
//获得年龄大于25岁所有员工信息
// List<Employee> emps1=filterEmployee(emplist, new MyFilter() {
//
// @Override
// public Boolean filterEmp(Employee emp) {
// if (emp.eage>25) {
// return true;
// }
// return null;
// }
// });
List<Employee> emps=filterEmployee(emplist, (e)->e.eage>25);
for (Employee emp2 : emps) {
System.out.println(emp2);
}
System.out.println("------------------------------");
System.out.println("工资大于10000所有工信息:");
//获得年龄大于25岁所有员工信息
List<Employee> emps2=filterEmployee(emplist, (e)->e.salary>10000);
for (Employee emp2 : emps2) {
System.out.println(emp2);
}
System.out.println("============================");
System.out.println("获得所有姓王的员工信息:");
//获得年龄大于25岁所有员工信息
List<Employee> emps3=filterEmployee(emplist, (e)->e.ename.startsWith("王"));
for (Employee emp2 : emps3) {
System.out.println(emp2);
}
}
public static List<Employee> filterEmployee(List<Employee> employees,MyFilter mf){
//声明一个集合存年龄大于25岁的所有员工信息
List<Employee> emplist2=new ArrayList<>();
//遍历原集合,将年龄大于25岁所有员工信息添加新集合中
for (Employee emp : employees) {
if (mf.filterEmp(emp)) {
emplist2.add(emp);
}
}
return emplist2;
}
2.4:函数式接口
如果一个接口中只有一个抽象方法,这个接口叫函数式接口.
函数式接口可以使用Lambda表达式,lambda表达 式会被匹配到这个抽象方法上 .
如果一个接口上面加@FunctionalInterface 注解,编译器如果发现你标注了这个注解的接口有多于一个抽象方法的时候会报错的。
public class FunctionInterfaceTest1 {
public static void main(String[] args) {
//消费型接口方法的调用
consumetMethod(1000.0, (e)->System.out.println("花费"+e+"元钱来买键盘"));
//供给型接口方法的调用
Integer result1=supplierMethod(()->{return (int)(Math.random()*(100-75+1)+75);});
System.out.println("结果1为:"+result1);
//函数式接口方法的调用
Integer result2=functionMethod("123", (e)->{return Integer.valueOf(e);});
System.out.println("结果2为:"+result2);
}
/**
* 消费型接口的使用
*/
private static void consumetMethod(Double money,Consumer<Double> c) {
c.accept(money);
}
/**
* 供给型接口的使用
* @param s
* @return
*/
private static Integer supplierMethod(Supplier<Integer> s) {
return s.get();
}
/**
* 函数型接口的使用
* @return
*/
private static Integer functionMethod(String s1,Function<String, Integer> f) {
Integer result2=f.apply(s1);
return result2;
}
}
public class Test1 {
public static void main(String[] args) {
List<Employee> emplist=new ArrayList<>();
emplist.add(new Employee("小王", 18, 2000.0));
emplist.add(new Employee("大王", 28, 20000.0));
emplist.add(new Employee("老王", 38, 12000.0));
emplist.add(new Employee("王宝强", 48, 200000.0));
System.out.println("年龄大于25岁所有员工信息:");
//获得年龄大于25岁所有员工信息
List<Employee> emps=filterEmployee(emplist, (e)->e.eage>25);
for (Employee emp2 : emps) {
System.out.println(emp2);
}
System.out.println("------------------------------");
System.out.println("工资小于10000所有工信息:");
//获得年龄大于25岁所有员工信息
List<Employee> emps2=filterEmployee(emplist, (e)->e.salary<10000);
for (Employee emp2 : emps2) {
System.out.println(emp2);
}
System.out.println("============================");
System.out.println("获得所有姓王的员工信息:");
//获得年龄大于25岁所有员工信息
List<Employee> emps3=filterEmployee(emplist, (e)->e.ename.startsWith("王"));
for (Employee emp2 : emps3) {
System.out.println(emp2);
}
}
/**
* 断言型接口的使用
* @param employees
* @param p
* @return
*/
public static List<Employee> filterEmployee(List<Employee> employees,Predicate<Employee> p){
//声明一个集合存年龄大于25岁的所有员工信息
List<Employee> emplist2=new ArrayList<>();
//遍历原集合,将年龄大于25岁所有员工信息添加新集合中
for (Employee emp : employees) {
if (p.test(emp)) {
emplist2.add(emp);
}
}
return emplist2;
}
}
2.5:lambda表达式的使用场景
当方法的形参是函数式接口,实参用lambda表达式(理解为lambda表达式就是函数式接口中唯一的那个方法的方法具体实现).
3.(了解)方法引用
是lambda表达式的一种简写形式。 如果lambda表达式方法体中只是调用一个特定的已经存在的方法,则 可以使用方法引用。
使用“::”操作符将方法名和对象或类的名字分隔开来。以下是四种使用情况:
- 1:对象::实例方法
- 2:类::静态方法
- 3:类::实例方法 (四大函数式接口都不能直接用,但是可以间接用Function第一个泛型类型与类名相同,调用无参方法)
- 4:类::new 调用无参构造
public static void main(String[] args) {
// 创建学生类对象
Student stu=new Student();
//对象::实例方法
Supplier<String> ss=stu::getSname;
System.out.println("当前姓名为:"+ss.get());
//类名::静态方法
Consumer<String> cc=Student::show;
cc.accept("Hello Java8");
//类名::new
Supplier<Student> ss2=Student::new;
Student stu2=ss2.get();
System.out.println(stu2.getSname());
//类名::实例方法,不能用供给型接口,函数型接口,消费型接口,断言型接口
//Predicate<Integer> ff=Student::change;
//类名::实例方法时,Function<String, Integer>,第一个泛型与类名同名,否则调不出来
Function<String, Integer> ff1=String::length;
Integer len=ff1.apply("abcd");
Function<Student, String> ff2=Student::getSname;
String sname=ff2.apply(stu);
System.out.println("sname:"+sname);
}
4.(重点)Stream API
一个Stream表面上与一个集合很类似,集合中保存的是数据,而流中对数据的操作。
4.1:Stream特点:
- 1:Stream 自己不会存储元素。
- 2:Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
- 3:Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
4.2:获得Stream的方法(5种)
public static void main(String[] args) {
//第一种创建流
Stream nums1=Stream.of(11,66,22,33);
//第二种创建流:将数组转换为流
int[] nums= {12,43,55};
Stream nums2=Stream.of(nums);
//第三种创建流:将集合转换为流
HashSet<String> hset=new HashSet<>();
hset.add("ff");
hset.add("aa");
hset.add("kk");
Stream s3=hset.stream();//普通流,单个线程操作
//Stream s3=hset.parallelStream();//并行流,多个线程操作
//第四种创建流:生成自动无限流
Stream nums4=Stream.generate(()->{return Math.random();});
//第五种创建流:用自动增减来实现无限流
Stream nums5=Stream.iterate(1, (e)->{return e+2;});
nums5.limit(10).forEach((e)->System.out.println(e));
}
4.3:Stream的常用中间操作
过滤,限制,跳过,去重,map映射,自然排序,定制排序
**注意:**Stream对象调用中间操作的方法后返回的还是Stream类型对象.
Stream对象调用中间操作的方法后,Stream没有关闭.
public static void main(String[] args) {
List<String> alist=new ArrayList<String>();
alist.add("f张三");
alist.add("a李四");
alist.add("k来福");
alist.add("b张师妹");
alist.add("c张师妹");
//过滤
Stream<String> s1= alist.stream().filter((e)->e.startsWith("张"));
//限制
Stream<String> s2= alist.stream().limit(2);
//跳过前几个
Stream<String> s3= alist.stream().skip(3);
//去重,元素所在的类中不重写hashCode()和equals()根据内存地址,重写hashCode()和equals()根据值去重
Stream<String> s4= alist.stream().distinct();
//map映射
Stream<Object> s5= alist.stream().map((e)->{return e.length();});
//自然排序
Stream<String> s6= alist.stream().sorted();
//定制排序
Stream<String> s7= alist.stream().sorted((e1,e2)->{
return -e1.compareTo(e2);
});
s7.forEach((e)->System.out.println(e));
}
4.4:Stream的终止操作
作完终止操作后,流会关闭.
//allMatch——检查是否匹配所有元素
// anyMatch——检查是否至少匹配一个元素
// noneMatch——检查是否没有匹配的元素
// findFirst——返回第一个元素
// findAny——返回当前流中的任意元素
// (*)count——返回流中元素的总个数
// max——返回流中大值
// min——返回流中小值
//(*)reduce处理集合中元素得到个新数据
//()将流转换为list集合
//(*)将流转换为set集合
public static void main(String[] args) {
List<String> alist=new ArrayList<String>();
alist.add("f张三");
alist.add("a李四");
alist.add("k来福");
alist.add("b张师妹");
alist.add("c张师妹");
// (*)count——返回流中元素的总个数
long result=alist.stream().count();
//System.out.println(result);
//(*)reduce处理集合中元素得到个新数据
Stream<Integer> nums1=Stream.of(33,12,22,44);
//第一个参数是结果初始值,x代表每次的结果,y代表集合中每个元素
//Integer sum=nums1.reduce(0, (x,y)->x+y);//x=0, x=x+集合中每个元素
//System.out.println(sum);
//(*)将流转换为list集合
//List<Integer> list2=nums1.collect(Collectors.toList());
//List<String> list2=alist.parallelStream().collect(Collectors.toList());
// for (int i = 0; i < list2.size(); i++) {
// System.out.println(list2.get(i));
// }
//(*)将流转换为set集合
// Set<String> set3=alist.parallelStream().collect(Collectors.toSet());
Set<Integer> set3=nums1.collect(Collectors.toSet());
for (Integer s : set3) {
System.out.println(s);
}
//将流中数据遍历输出
//s7.forEach((e)->System.out.println(e));
}
5.java8中新日期
5.1:原来java中日期问题
非线程安全;设计差(java.util.Date,java.sql.Date);时区处理麻烦
java8中引入新日期时间API
LocalDate:是一个不可变的日期时间对象,表示日期,通常被视为年月日
LocalTime:是一个不可变的日期时间对象,代表一个时间,通常被看作是小时 - 秒
LocalDateTime:是一个不可变的日期时间对象,代表日期时间,
通常被视为年 - 月 - 日 - 时 - 分 - 秒。
Instant:在时间线上的瞬间点,可以对日期作加,减操作。
ZoneId:用于识别用于在Instant和LocalDateTime之间转换的规则
DateTimeFormatter:格式化器用于打印和解析日期时间对象。
5.2:新日期时间的使用:
5.2.1:本地化日期时间
public static void main(String[] args) {
//获得系统日期
LocalDateTime today=LocalDateTime.now();
System.out.println("当前系统时间为:"+today);
System.out.println("年:"+today.getYear());
System.out.println("月:"+today.getMonth());
System.out.println("日:"+today.getDayOfMonth());
System.out.println("时:"+today.getHour());
System.out.println("分:"+today.getMinute());
System.out.println("秒:"+today.getSecond());
//设定日期
LocalDateTime ldt1=LocalDateTime.of(2020, 10, 1, 1, 1,1);
System.out.println("设置的日期为:"+ldt1);
//在日期中加5天
LocalDateTime ldt2= ldt1.plusDays(5);
System.out.println("在日期中加5天为:"+ldt2);
//在日期中减5天
LocalDateTime ldt3= ldt1.minusDays(5);
System.out.println("在日期中减5天为:"+ldt3);
}
5.2.2:Instant 时间戳 类似以前的Date和ZoneId时区
//Date-----Instant-------LocalDateTime
//LocalDateTime-----Instant-------Date---------
5.2.3:时间矫正器 TemporalAdjuster
5.2.4: DateTimeFormatter
public static void main(String[] args) {
//获得当前系统一瞬间的GMT时间
// Instant i1=Instant.now();
// System.out.println("当前系统一瞬间的时间:"+i1);
//
// //获得所有时区
// Set<String> allZone= ZoneId.getAvailableZoneIds();
// System.out.println("所有时区:"+allZone);
// //获得系统默认时区
// ZoneId zone1= ZoneId.systemDefault();
// System.out.println("系统默认时区:"+zone1);
//Date-----Instant-------LocalDateTime
//获得当前系统时间java.util.Date
Date d1=new Date();
System.out.println("d1:"+d1);
//将date转换为Instant
Instant i1=d1.toInstant();
//将Instant转换为LocalDateTime
LocalDateTime ldt3=LocalDateTime.ofInstant(i1, ZoneId.systemDefault());
System.out.println("ldt3:"+ldt3);
//LocalDateTime-----Instant-------Date---------
//获得当前系统时间java.time.LocalDateTime
LocalDateTime ldt4=LocalDateTime.now();
System.out.println("ldt4:"+ldt4);
//将LocalDateTime转换为Instant
//Instant i2=ldt4.atZone(ZoneId.systemDefault()).toInstant();
//将LocalDateTime->时区->Instant->Date
Date d2=Date.from(ldt4.atZone(ZoneId.systemDefault()).toInstant());
System.out.println("d2:"+d2);
//求时间之差
System.out.println("时间之差:"+Duration.between(ldt3, ldt4));
//日期矫正器,获得下个星期一
LocalDateTime ldt5= ldt4.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
//获得上个星期一
LocalDateTime ldt6=ldt4.with(TemporalAdjusters.previous(DayOfWeek.MONDAY));
System.out.println(ldt6);
//日期格式化
DateTimeFormatter dtf=DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
//将日期转换为指定格式字符串
String s1=ldt6.format(dtf);
System.out.println("s1:"+s1);
//将字符串转换为指定格式日期
LocalDateTime ldt7=LocalDateTime.parse("2020-01-01 11:11:11", dtf);
System.out.println("ldt7:"+ldt7);
}
6.(扩展):策略模式
- 1:优点:提高程序可扩展性.
- 2:实现原理:将相同行为抽成一个接口(行为接口),定义方法,将具体实现定义实现类(算法类),在调用算法的方法中,用行为接口作为参数,调用方法.在实参传具体接口实现类(算法类),从而不同实现类,实现不同效果.
- 3:案例:有个员工集合,根据不同条件筛选需要员工信息,相同点复选员工,不同点就是筛选条件不同,将筛选作为接口,声明几个不同筛选条件实现类.
个人笔记,思路,仅供参考