Java8新特性
-
学习的思维:
1大处着眼,小处着手
2意向思维,反证法
List<String> list2;
List<Object> list1 = list2;//为什么保错
3通过问题看本质
-
两句话:
1小不忍则乱大谋
2识时务者为俊杰
-
Java8新特性优点
1 速度更快
2 代码更少(Lambda表达式)
3 强大的Stream API
4 便于并行
5 最大化减少空指针异常:Optional
6 Nashorn引擎,允许在JVM运行JS应用
Lambda表达式
难点:语法层面的改变
为什么使用Lambda表达式:本质原因是别的语言都有,还挺好,自己也就模仿设计了
- 入门案例
package lambda;
import org.junit.Test;
import java.util.Comparator;
public class LambdaInit {
@Test
public void initLambda1(){
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("这是JAVA8之前的匿名函数内部类");
}
};
r1.run();
System.out.println("---------------------------------");
Runnable r2 = () -> System.out.println("这是JAVA8中的Lambda语法实现的效果");
r2.run();
}
@Test
public void initLambda2(){
Comparator<Integer> c1 = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
};
System.out.println("java7:"+c1.compare(22,20));
System.out.println("---------------------------------");
Comparator<Integer> c2 = (o1,o2)->Integer.compare(o1,o2);
System.out.println("java8 lambda:"+c2.compare(20,22));
System.out.println("---------------------------------");
Comparator<Integer> c3 = Integer::compare;
System.out.println("java8 函数引用:"+c3.compare(21,21));
}
}
- Lambda的语法说明
格式:(形参)->{Lambda体}
1.形参为接口中抽象方法的形参
2.->为Lambda操作符
3.Lambda体为实现的抽象方法的方法体
- Lambda的几种语法情况
package lambda;
import org.junit.Test;
import java.util.Comparator;
import java.util.function.Consumer;
public class LambdaInit {
@Test
public void initLambda1(){
//情况一:无参 无返回值
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("这是JAVA8之前的匿名函数内部类");
}
};
r1.run();
System.out.println("---------------------------------");
Runnable r2 = () -> {System.out.println("这是JAVA8中的Lambda语法实现的效果");};
r2.run();
//情况二:有参 无返回值
Consumer<String> consumer1 = new Consumer<String>(){
@Override
public void accept(String str) {
System.out.println(str);
}
};
consumer1.accept("谎言和誓言有什么区别?");
Consumer<String> consumer2 = (String str)->{
System.out.println(str);
};
consumer2.accept("一个是听者相信,一个是说着相信");
//情况三:有参 无返回值 类型推断即省略参数类型:类似的有List集合的实例化省略右侧<>和数组实例化省略new...[],留下{...}
Consumer<String> consumer3 = (str)->{
System.out.println(str);
};
consumer2.accept("一个是听者相信,一个是说着相信");
//情况四:有且仅有一个参数 无返回值 类型推断+省略小括号
Consumer<String> consumer4 = str->{
System.out.println(str);
};
consumer2.accept("一个是听者相信,一个是说着相信");
//情况五:超过一个参数 有返回值 类型推断、不可省略小括号、可省略Lambda体的花括号和return关键字
Comparator<Integer> comparator1 = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
};
System.out.println("java7:"+comparator1.compare(22,20));
System.out.println("---------------------------------");
Comparator<Integer> comparator2 = (o1,o2)->Integer.compare(o1,o2);
System.out.println("java8 lambda:"+comparator2.compare(20,22));
//情况六:超过一个参数 多条返回值 可类型推断、不可省略小括号、不可省略Lambda体的花括号,有返回值不可省略return关键字
Comparator<Integer> comparator3 = (o1,o2)->{
System.out.println("多条语句时");
return Integer.compare(o1,o2);
};
System.out.println("java8 lambda:"+comparator3.compare(20,22));
}
}
函数式接口
-
函数式接口是只有且仅有一个抽象方法的接口
-
@FunctionalInterface注解用于验证是否是函数式接口
-
Lambda表达式依赖于函数式接口,是函数式接口的实例
-
函数式的四大接口
函数式接口 参数类型 返回类型 抽象方法 Consumer T void void accept(T t) Supplier 无 T T get() Function<T,R> T R R apply(T t) Predicate T boolean boolean test(T t) -
其他接口
函数接口 参数类型 返回类型 抽象方法 BiFunction<T,U,R> T,U R R apply(T t,U u) UnaryOperator T T T apply(T t) BinaryOperator T,T T T apply(T t1,T t2) BiConsumer<T,U> U,T void void accept(T t,U u) BiPredicate<T,U> T,U boolean boolean test(T t,U u)
方法引用与构造器引用
-
方法引用的三种方式
1 对象名::方法名
2 类名::静态方法名
3 类名::非静态方法名
-
什么时候可以使用方法引用
情况1,情况2是在抽象方法的返回类型和参数列表和引用方法的返回类型和参数列表一致,可以使用方法引用
情况3是抽象方法的返回类型和引用方法的返回类型相同,参数列表比引用方法多个参数,且第一个参数作为引用方法的调用者,可以使用方法引用
-
方法引用的案例
@Test public void FunctionReference(){ Consumer<String> consumer = new Consumer<String>() { @Override public void accept(String s) { System.out.println(s); } }; consumer.accept("匿名内部类实现"); System.out.println("------------------------------"); Consumer<String> consumer1 = (string)->System.out.println(string); consumer1.accept("Lambda表达式实现"); System.out.println("------------------------------"); /** * 返回类型和参数情况一致,可以使用函数引用 * void accept(T t) * void println(String string) * 对象名::非静态方法 */ PrintStream printStream = System.out; Consumer<String> consumer2 = printStream::println; consumer2.accept("函数引用方式实现"); System.out.println("------------------------------"); Comparator<Integer> comparator = new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return Integer.compare(o1,o2); } }; System.out.println(comparator.compare(11,9)); Comparator<Integer> comparator1 = (o1,o2)->Integer.compare(o1,o2); System.out.println(comparator1.compare(9,9)); /** * Comparator:int compare(Integer o1,Integer o2) * Integer: static int compare(Integer o1,Integer o2) * 返回值和参数一致,可以使用函数引用 * 类名::静态方法名 */ Comparator<Integer> comparator2 = Integer::compare; System.out.println(comparator2.compare(9,11)); System.out.println("------------------------------"); BiPredicate<String,String> biPredicate = new BiPredicate<String, String>() { @Override public boolean test(String s, String s2) { return s.equals(s2); } }; System.out.println(biPredicate.test("abc","abd")); BiPredicate<String,String> biPredicate1 = (s1,s2)->s1.equals(s2); System.out.println(biPredicate1.test("abc","abd")); /** * BiPredicate: boolean test(T t1,D t2) * String: boolean t1.equal(t2) * 类名::非静态方法名 */ BiPredicate<String,String> biPredicate2 = String :: equals; System.out.println(biPredicate2.test("abc","abd")); BiFunction<String,String,Boolean> biFunction = new BiFunction<String, String, Boolean>() { @Override public Boolean apply(String s, String s2) { return s.equals(s2); } }; System.out.println(biFunction.apply("abc","abc")); BiFunction<String,String,Boolean> biFunction1 = String::equals; System.out.println(biFunction1.apply("abc","abc")); }
-
构造器引用
构造器引用时当抽象方法的参数和构造器方法的参数一致,且返回值类型时构造器方法类时可用,返回的实例调用实现的方法返回构造器类的一个实例对象。
@Test public void ConstructorReference(){ /** * 无参构造器 * Supplier: User get() * User: User() */ Supplier<User> supplier = User::new; System.out.println(supplier.get().toString()); /** * 一个参数构造器 * Function: User apply(Integer t) * User: User(Integer age) */ Function<Integer,User> function = User::new; System.out.println(function.apply(22).toString()); /** * 两个参数构造器 * Function: User apply(String name,Integer age) * User: User(String name,Integer age) */ BiFunction<String,Integer,User> function1 = User::new; System.out.println(function1.apply("tom",18).toString()); } class User{ String name; int age; public User(){ System.out.println("无参构造器"); } public User(int age) { this.age = age; System.out.println("一个参数构造器"); } public User(String name, int age) { this.name = name; this.age = age; System.out.println("二个参数构造器"); } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
-
数组引用类比构造器引用
@Test public void ArrayReference(){ /** * Function: String[] apply(Integer length) * String[]: String[](Integer length) */ Function<Integer,String[]> function = String[]::new; String[] strings = function.apply(10); System.out.println(Arrays.toString(strings)); }
-
-
强大的Stream API
-
Stream API把真正的函数编程风格引入到Java中
-
Stream API是对集合数据进行操作,类型于SQL语句查询表操作
-
MySQL和Oracle是关系型数据库,可以在数据库内进行数据处理
-
MongDB和Radis是非关系型数据库,需要在Java层面上数据处理
-
Stream和Collection区别
Collection是一种静态的内存数据结构,与内存相关
Stream是对内存数据结构计算操作,与CPU相关
-
Stream操作的三个步骤
1 创建Stream
一个数据源(如:集合、数组),获取一个流
2 中间操作
一个中间操作链,对数据源的数据进行处理
3 终止操作(终端操作)
一旦执行终止操作,就执行中间操作链,并产生结果,之后不能在使用
-
Stream的三点注意
1 Stream自己不会存储数据
2 Stream不会改变源对象
3 Stream操作延时执行的
-
Stream创建的五种方式
1 通过集合创建Stream
2 通过数组创建Stream
3 通过Stream.of(T t…)创建
4 通过Stream.iterate(final T seed,final UnaryOperator f)
5 通过Stream.generate(Supplier s) 4和5都为无限函数
/** * 流的实例化 * 1.list.stream() * 2.Arrays.stream(array) * 3.Stream.of(T t...) * 4.Stream.iterate(final T seed,UnaryOperator f) * 5.Stream.generate(Supplier s) */ @Test public void test1(){ List<User> users = getUsers(); int[] ints = {2,4,6,8,10}; String[] strings = {"a","b","c","d"}; //列表流化 /** * List.stream() 返回一个顺序流 * 顺序遍历 * List.parallelStream() 返回一个并行流 * 非顺序遍历 */ Stream<User> stream = users.stream(); stream.forEach(System.out::println); Stream<User> stream1 = users.parallelStream(); stream1.forEach(System.out::println); //数组流化 /** * Arrays.stream(数组对象) */ IntStream intStream = Arrays.stream(ints); Stream<String> stringStream = Arrays.stream(strings); intStream.forEach(System.out::println); stringStream.forEach(System.out::println); //其他流化 /** * Stream.of(T t...) */ Stream<String> stringStream1 = Stream.of("g", "h", "i", "j"); stringStream1.forEach(System.out::println); //创造数据流 /** * Stream.iterate(Integer,Consumer consumer) * 参数一为起始种子,参数二根据将起始种子作为lambda参数 * Stream.iterate无限流 */ Stream<Integer> iterate = Stream.iterate(1, num -> num + 2); iterate.limit(10).forEach(System.out::println); Stream<Double> generate = Stream.generate(Math::random); generate.limit(10).forEach(System.out::println); }
-
Stream的筛选和切片
/** * stream.filter(Predicate p) 遍历stream保留为true的数据 * stream.limit(long maxSize) 截取[0,maxSize)部分的数据 * stream.skip(long skip) 跳过skip之前的数据:[skip,-1] * stream.distinct() 去重操作根据equals来去重 */ @Test public void test2(){ List<User> users = getUsers(); users.stream().filter(user-> user.salary>6000).forEach(System.out::println); System.out.println("-------------------------------"); users.stream().limit(2).forEach(System.out::println); System.out.println("-------------------------------"); users.stream().skip(2).forEach(System.out::println); System.out.println("-------------------------------"); users.stream().distinct().forEach(System.out::println); System.out.println("-------------------------------"); }
-
Stream的映射
/** * stream.map(Function f) 遍历流 通过映射函数 返回映射流 * stream.flatMap(Function f) 应用于列表元素为列表或数组,类似于二维数组解析成一维数组的操作 */ @Test public void test3(){ List<User> users = getUsers(); //输出用户列表中名字长度大于3的名字 users.stream().map(user->user.name).filter(name->name.length()>3).forEach(System.out::println); users.stream().flatMap(user->{ String name = user.name; List<Character> characters = new ArrayList<>(); for (char c : name.toCharArray()) { characters.add(c); } return characters.stream(); }).forEach(System.out::println); }
-
stream的排序
/** * stream.sorted() 自然排序 * stream.sorted(Comparator comparator) 比较器顺序排序 */ @Test public void test4(){ Integer[] integers = {10,4,5,6,7,3,2,8}; //调用Integer.compare执行排序 Arrays.stream(integers).sorted().forEach(System.out::println); //User没有默认的compare方法,必须要手动添加比较器 List<User> users = getUsers(); users.stream().sorted((o1,o2)->{ int ageValue = o2.age - o1.age; if(ageValue==0){ return Double.compare(o2.salary,o1.salary); } return ageValue; }).forEach(System.out::println); }
-
stream的匹配与查找
/** * 匹配与查找 * boolean allMatch(Predicate p) p全部为true则为true * boolean anyMatch(Predicate p) p存在true则为true * boolean noneMatch(Predicate p) p全部为false则为true * Optional<T> findFirst() 返回第一个流数据 * Optional<T> findAny() 随机返回一条流数据 * long count() 返回流的长度 * Optional<T> max(Comparator c)返回最大的数据流 * Optional<T> min(Comparator c)返回最小的数据流 * void forEach(Consumer c) 内部迭代 */ @Test public void test5(){ List<User> users = getUsers(); boolean allMatch = users.stream().allMatch(user -> user.age < 30); System.out.println(allMatch); boolean anyMatch = users.stream().anyMatch(user -> user.age > 25); System.out.println(anyMatch); boolean noneMatch = users.stream().noneMatch(user -> user.age==28); System.out.println(noneMatch); Optional<User> first = users.stream().findFirst(); System.out.println(first); Optional<User> any = users.parallelStream().findAny(); System.out.println(any); long count = users.stream().filter(user -> user.salary >= 6000).count(); System.out.println(count); Optional<Double> max = users.stream().map(user -> user.salary).max(Double::compare); System.out.println(max); Optional<User> min = users.stream().min((user1, user2) -> Integer.compare(user1.age, user2.age)); System.out.println(min); users.stream().forEach(System.out::println); }
-
stream的归约
/** * T reduce(T identity, BinaryOperator accumulator) * T reduce(BinaryOperator accumulator) * 归约 多个->一个,如sum */ @Test public void test6(){ //1~10的累加 Integer reduce = Stream.iterate(1, num -> num + 1).limit(10).reduce(0, Integer::sum); System.out.println(reduce); //用户平均薪资 List<User> users = getUsers(); long count = users.stream().count(); Optional<Double> reduce1 = users.stream().map(user -> user.salary).reduce(Double::sum); System.out.println(reduce1); Double avg = reduce1.get()/count; System.out.println(avg); }
-
stream的收集
/** * List stream.collect(Collectors.toList()) stream->list * Set stream.collect(Collectors.toSet()) stream->set * Map<key,value> stream.collect(Collectors.groupingBy()) stream->map 分组 */ @Test public void test7(){ List<User> users = getUsers(); List<User> collect = users.stream().filter(user -> user.salary > 6000).collect(Collectors.toList()); collect.forEach(System.out::println); System.out.println("--------------------------"); Set<User> set = users.stream().collect(Collectors.toSet()); set.forEach(System.out::println); System.out.println("--------------------------"); Map<Integer, List<User>> collect1 = users.stream().collect(Collectors.groupingBy(user -> user.age)); System.out.println(collect1); }
Optional类
-
Optional类的创建
/** * Optional.of(参数不能为空) * Optional.empty() * Optional.ofNullable(参数可以为空) */ @Test public void test1(){ Optional<Girl> optional = Optional.of(new Girl()); Optional<Girl> optional1 = Optional.empty(); Optional<Girl> optional2 = Optional.ofNullable(null); System.out.println(optional); System.out.println(optional1); System.out.println(optional2); }
-
Optional类的使用
/** * Optional.orElse可以在T为null的使用,使用参数作为备胎使用 */ @Test public void test2(){ // Boy boy = null; // Boy boy = new Boy(); Boy boy = new Boy(new Girl("唐悠悠")); Optional<Boy> optional = Optional.ofNullable(boy); Boy boy1 = optional.orElse(new Boy(new Girl("唐嫣"))); Optional<Girl> optional1 = Optional.ofNullable(boy1.getGirl()); Girl girl = optional1.orElse(new Girl("金姐")); System.out.println(girl); }