Java8的新特性.pdf
Lambda表达式
适用于比较简单的结构体。避免匿名内部类定义过多的一种函数式编程思想;
接口中只有一个抽象方法,本质就是作为函数式接口的实例
public class test {public static void main(String[] args) {new Thread(new Runnable() { //实现匿名内部类@Overridepublic void run() {for(int i=0;i<5;i++) {System.out.println("a"+i);}}}).start();for(int i=0;i<5;i++) {System.out.println("b"+i);}}}//jdk8 lambda表达式 一般用于比较简单的线程体public class test {public static void main(String[] args) {new Thread(()->{ //关注线程体for(int i=0;i<5;i++) { //关注内部的核心代码即可 其它的可以简化System.out.println("a"+i);}}).start();for(int i=0;i<5;i++) {System.out.println("b"+i);}}}
推导过程
interface like{void lambda();}//1 接口实现class people1 implements like{@Overridepublic void lambda() {System.out.println("快乐");}}public class lambdaTest {static class people2 implements like{//2 静态内部类实现@Overridepublic void lambda() {System.out.println("快乐2");}}public static void main(String[] args) {like l1 = new people1();like l2 = new people2();like l3 = new like() {//3 匿名内部类实现@Overridepublic void lambda() {System.out.println("快乐3");}};like l4 =()->{//4 lambda表达式实现System.out.println("快乐4");};l1.lambda();l2.lambda();l3.lambda();l4.lambda();}}
带参数
interface habb{void lambda(int a);}class people3 implements habb{@Overridepublic void lambda(int a) {}}public class lambdatest2 {public static void main(String[] args) {habb h1 =(a)->{System.out.println("快乐"+a);};h1.lambda(20);//简化 只有一个参数 可以省略小括号habb h2 =a->{System.out.println("快乐"+a);};h2.lambda(30);//Lambda 体只有一条语句时,return 与大括号若有,都可以省略habb h3 =a->System.out.println("快乐"+a);h3.lambda(50);}}
函数式接口
如果一个接口中,只声明一个抽象方法,则称为函数式接口
可以在接口上用@FunctionalInterface注解检验声明它是一个函数式接口
Java内置四大核心函数式接口
public class testFunction {public static void main(String[] args) {//消费型接口原始写法happyTime(500, new Consumer<Double>() {@Overridepublic void accept(Double aDouble) {System.out.println("???"+aDouble);}});//消费型接口lambda写法happyTime(500, money-> System.out.println("???"+money));List<String> strings = Arrays.asList("a", "b", "ab", "ac");filterStrs(strings,s -> s.contains("a")).forEach(System.out::println);}//消费型接口public static void happyTime(double money, Consumer<Double> consumer){consumer.accept(money);}List<String> list = Arrays.asList("a,aa,ab,ac,bc");List<String> list2 = filterStrs(list, s -> s.contains("c"));//断定型接口//根据指定的规则过滤字符串 规则由Predicate 的方法决定public static List<String> filterStrs(List<String> list, Predicate<String> pre){ArrayList<String> filterList = new ArrayList<>();for (String s : list) {if (pre.test(s)) {filterList.add(s);}}return filterList;}}
方法引用和构造器的引用
方法引用
当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用;
实现接口的抽象方法的参数列表和返回值类型,必须与方法引用的,方法的参数列表和返回值类型保持一致
具体分为如下的三种情况:
对象 :: 非静态方法
类 :: 静态方法
类 :: 非静态方法
public class testFunction2 {//情况一:对象 :: 实例方法@Testpublic void test1(){Consumer c1 = str -> System.out.println(str);c1.accept("hello1");System.out.println("************");Consumer c2= System.out::println;c2.accept("hello2");}//Supplier中的T get()//user中的String getName()@Testpublic void test2() {user u1 = new user("h", 10000.00);// 先有对象后再调用Supplier<String> sup=()->u1.getName();System.out.println(sup.get());System.out.println("************");Supplier<String> sup2=u1::getName;System.out.println(sup2.get());}// 情况二:类 :: 静态方法//Comparator中的int compare(T t1,T t2)//Integer中的int compare(T t1,T t2)@Testpublic void test3(){Comparator<Integer> com1 = (t1, t2) -> Integer.compare(t1,t2);System.out.println(com1.compare(12,21));System.out.println("*******************");Comparator<Integer> com2 = Integer::compare;System.out.println(com2.compare(12,3));}// 情况三:类 :: 实例方法 (前一个参数作为第二个参数的调用者)// Comparator中的int comapre(T t1,T t2)// String中的int t1.compareTo(t2)@Testpublic void test4() {Comparator<String> com1 = (s1,s2) -> s1.compareTo(s2);System.out.println(com1.compare("abc","abd"));System.out.println("*******************");Comparator<String> com2 = String :: compareTo;System.out.println(com2.compare("abd","abm"));}//BiPredicate中的boolean test(T t1, T t2);//String中的boolean t1.equals(t2)@Testpublic void test5() {BiPredicate<String,String> pre1 = (s1, s2) -> s1.equals(s2);System.out.println(pre1.test("abc","abc"));System.out.println("*******************");BiPredicate<String,String> pre2 = String :: equals;System.out.println(pre2.test("abc","abd"));}}
Stream流
使用 Stream对集合数据进行操作计算,可以执行非常复杂的查找、过滤和映射数据等操作
在Java层面对取到的数据流做处理
注:
Stream 自己不会存储元素
Stream 不会改变源对象。相反,它会返回一个持有结果的新Stream
Stream 操作是延迟执行的。等到需要结果的时候才执行(执行终止操作时才执行中间操作链)
Stream 的操作三个步骤
1 创建 Stream
一个数据源(如:集合、数组),获取一个流
2 中间操作
一个中间操作链,对数据源的数据进行处理
3 终止操作(终端操作)
一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会再被使用
创建
public class streamTest {public static List<user> getUsers(){List<user> list = new ArrayList<>();list.add(new user("h",10000.00));list.add(new user("h2",10000.00));list.add(new user("h3",10000.00));return list;}//创建 Stream方式一:通过集合@Testpublic void test1(){List<user> users =streamTest.getUsers();// 返回一个顺序流Stream<user> stream = users.stream();// 返回一个并行流Stream<user> parallelStream = users.parallelStream();}//创建 Stream方式二:通过数组@Testpublic void test2(){int[] arr = new int[]{1,2,3,4,5,6};//调用Arrays类的static <T> Stream<T> stream(T[] array): 返回一个流IntStream stream = Arrays.stream(arr);//自定义类型的数组源user e1 = new user("m",1000);user e2 = new user("h",2000);user[] arr1 = new user[]{e1,e2};Stream<user> stream1 = Arrays.stream(arr1);}//创建 Stream方式三:通过Stream的of()@Testpublic void test3(){Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);}//创建 Stream方式四:创建无限流@Testpublic void test4(){// 迭代//遍历前10个偶数Stream.iterate(0, t -> t + 2).limit(10).forEach(System.out::println);// 生成Stream.generate(Math::random).limit(10).forEach(System.out::println);Stream.generate(()->random.nextInt(10)).limit(10).forEach(System.out::println);}}
中间操作


public static List<user> getUsers(){List<user> list = new ArrayList<>();list.add(new user("aaa",10000.00,21));list.add(new user("bbbb",20000.00,18));list.add(new user("cc",30000.00,29));return list;}#筛选与切片@Testpublic void test5(){Stream<user> stream = streamTest.getUsers().stream();//limit skip distinct 用法差不多stream.filter(user -> user.getSalary()>10000).forEach(System.out::println);}#映射@Testpublic void test6(){// map(Function f)——接收一个函数作为参数,将元素转换成其他形式或提取信息,// 该函数会被应用到每个元素上,并将其映射成一个新的元素。List<String> list = Arrays.asList("aaa", "bb", "cccc", "dd");//消费型接口list.stream().map(str -> str.toUpperCase()).forEach(System.out::println);//匹配名字长度大于2的人员list.stream().map(user::getName).filter(name->name.length()>2).forEach(System.out::println);// flatMap(Function f)接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。// 类似于list的addAll方法 将多维嵌套的数据转换成单维数据Stream<Character> characterStream = list.stream().flatMap(streamTest::fromStringToStream);characterStream.forEach(System.out::println); //获取每个集合中每个字符串的每个字符}//将字符串中的多个字符构成的集合转换为对应的Stream的实例public static Stream<Character> fromStringToStream(String str){ArrayList<Character> list = new ArrayList<>();for(Character c : str.toCharArray()){list.add(c);}return list.stream();}#排序@Testpublic void test7(){// sorted()——自然排序List<Integer> list = Arrays.asList(12, 43, 65, 34, 87, 0, -98, 7);list.stream().sorted().forEach(System.out::println);//sorted(Comparator com) -- 定制排序List<user> users = streamTest.getUsers();users.stream().sorted( (e1,e2) -> {int ageValue = Double.compare(e1.getAge(),e2.getAge());if(ageValue != 0){return ageValue;}else{//年纪相等再比较工资return -Double.compare(e1.getSalary(),e2.getSalary()); //从大到小排序}}).forEach(System.out::println);}
终止操作
终端操作会从流的流水线生成结果。流进行了终止操作后,不能再次使用。



//1-匹配与查找@Testpublic void test11(){List<user> users = streamTest.getUsers();// allMatch(Predicate p)——检查是否匹配所有元素。boolean allMatch = users.stream().allMatch(e -> e.getAge() > 18);System.out.println(allMatch);// findFirst——返回第一个元素Optional<user> user = users.stream().findFirst();System.out.println(user);}@Testpublic void test12(){List<user> users = streamTest.getUsers();// count——返回流中元素的总个数long count = users.stream().filter(e -> e.getSalary() > 5000).count();System.out.println(count);// max(Comparator c)——返回流中最大值Stream<Double> salaryStream = users.stream().map(e -> e.getSalary());Optional<Double> maxSalary = salaryStream.max(Double::compare);System.out.println(maxSalary);// forEach(Consumer c)——内部迭代users.stream().forEach(System.out::println);//使用集合的遍历操作users.forEach(System.out::println);}//2-归约@Testpublic void test13(){// reduce(T identity, BinaryOperator)——可以将流中元素反复结合起来,得到一个值。返回 T// 计算1-10的自然数的和List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);Integer sum = list.stream().reduce(0, Integer::sum);System.out.println(sum);// reduce(BinaryOperator) ——可以将流中元素反复结合起来,得到一个值。返回 Optional<T>// 计算所有员工工资的总和List<user> users = streamTest.getUsers();Stream<Double> salaryStream = users.stream().map(user::getSalary);// Optional<Double> sumMoney = salaryStream.reduce(Double::sum);Optional<Double> sumMoney = salaryStream.reduce((d1, d2) -> d1 + d2);System.out.println(sumMoney.get());}//3-收集@Testpublic void test14(){//collect(Collector c)——将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法//查找工资大于6000的员工,结果返回为一个List或SetList<user> users = streamTest.getUsers();List<user> userList =users.stream().filter(e -> e.getSalary()>6000).collect(Collectors.toList());userList.forEach(System.out::println);Set<user> userSet = users.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toSet());userSet.forEach(System.out::println);}//连接流中每个字符串list.stream().collect(Collectors.joining()); 等价 String.join("", list)
Optional类
是一个容器类,它可以保存类型T的值,代表这个值存在。或者仅仅保存null,表示这个值不存在。原来用null表示一个值不存在,现在Optional可以更好的表达这个概念。并且可以避免空指针异常。
创建Optional类对象的方法:
- Optional.of(T t) :创建一一个 Optional实例,t必须非空;
- Optional.empty() :创建一个空 的Optional 实例
- Optional.ofNullable(T t): t可以为null
判断Optional容器中是否包含对象:
boolean isPresent() :判断是否包含对象
void ifPresent(Consumer<? super T> consumer) :如果有值,就执行Consumer接口的实现代码,并且该值会作为参数传给它。
获取Optional容器的对象:
- T get():如果调用对象包含值,返回该值,否则抛异常
- T orElse(T other): 如果有值则将其返回,否则返回指定的other对象。
- T orElseGet(Supplier<? extends T> other) :如果有值则将其返回,否则返回由Supplier接口实现提供的对象。
- T orElse Throw(Supplier<? extends X> exceptionSupplier) :如果有值则将其返回,否则抛出由Supplier接口实现提供的异常。
#举例 保证当user为空时不影响下面逻辑代码的执行User user = null;User optUser = Optional.ofNullable(user).orElse(new User("a",12));System.out.println(optUser.getName());
