java8之后的那些新玩意
一:Lambda表达式
声明:看到代码不要慌,里面的注释写的不明白你来打我
下面是案例中要用到的Student对象
public class Student {
public static List<Student> getList(){
List list = new ArrayList();
list.add(new Student("苍老师",28));
list.add(new Student("布泽老师",31));
list.add(new Student("吉田惠子",18));
list.add(new Student("巴王超过",26));
return list;
}
private String name;
private int age;
//getter setter toString 构造
先体验一把,后面会细讲
public static void main(String[] args) {
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("这是传统的匿名内部类");
}
};
r1.run();
System.out.println("=========================================================");
//lambda表达式 将new Runnable直接省略了,因为我前面是Runable接收,这里肯定是newRunable,是死的所以可以省略
//省略了之后小括号和大括号之间要用一个箭头连接
Runnable r2 =()->{
System.out.println("这是lambda表达式1");
};
r2.run();
System.out.println("=========================================================");
//lambda表达式-----如果方法体只有一条语句,那么大括号也可以省略
Runnable r3 =()->System.out.println("这是lambda表达式2");
r3.run();
System.out.println("====================案例二=====================================");
//传统
Comparator<Integer> com1 = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
};
int rs1 = com1.compare(10,20);
System.out.println(rs1);
System.out.println("====================案例二=====================================");
//lambda
Comparator<Integer> com2 = (Integer o1, Integer o2)->{
return Integer.compare(o1,o2);
};
int rs2 = com1.compare(30,20);
System.out.println(rs2);
System.out.println("====================案例二=====================================");
//lambda 参数的类型由前面的泛型指定了,所以也可以省略
//当lambda的语句体只有一条语句时,return和大括号都可以省略,否则需要保留
Comparator<Integer> com3 = (o1, o2)-> Integer.compare(o1,o2);
int rs3 = com1.compare(30,30);
System.out.println(rs3);
/**
× 格式:
* (param1,param2....)->{};
* ->:是lambda操作符或箭头操作符
* ->左边是形参列表没有参数时保留小括号,有一个参数是可以省略小括号param1->{}
* ->右边:是lambda体
* lambda表达式的本质是接口的实例对象,也可以理解为匿名内部类的简化写法
*/
//
Runnable r11 = new Runnable() {
@Override
public void run() {
System.out.println("这是传统的匿名内部类");
}
};
r11.run();
System.out.println("=========================================================");
//lambda表达式
Runnable r21 =()->{
System.out.println("这是lambda表达式1");
};
r21.run();
System.out.println("=========================================================");
//
Consumer<String> con = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
con.accept("Consumer是有参无返回值");
Consumer<String> cons = (String s) ->System.out.println(s);
cons.accept("lambda:Consumer是有参无返回值");
//参数可以省略,由编译器推断得出:类型推断---由前面的泛型推断得到
Consumer<String> con2 = (s) ->System.out.println(s);
con2.accept("lambda:Consumer是有参无返回值");
//只有一个参数时,小括号可以省略
Consumer<String> con3 = s ->System.out.println(s);
con3.accept("lambda2:Consumer是有参无返回值");
//ComParator有且仅有一个方法
Comparator<Integer> com11 = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
};
int rs11 = com11.compare(10,20);
System.out.println(rs11);
//因为ComParator有且仅有一个方法,所以我们省略了方法的名字,以为调用的方法一定是compare方法,没有其他的方法,如果有其他的方法,那么也就不能用lambda表达式
Comparator<Integer> com22 = (Integer o1, Integer o2)->{
System.out.println("包含多条lambda体");
return Integer.compare(o1,o2);
};
int rs22 = com1.compare(30,20);
System.out.println(rs22);
/**
* 总结:
* lambda的参数类型可以省略,如果只有一个参数是小括号也可以省略
* 如果lambda语句体只有一条语句,则可以省略大括号,如果只有一条语句且包含return,则大括号和return需要同时省略
* lambda表达式主要是给也只能给只有一个方法的接口提供实例化对象
*/
}
二:函数式接口
public static void main(String[] args) {
/**
* 函数式接口:如果一个接口有且仅有一个抽象方法时,这个接口被称为函数式接口,这种接口上面都会加一个@FunctionalInterface注解,如果有该注解,你就不能在为该接口增加方法,因为它只能有一个方法
* ctrl+shift+t可以搜索你想查看的类结构 Ctrl+H 全项目检索你要查找的字符
* @FunctionalInterface
* public interface Comparator<T> {
*
* java早期倡导的是一切皆对象的面向对象编程OOP,但是为了适应更为广泛的技术要求,java也开始支持面向函数编程OOF
*
* 其他语言里面Lambda表达式属于函数,但是在java里面Lambda表达式属于对象,它必须依附于一类特别的对象类型而存在-->函数式接口
*
* 所以,Lambda表达式是匿名内部类的一种简化
*
* java内置了四大核心函数式接口
* 1消费型接口
* Consumer<T> void accept(T t);
* 2供给型接口
* Supplier<T> T get()
* 3函数型接口
* Function<T,R> R apply(T t)
* 4断言型接口
* Predicate<T> boolean rest(T t)
*/
//testConsuper
Consumer<Double> con = (m)->System.out.println("天上人间不适合,白马会所欢迎您,此次消费"+m);
//happyTime是main方法外面自定义的函数,请网下翻看
happyTime(212.5,con);
//happyTime第二个参数要的是Consumer参数,所以lambda创建的是Consumer接口的对象
happyTime(312.5,mm-> System.out.println("天上人间不适合,白马会所欢迎您,此次消费"+mm));
//testSupplier
int[] arr = getArr(10, () -> new Random().nextInt(100));
for (Integer i:arr ) {
System.out.print(i+",");
}
System.out.println();
//testFunction
String helloword = handlerString("helloword", (s1) -> s1.toUpperCase());
System.out.println(helloword);
//testPredicatet
List list = Arrays.asList("苍老师","布泽老师","麻生希博士","上原瑞橞博士");
String fs = filterString(list,s->s.endsWith("老师"));
System.out.println(fs);
}
/**
* testConsuper
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
*/
public static void happyTime(double money, Consumer<Double> con){
con.accept(money);
}
/**
* testSupplier
@FunctionalInterface
public interface Supplier<T> {
T get();
}
*/
public static int [] getArr(int length, Supplier<Integer> supplier){
int [] arr = new int[length];
for (int i=0;i<length;i++){
arr[i] = supplier.get();
}
return arr;
}
/**
* testFunction
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
*/
public static String handlerString(String str, Function<String,String> function){
return function.apply(str);
}
/**
* testPredicatet
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
*/
public static String filterString(List<String> list, Predicate<String> predicate){
List<String> rs = new ArrayList<>();
for (String s :list){
if (predicate.test(s)){
rs.add(s);
}
}
return rs.toString();
}
三:方法引用
public static void main(String[] args) {
/**
* 什么时候使用方法引用:当函数式接口的实现语句体是另外一个对象的方法并且参数匹配时,可以使用方法引用省略函数式接口的方法声明
* 举例:
* aaa(String aa,String bb){
对象.mm(aa,bb);
}
可以简化:
aaa(String aa,String bb){
对象::mm;
}
* 格式:
* 对象::实例方法
* 类::实例方法
* 类::静态方法
×
*/
/**
* 对象::实例方法
*/
Consumer<String> con = s-> System.out.println(s);
con.accept("消费性接口字符串");
PrintStream ps = System.out;
//Consumer的accept方法和ps的print方法参数和返回值都相同,
//所以直接用ps的print方法来代替consumer的accept方法
//由右边可以推出左边创建的对象是Consumer,所以调用的方法一定是accept,参数为String类型,然后accept方法调用ps的print方法,由于println和accept的参数一样,所以使用方法引用简化操作。
Consumer<String> con2 = ps::println;
con2.accept("方法引用消费性接口");
Student stu = new Student("张三",18);
Supplier<String> supplier =()->stu.getName();
System.out.println(supplier.get());
//Supplier的get方法和stu的getAge方法形参列表和返回值类型都一样,所以可以直接使用方法引用简化
Supplier<Integer> supplier2 = stu::getAge;
System.out.println(supplier2.get());
System.out.println("=================================================================================");
/**
* 类::静态方法
*/
Comparator<Integer> com1 = (num1,num2)->Integer.compare(num1,num2);
System.out.println(com1.compare(10,20));
Comparator<Integer> com2 = Integer::compare;
System.out.println(com2.compare(20,10));
Function<Double,Long> function = num->Math.round(num);
System.out.println(function.apply(12.3));
Function<Double,Long> function1 = Math::round;
System.out.println(function1.apply(12.5));
System.out.println("=================================================================================");
/**
* 前面两种情况一定要强调方法引用的形参列表和返回值类型一定要和函数式接口的抽象方法一致
* 但是
* 在下面这种情况下,他们也可以不一致
* 类::非静态方法
*/
//String类中有一个方法compareTo: s1.compareTo(s2) 比较s1和s2的大小
Comparator<String> comStr = (s1,s2)->s1.compareTo(s2);
System.out.println(comStr.compare("abc","abd"));
//上面式用s1去调用参数s2 那么调用者我们可以使用它的类来代替,当作方法参数的直接省略
Comparator<String> comStr2 = String::compareTo;
System.out.println(comStr2.compare("abd","abc"));
BiPredicate<String,String> biPredicate = (s1,s2)->s1.equals(s2);
System.out.println(biPredicate.test("abc","abc"));
BiPredicate<String,String> biPredicate2 = String::equals;
System.out.println(biPredicate2.test("abc","abd"));
Student student = new Student("巴王超过",9);
//第一个泛型式参数类型,第二个泛型是返回值类型
Function<Student,String> fun = new Function<Student, String>() {
@Override
public String apply(Student ss) {
return ss.getName();
}
};
System.out.println(fun.apply(student));
Function<Student,String> function2 = Student::getName;
System.out.println(function2.apply(student));
}
四:构造器引用和数组引用
public static void main(String[] args) {
Supplier<Student> supplier = ()->new Student();
System.out.println(supplier.get());
Supplier<Student> supplier1 = Student::new;
System.out.println(supplier.get());
Function<String,Student> function = name->new Student(name);
System.out.println(function.apply("巴王超过"));
Function<String,Student> function1 = Student::new;
System.out.println(function1.apply("巴王超过牛逼"));
BiFunction<String,Integer,Student> biFunction = (name,age)->new Student(name,age);
System.out.println(biFunction.apply("巴王超过",66));
BiFunction<String,Integer,Student> biFunction1 = Student::new;
System.out.println(biFunction1.apply("巴王超过",99));
System.out.println("=============================================================================");
//数组引用
Function<Integer,String[]> function2 = leng->new String[leng];
System.out.println(Arrays.toString(function2.apply(5)));
Function<Integer,String[]> function3 = String[]::new;
System.out.println(Arrays.toString(function3.apply(10)));
}
五:Stream流
public static void main(String[] args) {
/**
* Stream定义在java.util.stream包下面
* 主要作用是对集合数据进行处理:如排序,筛选等
* Collection集合主要是将数据存放在内存中,而Stream是将这些存放在内存中的数据做进一步的处理,所以stream本身不会存储数据
*
* Stream对数据的操作分为三步:
* 1.创建stream
* 2.对数据进行操作
* 3.提交。2中的操作不会立即执行,需要在第三步调用执行提交的方法才会去执行)
*/
//创建Stream对象有四种方式
//方式一:通过集合创建
List<Student> list = Student.getList();
//串行流
Stream<Student> stream1 = list.stream();
//并行流
Stream<Student> paralleStream = list.parallelStream();
//方式二:通过Arrays工具类的stream方法创建
int [] intarr = {11,22,33};
double [] darr = {1.1,2.2,3.3};
long [] larr = {1L,2L,3L};
Student [] stuarr = {new Student(),new Student()};
IntStream intStream = Arrays.stream(intarr);
DoubleStream Doublestream = Arrays.stream(darr);
LongStream longStream = Arrays.stream(larr);
Stream<Student> stuStream = Arrays.stream(stuarr);
//方式三:通过Stream本身的of方法
Stream<Integer> integerStream = Stream.of(11, 22, 33, 44);
Stream<Student> studentStream = Stream.of(new Student(), new Student());
//方式四:通过无限流创建:容器中的元素是无限的,Stream有两个方法:iterate和generate
//public static Stream iterate(final T seed, final UnaryOperator<T> f) {
//public interface UnaryOperator<T> extends Function<T, T> 第二个参数UnaryOperator就是一个特殊的Function,参数和返回值类型一样的Function
UnaryOperator<Integer> function = num->num+2;
//初始值是0,后面每次递增2
Stream s1 = Stream.iterate(0,function);
//容器中的数初始值是10,后面每次递增10
Stream s2 = Stream.iterate(10,t->t+10);
//public static Stream generate(Supplier<? extends T> s) {
//generate的参数是Supplier,返回supplier提供的数据
Stream s3 = Stream.generate(Math::random);
//上面三个无限流可以通过下面的方式查看(后面细讲)
s1.limit(10).forEach(System.out::println);
s2.limit(10).forEach(System.out::println);
s3.limit(10).forEach(System.out::println);
}
六:Steam对数据的操作
public static void main(String[] args) {
/**
* 筛选与分片
*/
//1:filter(Predicate) 从容器中排除某些数据
List<Student> list = Student.getList();
Stream<Student> stuStream = list.stream();
//将list中年龄大于30的取出来
Stream<Student> endStream = stuStream.filter(stu -> stu.getAge() > 30);
endStream.forEach(System.out::println);
System.out.println("===========================================================================================");
//2:limit(n) 截取容器中的元素,使容器中的元素不超过给定的数n,包含n
//这里会报错,因为stuStream上面已经结束操作了,不能重复操作
//stuStream.filter(stu -> stu.getAge() > 10).limit(2).forEach(System.out::println);
Stream<Student> stuStream2 = list.stream();
stuStream2.filter(stu -> stu.getAge() > 10).limit(2).forEach(System.out::println);
System.out.println("===========================================================================================");
//3:skip(n) 跳过前n个数据,如果不足n个,则返回一个空流,也就是流中没有任何数据
list.stream().skip(2).forEach(System.out::println);
//4: distinct() 去重:根据hashCode和equals方法进行去重
System.out.println("===========================================================================================");
list.add(new Student("abc",222));
list.add(new Student("abc",222));
list.add(new Student("abc",222));
list.add(new Student("abc",222));
list.add(new Student("abc",222));
list.stream().forEach(System.out::println);
System.out.println("===========================================================================================");
list.stream().distinct().forEach(System.out::println);
/**
* 映射
*/
System.out.println("===========================================================================================");
//map(Function f)将map中的函数作用在容器中的每一个元素上
List<String> arrList = Arrays.asList("aa","bb","cc");
//容器中现在有三个元素"aa","bb","cc",现在把转大写的方法作用在每一个元素上,使他们全部变为大写:把小写映射成大写
arrList.stream().map(str->str.toUpperCase()).forEach(System.out::println);
System.out.println("===========================================================================================");
//获取学生姓名大于三个字的 学生姓名
//流中的数据是一个一个的学生我们用变量stu表示 nameSteam流里面只包含学生姓名
Stream<String> nameStream = list.stream().map(stu -> stu.getName());
//上一行代码也可以用下面的代码简化
Stream<String> nameStream2 = list.stream().map(Student::getName);
nameStream.filter(name->name.length()>3).forEach(System.out::println);
System.out.println("===========================================================================================");
//flatMap(Function f)
//map和flatMap的区别:如果操作的本身是流数据,Map会把流装到外面的流里面形成Stream<Stream<T>>结构,
// 如果是flatMap,会把里面的流数据和外面的流数据合并成一个流,形参Stream<T>的结构
//用list的add和andall方法举例
List list1 = Arrays.asList(11,22);
List list2 = Arrays.asList(33,44);
List list3 = new ArrayList<>();
list3.add(list1);
list3.add(list2);
System.out.println(list3.toString());//[ [11, 22], [33, 44] ]
System.out.println("===========================================================================================");
List list4 = new ArrayList<>();
list4.addAll(list1);
list4.addAll(list2);
System.out.println(list4.toString());// [11, 22, 33, 44]
//对比list3和list4你细品
System.out.println("===========================================================================================");
List<String> list5 = Arrays.asList("abcdef");
//stream1里面装的是abcdef
Stream<String> stream1 = list5.stream();
//stream2中装的是getStream方法返回的流
Stream<Stream<Character>> stream2 = stream1.map(str -> getStream(str));
stream2.forEach(stream11->stream11.forEach(System.out::println));
System.out.println("===========================================================================================");
List<String> list6 = Arrays.asList("abcdef");
//stream1里面装的是abcdef
Stream<String> stream21 = list6.stream();
//stream2的流和getStream返回的流合并成一个流,里面装的是Character
Stream<Character> stream22 = stream21.flatMap(str -> getStream(str));
stream22.forEach(System.out::println);
System.out.println("===========================================================================================");
/**
* 排序
*/
//sorted()自然排序
List<Integer> inlist = Arrays.asList(12,66,14,78,33,66,11);
inlist.stream().sorted().forEach(System.out::println);
System.out.println("===========================================================================================");
List<Student> sslist = Student.getList();
//会报错,因为我们的Student类并没有实现Comparable接口
//sslist.stream().sorted().forEach(System.out::println);
//System.out.println("===========================================================================================");
//sorted(Comparator com) 自定义规则排序
//自定义规则按年龄排序
sslist.stream().sorted((stu1,stu2)->{
return Integer.compare(stu1.getAge(),stu2.getAge());
}).forEach(System.out::println);
}
//我们自定义一个能返回流的方法
public static Stream<Character> getStream(String str){
ArrayList<Character> list = new ArrayList();
for (Character ch:str.toCharArray()) {
list.add(ch);
}
return list.stream();
}
七:Stream的提交操作
Stream对操作没有提交前所有的操作并未生效执行,只有执行提交操作后所有的操作才会执行,提交之后Stream流会关闭
下面是对流进行提交操作的方法
public static void main(String[] args) {
//提交操作有三种:匹配与查找、规约、收集
/**
* 匹配与查找
*/
List<Student> list = Student.getList();
//allMatch(Predicate) 检查是否匹配所有元素
boolean b = list.stream().allMatch(stu -> stu.getAge() > 30);
System.out.println(b);
System.out.println("========================================================================");
//anyMatch(Predicate) 是否至少有一条匹配
boolean b1 = list.stream().anyMatch(stu -> stu.getAge() > 300);
System.out.println(b1);
System.out.println("========================================================================");
//noneMathce(Predicate)检查是否 没有 匹配的元素 注意是检查是否没有 ,没有返回true
boolean b2 = list.stream().noneMatch(stu -> stu.getAge() > 30);
System.out.println(b2);
System.out.println("========================================================================");
//findFirst返回第一个元素
Optional<Student> opt1 = list.stream().findFirst();
System.out.println(opt1);
System.out.println("========================================================================");
//findAny返回当前流中的任意元素
Optional<Student> any = list.stream().findAny();
System.out.println(any);
System.out.println("========================================================================");
//count 返回流中的元素总数
long count = list.stream().count();
System.out.println(count);
System.out.println("========================================================================");
//max(Comparator) 返回流中最大值
Optional<Integer> max = list.stream().map(stu -> stu.getAge()).max((age1, age2) -> Integer.compare(age1, age2));
System.out.println(max);
System.out.println("========================================================================");
//min(Comparator)返回六种最小值
Optional<Integer> min = list.stream().map(stu -> stu.getAge()).min((age1, age2) -> Integer.compare(age1, age2));
System.out.println(min);
System.out.println("========================================================================");
//forEach(Consumer c) 内部迭代所有元素
list.stream().forEach(stu->System.out.println(stu));
System.out.println("========================================================================");
/**
* 规约---累计计算
*/
//reduce(T,BinaryOperator)
//public interface BinaryOperator<T> extends BiFunction<T,T,T> { 传递两个同类型的参数,返回值还是同一类型
List<Integer> listp = Arrays.asList(1,2,3,4);
//o作为起始值,然后累加集合中的数
Object reduce = listp.stream().reduce(0, (num1, num2) -> num1+num2);
System.out.println(reduce);
System.out.println("========================================================================");
Integer reduce1 = listp.stream().reduce(10, Integer::sum);
System.out.println(reduce1);
Integer reduce2 = listp.stream().reduce(10, (num1, num2) -> num1 * num2);
System.out.println(reduce2);
//reduce(BinaryOperator)
Optional<Integer> reduce3 = list.stream().map(stu -> stu.getAge()).reduce(Integer::sum);
//上面代码可以写成下面这种方式
Optional<Integer> reduce4 = list.stream().map(Student::getAge).reduce(Integer::sum);
System.out.println(reduce3);
System.out.println(reduce4);
/**
*
* 收集
*/
System.out.println("========================================================================");
//collect(Collector c) 将Stream流中的数据转换到其他容器中 蚕食Collerctor可由Collectors的静态方法获取
List<Student> collect = list.stream().collect(Collectors.toList());
collect.forEach(System.out::println);
System.out.println("========================================================================");
Set<Student> collect1 = list.stream().collect(Collectors.toSet());
collect1.forEach(System.out::println);
System.out.println("========================================================================");
}
八:Optional类
Optional类是java.util下面的一个容器类,可以包装其他对象并且可以避免空指针
public class School {
private Student student;
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
}
public static void main(String[] args) {
/**
*
* 创建Optional对象
*/
//Optional.of(T t) t必须非空
Student student = new Student();
Optional<Student> op1 = Optional.of(student);
System.out.println(op1);
System.out.println("=============================================================");
//Optonal.empty() 创建一个空格的Optional实例
Optional<Object> empty = Optional.empty();
System.out.println(empty);
System.out.println("=============================================================");
//Optional.ofNullable(T t) t可以为null
Optional<Student> op2 = Optional.ofNullable(null);
System.out.println(op2);
Optional<Student> op3 = Optional.ofNullable(student);
System.out.println(op3);
System.out.println("=============================================================");
//下面代码会报空指针
// School school = new School();
// getName(school);
System.out.println("=============================================================");
String name = getName2(null);
System.out.println(name+"abc");//nullabc
System.out.println("=============================================================");
String name3 = getName3(null);
System.out.println(name3+"name3");
//如果想精确掌握Optional类,请移步:https://blog.csdn.net/Summer_Lyf/article/details/102975055
}
public static String getName(School school){
return school.getStudent().getName();
}
public static String getName2(Student student){
Optional<Student> optional = Optional.ofNullable(student);
//如果传入的Student不为空则获取传入的,如果为空这new一个,相当于搞一个备胎
Student student1 = optional.orElse(new Student());
return student1.getName();
}
public static String getName3(School school){
Optional<School> op = Optional.ofNullable(school);
if(op.isPresent()){
School sc = op.get();
Optional<Student> op2 =Optional.ofNullable(sc.getStudent());
if(op2.isPresent()){
Student s = op2.get();
return s.getName();
}
}
return null;
}
九:代理模式
静态代理:
缺点:
1.代理类和目标类在编译阶段都已确定,不利于程序的扩张
2.每一个代理类都只能为一个接口服务,会产生大量的代理对象
创建被代理对象
public class MyThread implements Runnable{
@Override
public void run() {
System.out.println("我自己的run方法");
}
}
测试
public static void main(String[] args) {
//被代理类
MyThread m1 = new MyThread();
//代理类
Thread t1 = new Thread(m1);
t1.start();
}
动态代理:程序运行是根据需要动态创建代理对象
十:日期对象
待更新。。。。。