这,仅是我学习过程当中记录的笔记。肯定了一个待研究的主题,对这个主题进行全方面的剖析。笔记是用来方便我回顾与学习的,欢迎你们与我进行交流沟通,共同成长。不止是技术。html
跟大娃一块看,把原来的电脑拿出来放中间看视频用java
--- 之后会有的课程 难度node
先后端分离的开发,是靠node当作中间的spring
netty,已经成为国内外互联网公司的标配。会涉及底层的源代码的理解。sql
JVM 涉及的东西比较多。虽然每天用,可是没有深刻理解过。各类锁,可见性等。与计算机原理息息相关的。express
圣思园主要面对与已经工做的。大部分为一线的开发人员。 课程必定是完整的。由浅入深的。必定要有一种耐心。 对于基础很差的,能够看看之前面授的时候录制的视频。不懂的必定要多查资料。编程
在讲课过程当中的设计思路:4000块钱的收费标准。后端
介绍:Java 8可谓Java语言历史上变化最大的一个版本,其承诺要调整Java编程向着函数式风格迈进,这有助于编写出更为简洁、表达力更强,而且在不少状况下可以利用并行硬件的代码。本门课程将会深刻介绍Java 8新特性,学员将会经过本门课程的学习深刻掌握Java 8新增特性并能灵活运用在项目中。学习者将学习到如何经过Lambda表达式使用一行代码编写Java函数,如何经过这种功能使用新的Stream API进行编程,如何将冗长的集合处理代码压缩为简单且可读性更好的流程序。学习建立和消费流的机制,分析其性能,可以判断什么时候应该调用API的并行执行特性。api
课程的介绍:数组
拉姆达表达式: 函数式编程。之前的叫作命令式的编程。 使用面向对象语言就是来操做数据,封装继承多态。 函数式编程面向的是行为。好处:代码可读性提升。
开发安卓的时候大量的匿名内部类。
提到的关键字: kotlin ,JetBrains 。construction 构造
他之前在学习的时候,翻代码。
将要讲解的各个技术的简介、
课程讲解的时候遇到的工具: Mac , jdk8 ,idea(不少功能是经过插件的形式来实现的)
为何要使用lambda表示式
Java匿名内部类。
匿名内部类的介绍
Gradle的使用。能够彻底使用maven的中央仓库。 进行安卓的开发时,gradle已经成为标配了。
lambda: 匿名内部类
my_jButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.out.println("Button Pressed! "); } });
改造后
my_jButton.addActionListener(e -> System.out.println("Button Pressed!"));
lambda表达式的基本结构:
(param1,param2,param3) ->{ }
函数式编程: 一个接口里边只有一个抽象方法。 能够经过lambda表达式来实例。
关于函数式接口:
经过实例对函数式接口的理解:
package com.erwa.jdk8; @FunctionalInterface interface MyInterface { void test(); // Multiple non-overriding abstract methods found in interface com.erwa.jdk8.MyInterface // void te(); //若是一个接口声明一个抽象方法,可是这个方法重写了 object类中的一个方法. //接口的抽象方法不会加一.因此依然是函数方法. // Object 类是全部类的父类. @Override String toString(); } public class Test2 { public void myTest(MyInterface myInterface) { System.out.println(1); myInterface.test(); System.out.println(2); } public static void main(String[] args) { Test2 test2 = new Test2(); test2.myTest(() -> { System.out.println(3); }); } }
接口里边从1.8开始也能够有方法实现了。default
默认方法。 default void forEach(Consumer<? super T> action) { Objects.requireNonNull(action); for (T t : this) { action.accept(t); } }
* <p>Note that instances of functional interfaces can be created with * lambda expressions, method references, or constructor reference
lambda表达式的做用:
迭代的方式:
list.forEach(System.out::println);
接口中能够有默认方法和静态方法。
流: stream
/** * Returns a sequential {@code Stream} with this collection as its source. * * <p>This method should be overridden when the {@link #spliterator()} * method cannot return a spliterator that is {@code IMMUTABLE}, * {@code CONCURRENT}, or <em>late-binding</em>. (See {@link #spliterator()} * for details.) * * @implSpec * The default implementation creates a sequential {@code Stream} from the * collection's {@code Spliterator}. * * @return a sequential {@code Stream} over the elements in this collection * @since 1.8 */ default Stream<E> stream() { return StreamSupport.stream(spliterator(), false); }
关于流方式实现的举例:
public static void main(String[] args) { //函数式接口的实现方式 MyInterface1 i1 = () -> {}; System.out.println(i1.getClass().getInterfaces()[0]); MyInterface2 i2 = () -> {}; System.out.println(i2.getClass().getInterfaces()[0]); // 没有上下文对象,必定会报错的. // () -> {}; //经过lambda来实现一个线程. new Thread(() -> System.out.println("hello world")).start(); //有一个list ,将内容中的首字母变大写输出. List<String> list = Arrays.asList("hello","world","hello world"); //经过lambda来实现全部字母编程大写输出. // list.forEach(item -> System.out.println(item.toUpperCase())); //把三个单词放入到新的集合里边. List<String> list1 = new ArrayList<>(); //diamond语法. 后边的<>不用再放类型 // list.forEach(item -> list1.add(item.toUpperCase())); // list1.forEach(System.out::println); //进一步的改进. 流的方式 // list.stream();//单线程 // list.parallelStream(); //多线程 list.stream().map(item -> item.toUpperCase()).forEach(System.out::println);//单线程 list.stream().map(String::toUpperCase).forEach(System.out::println); //上边的两种方法,都知足函数式接口的方式. }
lambda表达式的做
lambda基本语法
Java lambda结构
高阶函数: 若是一个函数接收一个函数做为参数,或者返回一个函数做为返回值,那么该函数就叫作高阶函数.
传递行为的举例:
public static void main(String[] args) { // 函数的测试 // 传递行为的一种方式. FunctionTest functionTest = new FunctionTest(); int compute = functionTest.compute(1, value -> 2 * value); System.out.println(compute); System.out.println(functionTest.compute(2,value -> 5+ value)); System.out.println(functionTest.compute(3,a -> a * a)); System.out.println(functionTest.convert(5, a -> a + "hello ")); /** * 高阶函数: * 若是一个函数接收一个函数做为参数,或者返回一个函数做为返回值,那么该函数就叫作高阶函数. */ } //使用lambda表达式的话,能够直觉预约义行为.用的时候传递. // 即 函数式编程. public int compute(int a, Function<Integer, Integer> function) { return function.apply(a); } public String convert(int a, Function<Integer, String> function) { return function.apply(a); } // 以前完成行为的作法. 提早把行为定义好,用的时候调用方法. 如: public int method1(int a ){ return a * 2 ; }
Function类中提供的默认方法的讲解:
/** * Returns a composed function that first applies the {@code before} * function to its input, and then applies this function to the result. * If evaluation of either function throws an exception, it is relayed to * the caller of the composed function. 返回一个组合的函数。对应用完参数后的结果,再次运行apply * * @param <V> the type of input to the {@code before} function, and to the * composed function * @param before the function to apply before this function is applied * @return a composed function that first applies the {@code before} * function and then applies this function * @throws NullPointerException if before is null * * @see #andThen(Function) */ default <V> Function<V, R> compose(Function<? super V, ? extends T> before) { Objects.requireNonNull(before); return (V v) -> apply(before.apply(v)); } /** * Returns a composed function that first applies this function to * its input, and then applies the {@code after} function to the result. * If evaluation of either function throws an exception, it is relayed to * the caller of the composed function. * * @param <V> the type of output of the {@code after} function, and of the * composed function * @param after the function to apply after this function is applied * @return a composed function that first applies this function and then * applies the {@code after} function * @throws NullPointerException if after is null * * @see #compose(Function) */ default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t) -> after.apply(apply(t)); }
compose : 组合function, 造成两个function的串联。 先执行参数
andThen :先应用当前的函数apply,而后再当作参数再次执行apply。 后执行参数。
identity:输入什么返回什么。
BiFunction: 整合两个函数的方法。 为何BiFunction不提供 compose ,只提供andThen呢? 由于若是提供compose方法的话,只能获取一个参数的返回值。不合理。
public static void main(String[] args) { FunctionTest2 functionTest2 = new FunctionTest2(); // compose // System.out.println(functionTest2.compute(2,a -> a * 3,b -> b * b)); // andThen // System.out.println(functionTest2.compute2(2,a -> a * 3,b -> b * b)); //BiFunction // System.out.println(functionTest2.compute3(1,2, (a,b) -> a - b)); // System.out.println(functionTest2.compute3(1,2, (a,b) -> a * b)); // System.out.println(functionTest2.compute3(1,2, (a,b) -> a + b)); // System.out.println(functionTest2.compute3(1,2, (a,b) -> a / b)); //BiFunction andThen System.out.println(functionTest2.compute4(2,3,(a,b) ->a + b , a -> a * a )); } //compose : 组合function, 造成两个function的串联。 先执行参数 //andThen :先应用当前的函数apply,而后再当作参数再次执行apply。 后执行参数 public int compute(int a, Function<Integer, Integer> function1, Function<Integer, Integer> function2) { return function1.compose(function2).apply(a); } public int compute2(int a, Function<Integer, Integer> function1, Function<Integer, Integer> function2) { return function1.andThen(function2).apply(a); } //BiFunction //求两个参数的和 //先定义一个抽象的行为. public int compute3(int a, int b, BiFunction<Integer, Integer, Integer> biFunction) { return biFunction.apply(a, b); } //BiFunction andThen public int compute4(int a, int b, BiFunction<Integer, Integer, Integer> biFunction, Function<Integer, Integer> function) { return biFunction.andThen(function).apply(a, b); }
测试 函数式接口的实例:
public class PersonTest { public static void main(String[] args) { List<Person> personList = new ArrayList<>(); personList.add(new Person("zhangsan", 20)); personList.add(new Person("zhangsan", 28)); personList.add(new Person("lisi", 30)); personList.add(new Person("wangwu", 40)); PersonTest test = new PersonTest(); //测试 getPersonUsername // List<Person> personList1 = test.getPersonUsername("zhangsan", personList); // personList1.forEach(person -> System.out.println(person.getUsername())); //测试 getPersonByAge List<Person> personByAge = test.getPersonByAge(25, personList); personByAge.forEach(person -> System.out.println(person.getAge())); //测试第三种: 自定义输入行为 List<Person> list = test.getPersonByAge2(20,personList,(age,persons) ->{ return persons.stream().filter(person -> person.getAge() > age).collect(Collectors.toList()); }); list.forEach(person -> System.out.println(person.getAge())); } public List<Person> getPersonUsername(String username, List<Person> personList) { return personList.stream().filter(person -> person.getUsername().equals(username)).collect(Collectors.toList()); } public List<Person> getPersonByAge(int age, List<Person> personList) { //使用BiFunction的方式 // BiFunction<Integer, List<Person>, List<Person>> biFunction = (ageOfPerson, list) -> { // return list.stream().filter(person -> person.getAge() > ageOfPerson ).collect(Collectors.toList()); // }; //变换以后: BiFunction<Integer, List<Person>, List<Person>> biFunction = (ageOfPerson, list) -> list.stream().filter(person -> person.getAge() > ageOfPerson ).collect(Collectors.toList()); return biFunction.apply(age, personList); } //第三种方式, 动做也让用户本身定义传进来 public List<Person> getPersonByAge2(int age ,List<Person> list,BiFunction<Integer,List<Person>,List<Person>> biFunction){ return biFunction.apply(age, list); } }
函数式接口的真谛: 传递的是行为,而不是数据
。
public static void main(String[] args) { //给定一个输入参数,判断是否知足条件,知足的话返回true Predicate<String> predicate = p -> p.length() > 5; System.out.println(predicate.test("nnihaoda")); }
到如今为止,只是讲解了Java.lang.function包下的几个最重要的,常用的方法。
2020年01月01日19:03:33 新的一年开始,记录一下每次学习的时间。
Predicate 谓语。 类中包含的方法:
boolean test(T t);
default Predicate<T> or(Predicate<? super T> other)
default Predicate<T> negate()
default Predicate<T> and(Predicate<? super T> other)
static <T> Predicate<T> isEqual(Object targetRef)
函数式编程,注重传递行为,而不是传递值。
public class PredicateTest2 { /** * 测试Predicate中的test方法 */ public static void main(String[] args) { List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9); PredicateTest2 predicateTest2 = new PredicateTest2(); //获取大于5的数字 predicateTest2.getAllFunction(list,item -> item > 5); System.out.println("--------"); //获取全部的偶数 predicateTest2.getAllFunction(list,item -> item % 2 ==0); System.out.println("--------"); //获取全部的数字 predicateTest2.getAllFunction(list,item -> true); //获取大于5而且是偶数的 System.out.println("--------"); predicateTest2.testAnd(list,item -> item > 5,item -> item % 2 == 0); } public void getAllFunction(List<Integer> list, Predicate<Integer> predicate){ for (Integer integer : list) { if (predicate.test(integer)) { System.out.println(integer); } } } // test or and public void testAnd(List<Integer> list,Predicate<Integer> integerPredicate,Predicate<Integer> integerPredicate1){ for (Integer integer : list) { if (integerPredicate.and(integerPredicate1).test(integer)) { System.out.println(integer); } } } }
lambda表达式到底给咱们带来了什么?原来经过面向对象的时候一个方法只能执行一种功能。如今传递的是行为,一个方法能够屡次调用。
逻辑与或非三种的理解.
Supplier类 供应厂商;供应者 (不接收参数,返回结果)
用于什么场合? 工厂
2020年1月3日08:06:28
BinaryOperator 接口
public class SinaryOpertorTest { public static void main(String[] args) { SinaryOpertorTest sinaryOpertorTest = new SinaryOpertorTest(); System.out.println(sinaryOpertorTest.compute(1,2,(a,b) -> a+b)); System.out.println("-- -- - - - -- -"); System.out.println(sinaryOpertorTest.getMax("hello123","world",(a,b) -> a.length() - b.length())); } private int compute(int a, int b, BinaryOperator<Integer> binaryOperator) { return binaryOperator.apply(a, b); } private String getMax(String a, String b, Comparator<String> comparator) { return BinaryOperator.maxBy(comparator).apply(a, b); } }
Optional final :Optional 不要试图用来当作参数, 通常只用来接收返回值,来规避值的空指针异常的问题。
public class OptionalTest { public static void main(String[] args) { Optional<String> optional = Optional.of("hello"); //不肯定是否为 空是 调用和这个方法 // Optional<String> optional2 = Optional.ofNullable("hello"); // Optional<String> optional1 = Optional.empty(); //过期 // if (optional.isPresent()) { // System.out.println(optional.get()); // } optional.ifPresent(item -> System.out.println(item)); System.out.println(optional.orElse("nihao")); System.out.println(optional.orElseGet(() -> "nihao")); }
public class OptionalTest2 { public static void main(String[] args) { Employee employee = new Employee(); employee.setName("dawa"); Employee employee1 = new Employee(); employee1.setName("erwa"); List<Employee> list = Arrays.asList(employee, employee1); Company company = new Company("gongsi", list); Optional<Company> optionalCompany = Optional.ofNullable(company); System.out.println(optionalCompany.map(company1 -> company1.getList()).orElse(Collections.emptyList())); } }
2020你还不会Java8新特性?方法引用详解及Stream 流介绍和操做方式详解(三)
方法引用: method reference
方法引用其实是Lambda表达式的一种语法糖
咱们能够将方法引用看做是一个「函数指针」,function pointer
public class StudentTest { public static void main(String[] args) { Student student = new Student("zhangsan",10); Student student1 = new Student("lisi",40); Student student2 = new Student("wangwu",30); Student student3 = new Student("zhaoliu",550); List<Student> list = Arrays.asList(student, student2, student3, student1); // list.forEach(item -> System.out.println(item.getName())); //1. 类名 :: 静态方法 // list.sort((studentpar1,studentpar2) -> Student.getStudentByScore(studentpar1,studentpar2)); list.sort(Student::getStudentByScore); list.forEach(item -> System.out.println(item.getScore())); System.out.println(" - - - - - - - -- "); // 2. 引用名(对象名)::实例方法名 StudentMethod studentMethod = new StudentMethod(); list.sort(studentMethod::getStudentBySource); list.forEach(item -> System.out.println(item.getScore())); System.out.println(" - - - -- -- "); // 3. 类名:: 实例方法名 // 这个地方调用的方法只有一个参数,为何还能正常调用呢? 由于调用比较时,第一个对象来调用getStudentByScore1. 第二个对象来当作参数 list.sort(Student::getStudentByScore1); list.forEach(item -> System.out.println(item.getScore())); System.out.println("- - - - - - - -"); // 原生的sort 来举个例子 List<String> list1 = Arrays.asList("da", "era", "a"); // Collections.sort(list1,(city1,city2) -> city1.compareToIgnoreCase(city2)); list1.sort(String::compareToIgnoreCase); list1.forEach(System.out::println); System.out.println("- - - - - - -- "); //4. 构造方法引用 StudentTest studentTest = new StudentTest(); System.out.println(studentTest.getString(String::new)); } public String getString(Supplier<String> supplier) { return supplier.get()+"hello"; } }
defaute method
默认方法是指实现此接口时,默认方法已经被默认实现。
引入默认方法最重要的做用就是Java要保证向后兼容。
情景一: 一个类,实现了两个接口。两个接口中有一个相同名字的默认方法。此时会报错,须要从写这个重名的方法
情景二: 约定:实现类的优先级比接口的优先级要高。 一个类,实现一个接口,继承一个实现类。接口和实现类中有一个同名的方法,此时,此类会使用实现类中的方法。
Collection提供了新的stream()方法。
流不存储值,经过管道的方式获取值。
本质是函数式的,对流的操做会生成一个结果,不过并不会修改底层的数据源,集合能够做为流的底层数据源。
延迟查找,不少流操做(过滤、映射、排序等)等能够延迟实现。
经过流的方式能够更好的操做集合。使用函数式编程更为流程。与lambda表达式搭配使用。
使用链式的调用方式sunc as : stream.xxx().yyy().zzz().count(); 没有count的时候前边的三个方法不会被调用。后续会进行举例。
掌握流经常使用的api,了解底层。
流支持并行化,能够多线程操做。迭代器不支持并行化。
public static void main(String[] args) { IntStream.of(1,2,4,5,6).forEach(System.out::println); IntStream.range(3, 8).forEach(System.out::println); IntStream.rangeClosed(3, 8).forEach(System.out::println); }
public static void main(String[] args) { List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); System.out.println(list.stream().map(i -> i*2).reduce(0,Integer::sum)); }
函数式编程和传统面向对象编程根本上有什么不一样?
传统面向对象编程传递的是数据。函数式编程经过方法传递的是一种行为,行为指导了函数的处理,根据行为对数据进行加工。
public static void main(String[] args) { Stream<String> stream = Stream.of("hello", "world", "hello world"); // String[] stringArray = stream.toArray(length -> new String[length]); //替换成方法引用的方式 --> 构造方法引用. String[] stringArray = stream.toArray(String[]::new); Arrays.asList(stringArray).forEach(System.out::println); System.out.println("- - - - - - - - - - -"); //将流转换成list, 有现成的封装好的方法 Stream<String> stream1 = Stream.of("hello", "world", "hello world"); List<String> collect = stream1.collect(Collectors.toList());// 自己是一个终止操做 collect.forEach(System.out::println); System.out.println("- - - - - - "); //使用原生的 collect 来将流转成List Stream<String> stream2 = Stream.of("hello", "world", "hello world"); // List<String> lis = stream2.collect(() -> new ArrayList(), (theList, item) -> theList.add(item), // (theList1, theList2) -> theList1.addAll(theList2)); // 将上面的转换成方法引用的方式 -- 这种方法很差理解. List<String> list = stream2.collect(LinkedList::new, LinkedList::add, LinkedList::addAll); //这种方法,若是想要返回ArrayList也能够实现. // List<String> list1 = stream2.collect(ArrayList::new, ArrayList::add, ArrayList::addAll); list.forEach(System.out::println); }
public static void main(String[] args) { Stream<String> stream = Stream.of("hello", "world", "hello world"); //将流转换成List 另外一种方法 // List<String> list= stream.collect(Collectors.toCollection(ArrayList::new)); // list.forEach(System.out::println); //将流转成set // Set<String> set = stream.collect(Collectors.toSet()); //转成TreeSet // TreeSet<String> set = stream.collect(Collectors.toCollection(TreeSet::new)); // set.forEach(System.out::println); //转成字符串 String string = stream.collect(Collectors.joining()); System.out.println(string); //Collectors 类中有多重辅助的方法. }
**遇到问题的时候,先思考一下可否用方法引用的方式,使用流的方式来操做。**由于用起来比较简单。
public static void main(String[] args) { //将集合中的每个元素 转换成大写的字母, 给输出来 List<String> list = Arrays.asList("hello","world","hello world"); //转成字符串,而后转成大写. // System.out.println(list.stream().collect(Collectors.joining()).toUpperCase()); //上面的代码 能够转换成下边的代码. // System.out.println(String.join("", list).toUpperCase()); //视频上给出的 仍是List的大写 list.stream().map(String::toUpperCase).collect(Collectors.toList()).forEach(System.out::println); //将集合 的数据给平方一下输出. List<Integer> list1 = Arrays.asList(1, 2, 3, 4, 5); list1.stream().map(item -> item * item).collect(Collectors.toList()).forEach(System.out::println); }
流中的 .map () 方法,是对集合中的每个数据进行一下操做。
public static void main(String[] args) { // 举例: flag 的操做, 打平. 一个集合中有三个数组, 打平以后,三个数组的元素依次排列. Stream<List<Integer>> stream = Stream.of(Arrays.asList(1), Arrays.asList(2, 3), Arrays.asList(4, 5)); //将里边每个ArrayList的数据 作一个平方. 而后打平. 输出一个list stream.flatMap(theList -> theList.stream()).map(item -> item * item).forEach(System.out::println); }
public static void main(String[] args) { // stream 其余方法介绍. // generate(). 生成stream对象 Stream<String> stream = Stream.generate(UUID.randomUUID()::toString); // System.out.println(stream.findFirst().get()); // findFirst,找到第一个对象.而后就短路了,会返回一个Optional对象(为了不NPE),不符合函数式编程 // stream.findFirst().isPresent(System.out::print); // iterate() 会生成 一个 无限的串行流. // 通常不会单独使用. 会使用limit 来限制一下总长度. Stream.iterate(1, item -> item + 2).limit(6).forEach(System.out::println); }
Stream<Integer> stream = Stream.iterate(1, item -> item + 2).limit(6); //找出该流中大于2的元素,先使用filter()过滤. //每一个元素*2 使用mapToInt 避免重复拆箱. //忽略掉流中的前两个元素; 使用 skip(2) //再取流中的前两个元素; 使用limit(2) //求出流元素中的总和. 使用sum() System.out.println(stream.filter(item -> item>2).mapToInt(item -> item * 2).skip(2).limit(2).sum());
// .min() 返回的是IntOptional. // System.out.println(stream.filter(item -> item>2).mapToInt(item -> item * 2).skip(2).limit(2).min()); //应该这样调用. 上边的可能会出NPE异常 stream.filter(item -> item>2).mapToInt(item -> item * 2).skip(2).limit(2).min().ifPresent(System.out::println);
在练习的过程当中发现了一个问题。若是是这样连续打印两条对流操做以后的结果。会报流未关闭的异常。
如何避免:使用方法链的方式来处理流。 具体出现的缘由,后续进行详细的源码讲解。
public static void main(String[] args) { List<String> list = Arrays.asList("hello", "world", "hello world"); //首字母转大写 list.stream().map(item ->{ String s = item.substring(0, 1).toUpperCase() + item.substring(1); System.out.println("test"); return s; }).forEach(System.out::println); //没有遇到停止操做时,是不会执行中间操做的.是延迟的 // 遇到.forEach() 停止操做时,才会执行中间操做的代码 }
//程序不会中止 IntStream.iterate(0,i->(i+1)%2).distinct().limit(6).forEach(System.out::println); //程序会中止 IntStream.iterate(0,i->(i+1)%2).limit(6).distinct().forEach(System.out::println);
和迭代器不一样的是,Stream能够并行化操做,迭代器只能命令式地、串行化操做
当使用穿行方式去遍历时,每一个item读完后再读下一个item
使用并行去遍历时,数据会被分红多个段,其中每个都在不一样的线程中处理,而后将结果一块儿输出。
Stream的并行操做依赖于Java7中引入的Fork/Join框架。
描述性的语言:sql和Stream的对比
select name from student where age > 20 and address = 'beijing' order by desc;
===================================================================================
Student.stream().filter(student -> student.getAge >20 ).filter(student -> student.getAddress().equals("beijing")).sorted(..).forEach(student -> System.out.println(student.getName));
上述的描述,并无明确的告诉底层具体要怎么作,只是发出了描述性的信息。这种流的方式就叫作内部迭代。针对于性能来讲,流的操做确定不会下降性能。
外边迭代举例: jdk8之前的用的方式。
List<Student> list = new ArrayList<>();
for(int i = 0 ;i <= students.size();i++){
Student student = students.get(i);
If(student.getAge() > 20 )
list.add(student);
}
Collections.sort(list.....)
list.forEach().....
Stream的出现和集合是密不可分的。
集合关注的是数据与数据存储自己,流关注的则是对数据的计算。
流与迭代器相似的一点是:流是没法重复使用或消费的。
中间操做都会返回一个Stream对象,好比说返回Stream<Student>,Stream<Integer>,Stream<String>;
停止操做则不会返回Stream类型,可能不返回值,也可能返回其余类型的单个值。
public static void main(String[] args) { // 串行流和并行流的比较 List<String> list = new ArrayList<>(5000000); for (int i = 0; i < 5000000; i++) { list.add(UUID.randomUUID().toString()); } System.out.println("开始排序"); long startTime = System.nanoTime(); // list.parallelStream().sorted().count(); //串行流 list.parallelStream().sorted().count(); //并行流 long endTime = System.nanoTime(); long millis = TimeUnit.NANOSECONDS.toMillis(endTime - startTime); System.out.println("排序时间为: "+ millis); }
结果如图,并行流和串行流时间上错了4倍。
public static void main(String[] args) { List<String> list = Arrays.asList("hello", "world", "hello world"); // list.stream().mapToInt(item -> item.length()).filter(length -> length ==5) // .findFirst().ifPresent(System.out::println); list.stream().mapToInt(item -> { int length = item.length(); System.out.println(item); return length; }).filter(length -> length == 5).findFirst().ifPresent(System.out::println); //返回的是hello , 不包含 world. }
返回的是hello , 不包含 world.
流的操做原理: 把流想成一个容器,里边存储的是对每个元素的操做。操做时,把操做串行化。对同一个元素进行串行的操做。操做中还包含着短路操做。
public static void main(String[] args) { //举例; 找出 这个集合中全部的单词,并且要去重. List<String> list = Arrays.asList("hello welcome", "world hello", "hello world", "hello hello world"); // list.stream().map(item -> item.split(" ")).distinct() // .collect(Collectors.toList()).forEach(System.out::println); //使用map不能知足需求, 使用flatMap list.stream().map(item -> item.split(" ")).flatMap(Arrays::stream) .distinct().collect(Collectors.toList()).forEach(System.out::println); //结果为 hello welcome world }
public static void main(String[] args) { //组合起来. 打印出 hi zhangsan , hi lisi , hi wangwu , hello zhangsan , hello lisi .... List<String> list = Arrays.asList("Hi", "Hello", "你好"); List<String> list1 = Arrays.asList("zhangsan", "lisi", "wangwu"); List<String> collect = list.stream().flatMap(item -> list1.stream().map(item2 -> item + " " + item2)).collect(Collectors.toList()); collect.forEach(System.out::println); }
public static void main(String[] args) { //数据准备. Student student1 = new Student("zhangsan", 100, 20); Student student2 = new Student("lisi", 90, 20); Student student3 = new Student("wangwu", 90, 30); Student student4 = new Student("zhangsan", 80, 40); List<Student> students = Arrays.asList(student1, student2, student3, student4); //对学生按照姓名分组. Map<String, List<Student>> listMap = students.stream().collect(Collectors.groupingBy(Student::getName)); System.out.println(listMap); //对学生按照分数分组. Map<Integer, List<Student>> collect = students.stream().collect(Collectors.groupingBy(Student::getScore)); System.out.println(collect); //按照年龄分组. Map<Integer, List<Student>> ageMap = students.stream().collect(Collectors.groupingBy(Student::getAge)); System.out.println(ageMap); //按照名字分组后,获取到每一个分组的元素的个数. Map<String, Long> nameCount = students.stream().collect(Collectors.groupingBy(Student::getName, Collectors.counting())); System.out.println(nameCount); //按照名字分组,求得每一个组的平均值. Map<String, Double> doubleMap = students.stream().collect(Collectors.groupingBy(Student::getName, Collectors.averagingDouble(Student::getScore))); System.out.println(doubleMap); //分区, 分组的一种特例. 只能分两个组 true or flase . partitioning By Map<Boolean, List<Student>> collect1 = students.stream().collect(Collectors.partitioningBy(student -> student.getScore() >= 90)); System.out.println(collect1); }
继续学习Java8 新特性。
jdk8是怎么对底层完成支持的。不了解底层,平时用还能够,可是遇到问题的时候就会卡在那里。迟迟灭有解决方案。在学习一门新技术时,先学习怎么去用,不要执着于源码。可是随着用的愈来愈多,你去了解底层是比较好的一种学习方法。
有多种方法能够实现同一个功能.什么方式更好呢? 越具体的方法越好. 减小自动装箱拆箱操做
/** * A <a href="package-summary.html#Reduction">mutable reduction operation</a> that * accumulates input elements into a mutable result container, optionally transforming * the accumulated result into a final representation after all input elements * have been processed. Reduction operations can be performed either sequentially * or in parallel. Collector做为一个接口。它是一个可变的汇聚操做,将输入元素累计到一个可变的结果容器中;它会在全部元素都处理 完毕后将累计的结果做为一个最终的表示(这是一个可选操做);它支持串行与并行两种方式执行。(并非说并行必定比串行快。) * <p>Examples of mutable reduction operations include: * accumulating elements into a {@code Collection}; concatenating * strings using a {@code StringBuilder}; computing summary information about * elements such as sum, min, max, or average; computing "pivot table" summaries * such as "maximum valued transaction by seller", etc. The class {@link Collectors} * provides implementations of many common mutable reductions. Collects自己提供了关于Collectoe的常见汇聚实现,Collectors自己其实是一个工厂。 * <p>A {@code Collector} is specified by four functions that work together to * accumulate entries into a mutable result container, and optionally perform * a final transform on the result. They are: <ul> * <li>creation of a new result container ({@link #supplier()})</li> * <li>incorporating a new data element into a result container ({@link #accumulator()})</li> * <li>combining two result containers into one ({@link #combiner()})</li> * <li>performing an optional final transform on the container ({@link #finisher()})</li> * </ul> Collector 包含了4个参数 * <p>Collectors also have a set of characteristics, such as * {@link Characteristics#CONCURRENT}, that provide hints that can be used by a * reduction implementation to provide better performance. * * <p>A sequential implementation of a reduction using a collector would * create a single result container using the supplier function, and invoke the * accumulator function once for each input element. A parallel implementation * would partition the input, create a result container for each partition, * accumulate the contents of each partition into a subresult for that partition, * and then use the combiner function to merge the subresults into a combined * result. 举例说明: 1,2, 3, 4 四个部分结果。 1,2 -》 5 5,3 -》 6 6,4 -》 6 ### 同一性和结合性的解析: * <p>To ensure that sequential and parallel executions produce equivalent * results, the collector functions must satisfy an <em>identity</em> and an * <a href="package-summary.html#Associativity">associativity</a> constraints. 为了确保串行和并行的结果一致,须要进行额外的处理。必需要知足两个约束。 identity 同一性 associativity 结合性 * <p>The identity constraint says that for any partially accumulated result, * combining it with an empty result container must produce an equivalent * result. That is, for a partially accumulated result {@code a} that is the * result of any series of accumulator and combiner invocations, {@code a} must * be equivalent to {@code combiner.apply(a, supplier.get())}. 同一性: 对于任何一条并行线路来讲,须要知足a == combiner.apply(a, supplier.get()) * <p>The associativity constraint says that splitting the computation must * produce an equivalent result. That is, for any input elements {@code t1} * and {@code t2}, the results {@code r1} and {@code r2} in the computation * below must be equivalent: * <pre>{@code * A a1 = supplier.get(); 串行: * accumulator.accept(a1, t1); 第一个参数,每次累加的中间结果。 第二个参数,下一个要处理的参数 * accumulator.accept(a1, t2); * R r1 = finisher.apply(a1); // result without splitting * * A a2 = supplier.get(); 并行: * accumulator.accept(a2, t1); 第一个参数,每次累加的中间结果。 第二个参数,下一个要处理的参数 * A a3 = supplier.get(); * accumulator.accept(a3, t2); * R r2 = finisher.apply(combiner.apply(a2, a3)); // result with splitting * } </pre> 结合性: 如上例。 最终要求 r1 == r2 * <p>For collectors that do not have the {@code UNORDERED} characteristic, * two accumulated results {@code a1} and {@code a2} are equivalent if * {@code finisher.apply(a1).equals(finisher.apply(a2))}. For unordered * collectors, equivalence is relaxed to allow for non-equality related to * differences in order. (For example, an unordered collector that accumulated * elements to a {@code List} would consider two lists equivalent if they * contained the same elements, ignoring order.) 对于无序的收集器来讲,等价性就被放松了,会考虑到顺序上的区别对应的不相等性。 两个集合中包含了相同的元素,可是忽略了顺序。这种状况下两个的集合也是等价的。 ### collector复合与注意事项: * <p>Libraries that implement reduction (汇聚) based on {@code Collector}, such as * {@link Stream#collect(Collector)}, must adhere to the following constraints: * <ul> * <li>The first argument passed to the accumulator function, both * arguments passed to the combiner function, and the argument passed to the * finisher function must be the result of a previous invocation of the * result supplier, accumulator, or combiner functions.</li> * <li>The implementation should not do anything with the result of any of * the result supplier, accumulator, or combiner functions other than to * pass them again to the accumulator, combiner, or finisher functions, * or return them to the caller of the reduction operation.</li> 具体的实现来讲,不该该对中间返回的结果进行额外的操做。除了最终的返回的结果。 * <li>If a result is passed to the combiner or finisher * function, and the same object is not returned from that function, it is * never used again.</li> 若是一个结果被传递给combiner or finisher,可是并无返回一个你传递的对象,说明你生成了一个新的结果或者建立了新的对象。这个结果就不会再被使用了。 * <li>Once a result is passed to the combiner or finisher function, it * is never passed to the accumulator function again.</li> 一旦一个结果被传递给了 combiner or finisher 函数,他就不会再被传递给了accumulator函数了。 * <li>For non-concurrent collectors, any result returned from the result * supplier, accumulator, or combiner functions must be serially * thread-confined. This enables collection to occur in parallel without * the {@code Collector} needing to implement any additional synchronization. * The reduction implementation must manage that the input is properly * partitioned, that partitions are processed in isolation, and combining * happens only after accumulation is complete.</li> 线程和线程之间的处理都是独立的,最终结束时再进行合并。 * <li>For concurrent collectors, an implementation is free to (but not * required to) implement reduction concurrently. A concurrent reduction * is one where the accumulator function is called concurrently from * multiple threads, using the same concurrently-modifiable result container, * rather than keeping the result isolated during accumulation. * A concurrent reduction should only be applied if the collector has the * {@link Characteristics#UNORDERED} characteristics or if the * originating data is unordered.</li> 若是不是并发收集器,4个线程会生成4个中间结果。 是并发收集器的话,4个线程会同时调用一个结果容器。 * </ul> * * <p>In addition to the predefined implementations in {@link Collectors}, the * static factory methods {@link #of(Supplier, BiConsumer, BinaryOperator, Characteristics...)} * can be used to construct collectors. For example, you could create a collector * that accumulates widgets into a {@code TreeSet} with: * * <pre>{@code * Collector<Widget, ?, TreeSet<Widget>> intoSet = * Collector.of(TreeSet::new, TreeSet::add, * (left, right) -> { left.addAll(right); return left; }); * }</pre> 经过Collector.of(传进一个新的要操做的元素,结果容器处理的步骤,多线程处理的操做) 将流中的每一个Widget 添加到TreeSet中 * (This behavior is also implemented by the predefined collector * {@link Collectors#toCollection(Supplier)}). * * @apiNote * Performing a reduction operation with a {@code Collector} should produce a * result equivalent to: * <pre>{@code * R container = collector.supplier().get(); * for (T t : data) * collector.accumulator().accept(container, t); * return collector.finisher().apply(container); * }</pre> api的说明: collector的finisher汇聚的实现过程。 * <p>However, the library is free to partition the input, perform the reduction * on the partitions, and then use the combiner function to combine the partial * results to achieve a parallel reduction. (Depending on the specific reduction * operation, this may perform better or worse, depending on the relative cost * of the accumulator and combiner functions.) 性能取决于accumulator and combiner的代价。 也就是说 并行流 并不必定比串行流效率高。 * <p>Collectors are designed to be <em>composed</em>; many of the methods * in {@link Collectors} are functions that take a collector and produce * a new collector. For example, given the following collector that computes * the sum of the salaries of a stream of employees: * <pre>{@code * Collector<Employee, ?, Integer> summingSalaries * = Collectors.summingInt(Employee::getSalary)) * }</pre> 搜集器是能够组合的: take a collector and produce a new collector. 搜集器的实现过程。 如 员工的工资的求和。 * If we wanted to create a collector to tabulate the sum of salaries by * department, we could reuse the "sum of salaries" logic using * {@link Collectors#groupingBy(Function, Collector)}: * <pre>{@code * Collector<Employee, ?, Map<Department, Integer>> summingSalariesByDept * = Collectors.groupingBy(Employee::getDepartment, summingSalaries); * }</pre> 若是咱们想要新建一个搜集器,咱们能够复用以前的搜集器。 实现过程。 * @see Stream#collect(Collector) * @see Collectors * * @param <T> the type of input elements to the reduction operation <T> 表明 流中的每个元素的类型。 * @param <A> the mutable accumulation type of the reduction operation (often * hidden as an implementation detail) <A> 表明 reduction操做的可变容器的类型。表示中间操做生成的结果的类型(如ArrayList)。 * @param <R> the result type of the reduction operation <R> 表明 结果类型 * @since 1.8 */ public interface Collector<T, A, R>{ /** * A function that creates and returns a new mutable result container. * A就表明每一次返回结果的类型 * @return a function which returns a new, mutable result container */ Supplier<A> supplier(); // 提供一个结果容器 /** * A function that folds a value into a mutable result container. * A表明中间操做返回结果的类型。 T是下一个代操做的元素的类型。 * @return a function which folds a value into a mutable result container */ BiConsumer<A, T> accumulator(); //不断的向结果容器中添加元素。 /** * A function that accepts two partial results and merges them. The * combiner function may fold state from one argument into the other and * return that, or may return a new result container. * A 中间操做返回结果的类型。 * @return a function which combines two partial results into a combined * result */ BinaryOperator<A> combiner(); //在多线程中 合并 部分结果。 /** 和并行流紧密相关的 接收两个结果,将两个部分结果合并到一块儿。 combiner函数,有4个线程同时去执行,那么就会有生成4个部分结果。 举例说明: 1,2, 3, 4 四个部分结果。 1,2 -》 5 5,3 -》 6 6,4 -》 6 1,2合并返回5 属于return a new result container. 6,4合并返回6,属于The combiner function may fold state from one argument into the other and return that。 */ /** * Perform the final transformation from the intermediate accumulation type * {@code A} to the final result type {@code R}. *R 是最终返回结果的类型。 * <p>If the characteristic {@code IDENTITY_TRANSFORM} is * set, this function may be presumed to be an identity transform with an * unchecked cast from {@code A} to {@code R}. * * @return a function which transforms the intermediate result to the final * result */ Function<A, R> finisher(); // 合并中间的值,给出返回值。 /** * Returns a {@code Set} of {@code Collector.Characteristics} indicating * the characteristics of this Collector. This set should be immutable. * * @return an immutable set of collector characteristics */ Set<Characteristics> characteristics(); //特征的集合 /** * Returns a new {@code Collector} described by the given {@code supplier}, * {@code accumulator}, and {@code combiner} functions. The resulting * {@code Collector} has the {@code Collector.Characteristics.IDENTITY_FINISH} * characteristic. * * @param supplier The supplier function for the new collector * @param accumulator The accumulator function for the new collector * @param combiner The combiner function for the new collector * @param characteristics The collector characteristics for the new * collector * @param <T> The type of input elements for the new collector * @param <R> The type of intermediate accumulation result, and final result, * for the new collector * @throws NullPointerException if any argument is null * @return the new {@code Collector} */ public static<T, R> Collector<T, R, R> of(Supplier<R> supplier, BiConsumer<R, T> accumulator, BinaryOperator<R> combiner, Characteristics... characteristics) { Objects.requireNonNull(supplier); Objects.requireNonNull(accumulator); Objects.requireNonNull(combiner); Objects.requireNonNull(characteristics); Set<Characteristics> cs = (characteristics.length == 0) ? Collectors.CH_ID : Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH, characteristics)); return new Collectors.CollectorImpl<>(supplier, accumulator, combiner, cs); } /** * Returns a new {@code Collector} described by the given {@code supplier}, * {@code accumulator}, {@code combiner}, and {@code finisher} functions. * * @param supplier The supplier function for the new collector * @param accumulator The accumulator function for the new collector * @param combiner The combiner function for the new collector * @param finisher The finisher function for the new collector * @param characteristics The collector characteristics for the new * collector * @param <T> The type of input elements for the new collector * @param <A> The intermediate accumulation type of the new collector * @param <R> The final result type of the new collector * @throws NullPointerException if any argument is null * @return the new {@code Collector} */ public static<T, A, R> Collector<T, A, R> of(Supplier<A> supplier, BiConsumer<A, T> accumulator, BinaryOperator<A> combiner, Function<A, R> finisher, Characteristics... characteristics) { Objects.requireNonNull(supplier); Objects.requireNonNull(accumulator); Objects.requireNonNull(combiner); Objects.requireNonNull(finisher); Objects.requireNonNull(characteristics); Set<Characteristics> cs = Collectors.CH_NOID; if (characteristics.length > 0) { cs = EnumSet.noneOf(Characteristics.class); Collections.addAll(cs, characteristics); cs = Collections.unmodifiableSet(cs); } return new Collectors.CollectorImpl<>(supplier, accumulator, combiner, finisher, cs); } /** * Characteristics indicating properties of a {@code Collector}, which can * be used to optimize reduction implementations. */ enum Characteristics { // 特征 /** * Indicates that this collector is <em>concurrent</em>, meaning that * the result container can support the accumulator function being * called concurrently with the same result container from multiple * threads. * 并发的,同一个结果容器能够由多个线程同时调用。 * <p>If a {@code CONCURRENT} collector is not also {@code UNORDERED}, * then it should only be evaluated concurrently if applied to an * unordered data source. 若是不是UNORDERED。只能用于无序的数据源。 若是不加CONCURRENT,仍是能够操做并行流。可是操做的不是一个结果容器,而是多个结果容器。则须要调用finisher. 若是加了CONCURRENT,则是多个线程操做同一结果容器。 则无需调用finisher. */ CONCURRENT, /** * Indicates that the collection operation does not commit to preserving * the encounter order of input elements. (This might be true if the * result container has no intrinsic order, such as a {@link Set}.) 收集操做并不保留顺序。 */ UNORDERED, /** * Indicates that the finisher function is the identity function and * can be elided. If set, it must be the case that an unchecked cast * from A to R will succeed. 若是用和这个参数,表示 Finish函数就是 identity函数。 而且转换必定要是成功的。 */ IDENTITY_FINISH } }
static class CollectorImpl<T, A, R> implements Collector<T, A, R>
设计上,自己就是一个辅助类,是一个工厂。做用是给开发者提供常见的收集器实现。提供的方法都是静态方法,能够直接调用。
函数式编程最大的特色:表示作什么,而不是如何作。开发者更注重如作什么,底层实现如何作。
/** * Implementations of {@link Collector} that implement various useful reduction * operations, such as accumulating elements into collections, summarizing * elements according to various criteria, etc. 没有实现的方法,能够本身去编写收集器。 * <p>The following are examples of using the predefined collectors to perform * common mutable reduction tasks: * 举例: * <pre>{@code * // Accumulate names into a List 名字加入到一个集合。 * List<String> list = people.stream().map(Person::getName).collect(Collectors.toList()); * * // Accumulate names into a TreeSet 名字加入到一个Set。 待排序的集合。 * Set<String> set = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new)); * * // Convert elements to strings and concatenate them, separated by commas * String joined = things.stream() * .map(Object::toString) * .collect(Collectors.joining(", ")); * * // Compute sum of salaries of employee 计算员工工资的总数。 * int total = employees.stream() * .collect(Collectors.summingInt(Employee::getSalary))); * * // Group employees by department 对员工进行分组。 * Map<Department, List<Employee>> byDept * = employees.stream() * .collect(Collectors.groupingBy(Employee::getDepartment)); * * // Compute sum of salaries by department 根据部门计算工资的总数。 * Map<Department, Integer> totalByDept * = employees.stream() * .collect(Collectors.groupingBy(Employee::getDepartment, * Collectors.summingInt(Employee::getSalary))); * * // Partition students into passing and failing 将学生进行分区。 * Map<Boolean, List<Student>> passingFailing = * students.stream() * .collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD)); * * }</pre> * * @since 1.8 提供了常见的方法。没有的话能够去自定义。 */ public final class Collectors {
public static void main(String[] args) { Student student1 = new Student("zhangsan", 80); Student student2 = new Student("lisi", 90); Student student3 = new Student("wangwu", 100); Student student4 = new Student("zhaoliu", 90); Student student5 = new Student("zhaoliu", 90); List<Student> students = Arrays.asList(student1, student2, student3, student4, student5); //list 转换成一个流,再转换成一个集合. List<Student> students1 = students.stream().collect(Collectors.toList()); students1.forEach(System.out::println); System.out.println("- - - - - - -"); // collect 方法底层原理介绍. //有多种方法能够实现同一个功能.什么方式更好呢? 越具体的方法越好. 减小自动装箱拆箱操做. System.out.println("count:" + students.stream().collect(Collectors.counting())); System.out.println("count:" + (Long) students.stream().count()); System.out.println("- - - - - - - -"); //举例练习 // 找出集合中分数最低的学生,打印出来. students.stream().collect(minBy(Comparator.comparingInt(Student::getScore))).ifPresent(System.out::println); // 找出集合中分数最大成绩 students.stream().collect(maxBy(Comparator.comparingInt(Student::getScore))).ifPresent(System.out::println); // 求平均值 System.out.println(students.stream().collect(averagingInt(Student::getScore))); // 求分数的综合 System.out.println(students.stream().collect(summingInt(Student::getScore))); // 求各类汇总信息 结果为IntSummaryStatistics{count=5, sum=450, min=80, average=90.000000, max=100} System.out.println(students.stream().collect(summarizingInt(Student::getScore))); System.out.println(" - - - - - "); // 字符串的拼接 结果为:zhangsanlisiwangwuzhaoliuzhaoliu System.out.println(students.stream().map(Student::getName).collect(joining())); //拼接加分隔符 结果为:zhangsan,lisi,wangwu,zhaoliu,zhaoliu System.out.println(students.stream().map(Student::getName).collect(joining(","))); // 拼接加先后缀 结果为:hello zhangsan,lisi,wangwu,zhaoliu,zhaoliu world System.out.println(students.stream().map(Student::getName).collect(joining(",", "hello ", " world"))); System.out.println("- - - - - - "); // group by 多层分组 // 根据分数和名字进行分组 输出结果为: // {80={zhangsan=[Student{name='zhangsan', score=80}]}, // 100={wangwu=[Student{name='wangwu', score=100}]}, // 90={lisi=[Student{name='lisi', score=90}], zhaoliu=[Student{name='zhaoliu', score=90}, Student{name='zhaoliu', score=90}]}} Map<Integer, Map<String, List<Student>>> collect = students.stream().collect(groupingBy(Student::getScore, groupingBy(Student::getName))); System.out.println(collect); System.out.println("- - - - - - - "); // partitioningBy 多级分区 输出结果为:{false=[Student{name='zhangsan', score=80}], true=[Student{name='lisi', score=90}, Student{name='wangwu', score=100}, Student{name='zhaoliu', score=90}, Student{name='zhaoliu', score=90}]} Map<Boolean, List<Student>> collect1 = students.stream().collect(partitioningBy(student -> student.getScore() > 80)); System.out.println(collect1); // 按照大于80分区,再按照90分区 //输出结果为:{false={false=[Student{name='zhangsan', score=80}], true=[]}, true={false=[Student{name='lisi', score=90}, Student{name='zhaoliu', score=90}, Student{name='zhaoliu', score=90}], true=[Student{name='wangwu', score=100}]}} Map<Boolean, Map<Boolean, List<Student>>> collect2 = students.stream().collect(partitioningBy(student -> student.getScore() > 80, partitioningBy(student -> student.getScore() > 90))); System.out.println(collect2); //分区, 而后求出每一个分组中的个数. 结果为:{false=1, true=4} Map<Boolean, Long> collect3 = students.stream().collect(partitioningBy(student -> student.getScore() > 80, counting())); System.out.println(collect3); System.out.println("- - - - - - - "); //根据名字分组,获得学生的分数 --, 使用collectingAndThen 求最小值,而后整合起来. 最后Optional.get()必定有值. students.stream().collect(groupingBy(Student::getName,collectingAndThen(minBy(Comparator.comparingInt(Student::getScore)), Optional::get))); }
Comparator 比较器。引用了多个default方法。
完成一个功能时有多个方法,使用特化的方法。由于效率会更高。减小了装箱拆箱的操做。减小性能损耗。
public static void main(String[] args) { List<String> list = Arrays.asList("nihao", "hello", "world", "welcome"); //对list按照字母的升序排序 // list.stream().sorted().forEach(System.out::println); //按照字符串的长度排序 // Collections.sort(list, (item1, item2) -> item1.length() - item2.length()); // Collections.sort(list, Comparator.comparingInt(String::length)); //字符串的降序排序 // list.sort(Comparator.comparingInt(String::length).reversed()); // 下边的形式会报错 item识别成了(Obejct). //lambda表达式的类型推断. 若是没法推断类型,须要本身制定类型 // list.sort(Comparator.comparingInt(item-> item.length()).reversed()); //这样写就成功了. list.sort(Comparator.comparingInt((String item )-> item.length()).reversed()); //为何这个地方没法推断类型? // 能推断出的 : list.stream().... Strean<T> 传递的有参数. 精确的类型能够进行类型推断. //这个地方没有明确具体是什么类型.ToIntFunction<? super T> .能够是String 或者在往上的父类 这个地方当作了Object类了. // list.sort(Comparator.comparingInt((Boolean item)-> 1).reversed()); //这种Boolean 就会报错.编译不经过. System.out.println(list); }
thenComparing()多级排序的练习。;
List<String> list = Arrays.asList("nihao", "hello", "world", "welcome"); //两层的比较.先按照字符串的长度升序排序. 长度相同,根据每个ASCII码的升序排序. (不区分大小写的 ,按照字母排序的规则) 几种实现的方法。 list.sort(Comparator.comparingInt(String::length).thenComparing(String.CASE_INSENSITIVE_ORDER)); list.sort(Comparator.comparingInt(String::length).thenComparing((item1,item2) -> item1.toUpperCase().compareTo(item2.toUpperCase()))); list.sort(Comparator.comparingInt(String::length).thenComparing(Comparator.comparing(String::toUpperCase))); //排序后将顺序翻转过来. reverseOrder(); list.sort(Comparator.comparingInt(String::length).thenComparing(String::toLowerCase,Comparator.reverseOrder())); // 按照字符串的长度降序排序, 再根据ASCII的降序排序 list.sort(Comparator.comparingInt(String::length).reversed() .thenComparing(String::toLowerCase,Comparator.reverseOrder())); //多级排序 list.sort(Comparator.comparingInt(String::length).reversed() .thenComparing(String::toLowerCase, Comparator.reverseOrder()) .thenComparing(Comparator.reverseOrder())); // 最后一个thenComparing()没有发生做用。
jdk提供了Collector接口。
public class MySetCollector<T> implements Collector<T,Set<T>,Set<T>> { @Override public Supplier<Set<T>> supplier() { //用于提供一个空的容器 System.out.println("supplier invoked! "); return HashSet::new; // 不接受对象,返回一个Set对象 } @Override public BiConsumer<Set<T>, T> accumulator() { // 累加器类型. 接收两个参数不返回值. //完成的功能: 不断的往set中添加元素 System.out.println("accumulator invoked! "); return Set<T>::add ; // return HashSet<T>::add ; 返回HashSet报错. 缘由: 返回的是中间类型的返回类型. 不论返回什么类型的Set ,Set都符合要求. } @Override public BinaryOperator<Set<T>> combiner() { //将并行流的多个结果给合并起来. System.out.println("combiner invoked! "); return (set1,set2)->{ set1.addAll(set2); return set1; }; } @Override public Function<Set<T>, Set<T>> finisher() { //完成器,把全部的结果都合并在一块儿. 返回一个最终的结果类型 //若是中间类型 和最终结果类型一致, 不执行此方法; System.out.println("finisher invoked! "); // return t -> t ; return Function.identity(); // 老是返回参数. } @Override public Set<Characteristics> characteristics() { System.out.println("characterstics invoked! "); return Collections.unmodifiableSet(EnumSet.of(Characteristics.IDENTITY_FINISH,Characteristics.UNORDERED)); // 这个地方 不给参数,IDENTITY_FINISH . 则会调用finisher() } public static void main(String[] args) { List<String> list = Arrays.asList("hello", "world"); Set<String> collect = list.stream().collect(new MySetCollector<>()); System.out.println(collect); } 输出结果为: supplier invoked! accumulator invoked! combiner invoked! characterstics invoked! characterstics invoked! [world, hello] }
接下来跟源码,看一下程序的调用过程。
@Override @SuppressWarnings("unchecked") public final <R, A> R collect(Collector<? super P_OUT, A, R> collector) { A container; if (isParallel() && (collector.characteristics().contains(Collector.Characteristics.CONCURRENT)) && (!isOrdered() || collector.characteristics().contains(Collector.Characteristics.UNORDERED))) { container = collector.supplier().get(); BiConsumer<A, ? super P_OUT> accumulator = collector.accumulator(); forEach(u -> accumulator.accept(container, u)); } else { container = evaluate(ReduceOps.makeRef(collector)); } return collector.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH) ? (R) container : collector.finisher().apply(container); }
// 举例: 需求:将一个Set,进行一个收集.对结果进行加强,封装在一个map当中. // 输入:Set<String> // 输出:Map<String,String> // 示例输入: [hello,world,hello world] // 示例输出: {[hello,hello],[world,world],[hello world,hello world]}
public class MySetCollector2<T> implements Collector<T, Set<T>, Map<T, T>> { @Override public Supplier<Set<T>> supplier() { System.out.println("supplier invoked!"); return HashSet::new; } @Override public BiConsumer<Set<T>, T> accumulator() { System.out.println("accumlator invoked!"); return (set, item) -> { set.add(item); //每次调用 打印出线程 这里会打印6次, System.out.println("accunlator : " +set+ ", "+ Thread.currentThread().getName()); //出现异常的缘由在这里: // 一个线程去修改一个集合,同时另一个线程去迭代它(遍历它)。程序就会抛出并发修改异常。若是是并行操做的话,就不要在操做中额外的添加操做。添加就添加,别再去打印他。 }; } @Override public BinaryOperator<Set<T>> combiner() { System.out.println("combiner invoked!"); //并行流的时候才会被调用. 将并行流的多个结果给合并起来 return (set1, set2) -> { set1.addAll(set2); return set2; }; } @Override public Function<Set<T>, Map<T, T>> finisher() { System.out.println("finisher invoked!"); // 中间类型和最终类型 同样,这个是不会被调用的. //这里不同 . 会进行调用 return set -> { Map<T, T> map = new HashMap<>(); // Map<T, T> map = new TreeMap<>(); 直接返回一个排序的Map set.forEach(item -> map.put(item,item)); return map; }; } @Override public Set<Characteristics> characteristics() { System.out.println(" characteristics invoked"); return Collections.unmodifiableSet(EnumSet.of(Characteristics.UNORDERED));// 这个参数不能乱写. 要理解每一个枚举的具体意思. // return Collections.unmodifiableSet(EnumSet.of(Characteristics.UNORDERED,Characteristics.CONCURRENT));// 这个参数不能乱写. 要理解每一个枚举的具体意思. //加了这个参数 Characteristics.CONCURRENT // 会出异常, 会正常运行. Caused by: java.util.ConcurrentModificationException // return Collections.unmodifiableSet(EnumSet.of(Characteristics.UNORDERED,Characteristics.IDENTITY_FINISH)); // 加了参数Characteristics.IDENTITY_FINISH . 会报错 // Process 'command '/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/bin/java'' finished with non-zero exit value 1 // IDENTITY_FINISH 实际的含义: 若是用和这个参数,表示 Finish函数就是 identity函数。 而且转换必定要是成功的。失败的话会抛异常. // 这个收集器具备什么特性 ,由Characteristics 来定义. 就算你赋值的不实际,他也照样执行. } public static void main(String[] args) { List<String> list = Arrays.asList("hello","hello", "world", "helloworld","1","4","j"); Set<String> set = new HashSet<>(list); System.out.println("set"+set); // Map<String, String> collect = set.stream().collect(new MySetCollector2<>()); Map<String, String> collect = set.parallelStream().collect(new MySetCollector2<>()); //并行流 System.out.println(collect); } }
并行: accumlator invoked! accunlator : [j], main accunlator : [j, hello], main accunlator : [helloworld, 4, j, hello], ForkJoinPool.commonPool-worker-2 accunlator : [helloworld, 1, 4, j, hello], ForkJoinPool.commonPool-worker-2 accunlator : [helloworld, 1, world, 4, j, hello], ForkJoinPool.commonPool-worker-2
串行。 accunlator : [j], main accunlator : [helloworld], ForkJoinPool.commonPool-worker-11 accunlator : [helloworld, 1], ForkJoinPool.commonPool-worker-11 accunlator : [helloworld, 1, world], ForkJoinPool.commonPool-worker-11 accunlator : [4], ForkJoinPool.commonPool-worker-9 accunlator : [j, hello], main
/** * Characteristics indicating properties of a {@code Collector}, which can * be used to optimize reduction implementations. */ enum Characteristics { // 特征 /** * Indicates that this collector is <em>concurrent</em>, meaning that * the result container can support the accumulator function being * called concurrently with the same result container from multiple * threads. * 并发的,同一个结果容器能够由多个线程同时调用。 * <p>If a {@code CONCURRENT} collector is not also {@code UNORDERED}, * then it should only be evaluated concurrently if applied to an * unordered data source. 若是不是UNORDERED。只能用于无序的数据源。 若是不加CONCURRENT,仍是能够操做并行流。可是操做的不是一个结果容器,而是多个结果容器。则须要调用finisher. 若是加了CONCURRENT,则是多个线程操做同一结果容器。 则无需调用finisher. */ CONCURRENT, /** * Indicates that the collection operation does not commit to preserving * the encounter order of input elements. (This might be true if the * result container has no intrinsic order, such as a {@link Set}.) 收集操做并不保留顺序。无序的。 */ UNORDERED, /** * Indicates that the finisher function is the identity function and * can be elided. If set, it must be the case that an unchecked cast * from A to R will succeed. 若是用和这个参数,表示 Finish函数就是 identity函数。 而且转换必定要是成功的。不会调用Finish方法 */ IDENTITY_FINISH }
一个线程去修改一个集合,同时另一个线程去迭代它(遍历它)。程序就会抛出并发修改异常。
若是是并行操做的话,就不要在操做中额外的添加操做。添加就添加,别再去打印他。
若是不加CONCURRENT,仍是能够操做并行流。可是操做的不是一个结果容器,而是多个结果容器。则须要调用finisher. 若是加了CONCURRENT,则是多个线程操做同一结果容器。 则无需调用finisher.
超线程(HT, Hyper-Threading)是英特尔研发的一种技术,于2002年发布。超线程技术原先只应用于Xeon 处理器中,当时称为“Super-Threading”。以后陆续应用在Pentium 4 HT中。早期代号为Jackson。 [1]
经过此技术,英特尔实如今一个实体CPU中,提供两个逻辑线程。以后的[Pentium D](https://baike.baidu.com/item/Pentium D)纵使不支持超线程技术,但就集成了两个实体核心,因此仍会见到两个线程。超线程的将来发展,是提高处理器的逻辑线程。英特尔于2016年发布的Core i7-6950X即是将10核心的处理器,加上超线程技术,使之成为20个逻辑线程的产品
Collectors类中方法的实现练习。收集器老是有中间的容器。有必要的总结一下收集器中的方法。
当你具有一些前提的东西以后,你再去看难的东西就会以为理所固然的。
对于Collectors静态工厂类来讲,实现一共分为两种状况:
经过CollectorImpl来实现。
经过reducing方法来实现;reducing方法自己又是经过CollectorImpl实现的。
总的来讲,都是经过CollectorImpl来实现的。
1. toCollection(collectionFactory) 。 将集合转成指定的集合。 public static <T, C extends Collection<T>> Collector<T, ?, C> toCollection(Supplier<C> collectionFactory) { return new CollectorImpl<>(collectionFactory, Collection<T>::add, (r1, r2) -> { r1.addAll(r2); return r1; }, CH_ID); }
2. toList()是 toCollection()方法的一种具体实现。 public static <T> Collector<T, ?, List<T>> toList() { return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add, (left, right) -> { left.addAll(right); return left; }, CH_ID); }
3. toSet() 是toCollection()方法的一种具体实现。 public static <T> Collector<T, ?, Set<T>> toSet() { return new CollectorImpl<>((Supplier<Set<T>>) HashSet::new, Set::add, (left, right) -> { left.addAll(right); return left; }, CH_UNORDERED_ID); }
4. joining(); 融合成一个字符串。还有两个重载的,单参数的和多参数的 public static Collector<CharSequence, ?, String> joining() { return new CollectorImpl<CharSequence, StringBuilder, String>( StringBuilder::new, StringBuilder::append, (r1, r2) -> { r1.append(r2); return r1; }, StringBuilder::toString, CH_NOID); } public static Collector<CharSequence, ?, String> joining(CharSequence delimiter) { return joining(delimiter, "", ""); } public static Collector<CharSequence, ?, String> joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix) { return new CollectorImpl<>( () -> new StringJoiner(delimiter, prefix, suffix), StringJoiner::add, StringJoiner::merge, StringJoiner::toString, CH_NOID); }
5.mapping(); 将收集器的A 映射成B public static <T, U, A, R> Collector<T, ?, R> mapping(Function<? super T, ? extends U> mapper, Collector<? super U, A, R> downstream) { BiConsumer<A, ? super U> downstreamAccumulator = downstream.accumulator(); return new CollectorImpl<>(downstream.supplier(), (r, t) -> downstreamAccumulator.accept(r, mapper.apply(t)), downstream.combiner(), downstream.finisher(), downstream.characteristics()); } such as : Map<City, Set<String>> lastNamesByCity = people.stream().collect(groupingBy(Person::getCity, mapping(Person::getLastName, toSet())));
6.collectingAndThen(); 收集处理转换完后, 再去进行一个转换。 public static<T,A,R,RR> Collector<T,A,RR> collectingAndThen(Collector<T,A,R> downstream, Function<R,RR> finisher) { Set<Collector.Characteristics> characteristics = downstream.characteristics(); if (characteristics.contains(Collector.Characteristics.IDENTITY_FINISH)) { if (characteristics.size() == 1) characteristics = Collectors.CH_NOID; else { characteristics = EnumSet.copyOf(characteristics); characteristics.remove(Collector.Characteristics.IDENTITY_FINISH); // 这个地方为何要把IDENTITY_FINISH 去掉。 // 若是不去掉的话, 最终结果直接返回中间结果的类型 characteristics = Collections.unmodifiableSet(characteristics); } } return new CollectorImpl<>(downstream.supplier(), downstream.accumulator(), downstream.combiner(), downstream.finisher().andThen(finisher), characteristics); } such as : List<String> people = people.stream().collect(collectingAndThen(toList(),Collections::unmodifiableList));
7. counting(); 计数。 public static <T> Collector<T, ?, Long> counting() { return reducing(0L, e -> 1L, Long::sum); }
8. 最大值最小值 public static <T> Collector<T, ?, Optional<T>> minBy(Comparator<? super T> comparator) { return reducing(BinaryOperator.minBy(comparator)); } public static <T> Collector<T, ?, Optional<T>> maxBy(Comparator<? super T> comparator) { return reducing(BinaryOperator.maxBy(comparator)); }
9. summingInt();求和。 public static <T> Collector<T, ?, Integer> summingInt(ToIntFunction<? super T> mapper) { return new CollectorImpl<>( () -> new int[1], // 这个地方为何不能够用一个0,来当作中间类型呢?数字自己是一个值类型的,不可变的,无法引用。数组自己是一个引用类型,能够进行传递。数组自己是一个容器。 (a, t) -> { a[0] += mapper.applyAsInt(t); }, (a, b) -> { a[0] += b[0]; return a; }, a -> a[0], CH_NOID); } public static <T> Collector<T, ?, Long> summingLong(ToLongFunction<? super T> mapper) { return new CollectorImpl<>( () -> new long[1], (a, t) -> { a[0] += mapper.applyAsLong(t); }, (a, b) -> { a[0] += b[0]; return a; }, a -> a[0], CH_NOID); } public static <T> Collector<T, ?, Double> summingDouble(ToDoubleFunction<? super T> mapper) { /* * In the arrays allocated for the collect operation, index 0 * holds the high-order bits of the running sum, index 1 holds * the low-order bits of the sum computed via compensated * summation, and index 2 holds the simple sum used to compute * the proper result if the stream contains infinite values of * the same sign. */ return new CollectorImpl<>( () -> new double[3], (a, t) -> { sumWithCompensation(a, mapper.applyAsDouble(t)); a[2] += mapper.applyAsDouble(t);}, (a, b) -> { sumWithCompensation(a, b[0]); a[2] += b[2]; return sumWithCompensation(a, b[1]); }, a -> computeFinalSum(a), CH_NOID); }
10. averagingInt(); 求平均值。 public static <T> Collector<T, ?, Double> averagingInt(ToIntFunction<? super T> mapper) { return new CollectorImpl<>( () -> new long[2], (a, t) -> { a[0] += mapper.applyAsInt(t); a[1]++; }, (a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; }, a -> (a[1] == 0) ? 0.0d : (double) a[0] / a[1], CH_NOID); } public static <T> Collector<T, ?, Double> averagingLong(ToLongFunction<? super T> mapper) { return new CollectorImpl<>( () -> new long[2], (a, t) -> { a[0] += mapper.applyAsLong(t); a[1]++; }, (a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; }, a -> (a[1] == 0) ? 0.0d : (double) a[0] / a[1], CH_NOID); } public static <T> Collector<T, ?, Double> averagingDouble(ToDoubleFunction<? super T> mapper) { /* * In the arrays allocated for the collect operation, index 0 * holds the high-order bits of the running sum, index 1 holds * the low-order bits of the sum computed via compensated * summation, and index 2 holds the number of values seen. */ return new CollectorImpl<>( () -> new double[4], (a, t) -> { sumWithCompensation(a, mapper.applyAsDouble(t)); a[2]++; a[3]+= mapper.applyAsDouble(t);}, (a, b) -> { sumWithCompensation(a, b[0]); sumWithCompensation(a, b[1]); a[2] += b[2]; a[3] += b[3]; return a; }, a -> (a[2] == 0) ? 0.0d : (computeFinalSum(a) / a[2]), CH_NOID); }
11. reducing() ; 详解。 public static <T> Collector<T, ?, T> reducing(T identity, BinaryOperator<T> op) { return new CollectorImpl<>( boxSupplier(identity), (a, t) -> { a[0] = op.apply(a[0], t); }, (a, b) -> { a[0] = op.apply(a[0], b[0]); return a; }, a -> a[0], CH_NOID); }
12. groupingBy(); 分组方法详解。 public static <T, K> Collector<T, ?, Map<K, List<T>>> //使用者自己不注重中间类型怎么操做。 groupingBy(Function<? super T, ? extends K> classifier) { return groupingBy(classifier, toList()); //调用两个参数的 groupingBy(); } * @param <T> the type of the input elements //T; 接收的类型。 * @param <K> the type of the keys // K,分类器函数中间返回结果的类型。 * @param <A> the intermediate accumulation type of the downstream collector * @param <D> the result type of the downstream reduction * public static <T, K, A, D> Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier, Collector<? super T, A, D> downstream) { return groupingBy(classifier, HashMap::new, downstream); // 调用三参数的 groupingBy() } //功能最彻底的groupingBy(); /** * Returns a {@code Collector} implementing a cascaded "group by" operation * on input elements of type {@code T}, grouping elements according to a * classification function, and then performing a reduction operation on * the values associated with a given key using the specified downstream * {@code Collector}. The {@code Map} produced by the Collector is created * with the supplied factory function. * * <p>The classification function maps elements to some key type {@code K}. * The downstream collector operates on elements of type {@code T} and * produces a result of type {@code D}. The resulting collector produces a * {@code Map<K, D>}. * * <p>For example, to compute the set of last names of people in each city, * where the city names are sorted: * <pre>{@code * Map<City, Set<String>> namesByCity * = people.stream().collect(groupingBy(Person::getCity, TreeMap::new, * mapping(Person::getLastName, toSet()))); * }</pre> * * @implNote * The returned {@code Collector} is not concurrent. For parallel stream * pipelines, the {@code combiner} function operates by merging the keys * from one map into another, which can be an expensive operation. If * preservation of the order in which elements are presented to the downstream * collector is not required, using {@link #groupingByConcurrent(Function, Supplier, Collector)} * may offer better parallel performance. * 返回的 并非并发的。若是顺序并非很重要的话, 推荐使用groupingByConcurrent(); 并发的分组函数。 * @param <T> the type of the input elements * @param <K> the type of the keys * @param <A> the intermediate accumulation type of the downstream collector * @param <D> the result type of the downstream reduction * @param <M> the type of the resulting {@code Map} * @param classifier a classifier function mapping input elements to keys * @param downstream a {@code Collector} implementing the downstream reduction * @param mapFactory a function which, when called, produces a new empty * {@code Map} of the desired type * @return a {@code Collector} implementing the cascaded group-by operation * * @see #groupingBy(Function, Collector) * @see #groupingBy(Function) * @see #groupingByConcurrent(Function, Supplier, Collector) */ public static <T, K, D, A, M extends Map<K, D>> Collector<T, ?, M> groupingBy(Function<? super T, ? extends K> classifier, Supplier<M> mapFactory, Collector<? super T, A, D> downstream) { Supplier<A> downstreamSupplier = downstream.supplier(); BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator(); BiConsumer<Map<K, A>, T> accumulator = (m, t) -> { K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key"); A container = m.computeIfAbsent(key, k -> downstreamSupplier.get()); downstreamAccumulator.accept(container, t); }; BinaryOperator<Map<K, A>> merger = Collectors.<K, A, Map<K, A>>mapMerger(downstream.combiner()); //接收两个参数,参会一个结果。 @SuppressWarnings("unchecked") Supplier<Map<K, A>> mangledFactory = (Supplier<Map<K, A>>) mapFactory; // 进行一个强制的类型转换。 if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) { //若是 IDENTITY_FINISH , 则不用调用finisher方法。 return new CollectorImpl<>(mangledFactory, accumulator, merger, CH_ID); } else { @SuppressWarnings("unchecked") Function<A, A> downstreamFinisher = (Function<A, A>) downstream.finisher(); Function<Map<K, A>, M> finisher = intermediate -> { intermediate.replaceAll((k, v) -> downstreamFinisher.apply(v)); @SuppressWarnings("unchecked") M castResult = (M) intermediate; return castResult; }; return new CollectorImpl<>(mangledFactory, accumulator, merger, finisher, CH_NOID); } }
13. groupingByConcurrent(); 并发的分组方法。 使用前提是对数据里边的顺序没有要求。 /** * Returns a concurrent {@code Collector} implementing a cascaded "group by" * operation on input elements of type {@code T}, grouping elements * according to a classification function, and then performing a reduction * operation on the values associated with a given key using the specified * downstream {@code Collector}. */ // ConcurrentHashMap 是一个支持并发的Map public static <T, K> Collector<T, ?, ConcurrentMap<K, List<T>>> groupingByConcurrent(Function<? super T, ? extends K> classifier) { return groupingByConcurrent(classifier, ConcurrentHashMap::new, toList()); } public static <T, K, A, D> Collector<T, ?, ConcurrentMap<K, D>> groupingByConcurrent(Function<? super T, ? extends K> classifier, Collector<? super T, A, D> downstream) { return groupingByConcurrent(classifier, ConcurrentHashMap::new, downstream); } public static <T, K, A, D, M extends ConcurrentMap<K, D>> Collector<T, ?, M> groupingByConcurrent(Function<? super T, ? extends K> classifier, Supplier<M> mapFactory, Collector<? super T, A, D> downstream) { Supplier<A> downstreamSupplier = downstream.supplier(); BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator(); BinaryOperator<ConcurrentMap<K, A>> merger = Collectors.<K, A, ConcurrentMap<K, A>>mapMerger(downstream.combiner()); @SuppressWarnings("unchecked") Supplier<ConcurrentMap<K, A>> mangledFactory = (Supplier<ConcurrentMap<K, A>>) mapFactory; BiConsumer<ConcurrentMap<K, A>, T> accumulator; if (downstream.characteristics().contains(Collector.Characteristics.CONCURRENT)) { accumulator = (m, t) -> { K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key"); A resultContainer = m.computeIfAbsent(key, k -> downstreamSupplier.get()); downstreamAccumulator.accept(resultContainer, t); }; } else { accumulator = (m, t) -> { K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key"); A resultContainer = m.computeIfAbsent(key, k -> downstreamSupplier.get()); synchronized (resultContainer) { // 这里有一个同步的操做。虽然是多线程操做同一容器,可是同时仍是只有一个线程操做,进行了同步。 downstreamAccumulator.accept(resultContainer, t); } }; } if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) { return new CollectorImpl<>(mangledFactory, accumulator, merger, CH_CONCURRENT_ID); } else { @SuppressWarnings("unchecked") Function<A, A> downstreamFinisher = (Function<A, A>) downstream.finisher(); Function<ConcurrentMap<K, A>, M> finisher = intermediate -> { intermediate.replaceAll((k, v) -> downstreamFinisher.apply(v)); @SuppressWarnings("unchecked") M castResult = (M) intermediate; return castResult; }; return new CollectorImpl<>(mangledFactory, accumulator, merger, finisher, CH_CONCURRENT_NOID); } }
14. partitioningBy(); 分区详解。 public static <T> Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate) { return partitioningBy(predicate, toList()); } public static <T, D, A> Collector<T, ?, Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate, Collector<? super T, A, D> downstream) { BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator(); BiConsumer<Partition<A>, T> accumulator = (result, t) -> downstreamAccumulator.accept(predicate.test(t) ? result.forTrue : result.forFalse, t); BinaryOperator<A> op = downstream.combiner(); BinaryOperator<Partition<A>> merger = (left, right) -> new Partition<>(op.apply(left.forTrue, right.forTrue), op.apply(left.forFalse, right.forFalse)); Supplier<Partition<A>> supplier = () -> new Partition<>(downstream.supplier().get(), downstream.supplier().get()); if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) { return new CollectorImpl<>(supplier, accumulator, merger, CH_ID); } else { Function<Partition<A>, Map<Boolean, D>> finisher = par -> new Partition<>(downstream.finisher().apply(par.forTrue), downstream.finisher().apply(par.forFalse)); return new CollectorImpl<>(supplier, accumulator, merger, finisher, CH_NOID); } }
jdk的代码,就是咱们学习的范本。
讲这么细的缘由并非由于要本身去写,是为了了解内部是具体怎么实现的。调用的时候就信心很是的足。
AutoCloseable接口: 经过一个例子 举例自动关闭流的实现。
public interface BaseStream<T, S extends BaseStream<T, S>> extends AutoCloseable{} // BaseStream 继承了这个接口。 Stream继承了Stream
public class AutoCloseableTest implements AutoCloseable { public void dosomething() { System.out.println(" do something "); } @Override public void close() throws Exception { System.out.println(" close invoked "); } public static void main(String[] args) throws Exception { try ( AutoCloseableTest autoCloseableTest = new AutoCloseableTest()){ autoCloseableTest.dosomething(); } } }
运行结果以下: 自动调用了关闭流的方法
/** * A sequence of elements supporting sequential and parallel aggregate * operations. The following example illustrates an aggregate operation using * {@link Stream} and {@link IntStream}: * * <pre>{@code // 举例: * int sum = widgets.stream() * .filter(w -> w.getColor() == RED) * .mapToInt(w -> w.getWeight()) * .sum(); * }</pre> * * In this example, {@code widgets} is a {@code Collection<Widget>}. We create * a stream of {@code Widget} objects via {@link Collection#stream Collection.stream()}, * filter it to produce a stream containing only the red widgets, and then * transform it into a stream of {@code int} values representing the weight of * each red widget. Then this stream is summed to produce a total weight. * * <p>In addition to {@code Stream}, which is a stream of object references, * there are primitive specializations for {@link IntStream}, {@link LongStream}, * and {@link DoubleStream}, all of which are referred to as "streams" and * conform to the characteristics and restrictions described here. jdk提供了平行的 特化的流。 * * <p>To perform a computation, stream * <a href="package-summary.html#StreamOps">operations</a> are composed into a * <em>stream pipeline</em>. A stream pipeline consists of a source (which * might be an array, a collection, a generator function, an I/O channel, * etc), zero or more <em>intermediate operations</em> (which transform a * stream into another stream, such as {@link Stream#filter(Predicate)}), and a * <em>terminal operation</em> (which produces a result or side-effect, such * as {@link Stream#count()} or {@link Stream#forEach(Consumer)}). * Streams are lazy; computation on the source data is only performed when the * terminal operation is initiated, and source elements are consumed only * as needed. 为了执行计算,流会被执行到一个流管道当中。 一个流管道包含了: 一个源。(数字来的地方) 0个或多个中间操做(将一个stream转换成另一个Stream)。 一个终止操做(会生成一个结果,或者是一个反作用(求和,遍历))。 流是延迟的,只有当终止操做被发起的时候,才会执行中间操做。 * <p>Collections and streams, while bearing some superficial similarities, * have different goals. Collections are primarily concerned with the efficient * management of, and access to, their elements. By contrast, streams do not * provide a means to directly access or manipulate their elements, and are * instead concerned with declaratively describing their source and the * computational operations which will be performed in aggregate on that source. * However, if the provided stream operations do not offer the desired * functionality, the {@link #iterator()} and {@link #spliterator()} operations * can be used to perform a controlled traversal. 集合和流虽然有一些类似性,可是他们的差别是不一样的。 集合是为了高效对于元素的管理和访问。流并不会提供方式去直接操做流里的元素。(集合关注的是数据的管理,流关注的是元素内容的计算) 若是流操做并无提供咱们须要的功能,那么咱们可使用传统的iterator or spliterator去执行操做。 * <p>A stream pipeline, like the "widgets" example above, can be viewed as * a <em>query</em> on the stream source. Unless the source was explicitly * designed for concurrent modification (such as a {@link ConcurrentHashMap}), * unpredictable or erroneous behavior may result from modifying the stream * source while it is being queried. 一个流管道,能够看作是对流源的查询,除非这个流被显示的设计成能够并发修改的。不然会抛出异常。 (如一个线程对流进行修改,另外一个对流进行查询) * <p>Most stream operations accept parameters that describe user-specified * behavior, such as the lambda expression {@code w -> w.getWeight()} passed to * {@code mapToInt} in the example above. To preserve correct behavior, * these <em>behavioral parameters</em>: //为了能知足结果,需知足下边的条件。 * <ul> * <li>must be <a href="package-summary.html#NonInterference">non-interfering</a> * (they do not modify the stream source); and</li> * <li>in most cases must be <a href="package-summary.html#Statelessness">stateless</a> * (their result should not depend on any state that might change during execution * of the stream pipeline).</li> * </ul> 行为上的参数,大可能是无状态的。 * <p>Such parameters are always instances of a * <a href="../function/package-summary.html">functional interface</a> such * as {@link java.util.function.Function}, and are often lambda expressions or * method references. Unless otherwise specified these parameters must be * <em>non-null</em>. 无一例外的。这种参数老是函数式接口的形式。也就是lambda表达式。除非特别指定,这些参数必须是非空的。 * <p>A stream should be operated on (invoking an intermediate or terminal stream * operation) only once. This rules out, for example, "forked" streams, where * the same source feeds two or more pipelines, or multiple traversals of the * same stream. A stream implementation may throw {@link IllegalStateException} * if it detects that the stream is being reused. However, since some stream * operations may return their receiver rather than a new stream object, it may * not be possible to detect reuse in all cases. 一个流只能被使用一次。对相同的流进行屡次操做,须要建立多个流管道。 * <p>Streams have a {@link #close()} method and implement {@link AutoCloseable}, * but nearly all stream instances do not actually need to be closed after use. * Generally, only streams whose source is an IO channel (such as those returned * by {@link Files#lines(Path, Charset)}) will require closing. Most streams * are backed by collections, arrays, or generating functions, which require no * special resource management. (If a stream does require closing, it can be * declared as a resource in a {@code try}-with-resources statement.) 流拥有一个closed方法,实现了AutoCloseable,在他的父类里。 最上面以举例实现。 可是一个流 除了是I/O流(由于持有句柄等资源)才须要被关闭外,是不须要被关闭的。 大多数的流底层是集合、数组或者是生成器函数。 他们并不须要特别的资源管理。若是须要被关闭,能够用try()操做。 * <p>Stream pipelines may execute either sequentially or in * <a href="package-summary.html#Parallelism">parallel</a>. This * execution mode is a property of the stream. Streams are created * with an initial choice of sequential or parallel execution. (For example, * {@link Collection#stream() Collection.stream()} creates a sequential stream, * and {@link Collection#parallelStream() Collection.parallelStream()} creates * a parallel one.) This choice of execution mode may be modified by the * {@link #sequential()} or {@link #parallel()} methods, and may be queried with * the {@link #isParallel()} method. 流管道能够被串行或者并行操做。这种模式只是一个属性而已。 初始化的时候会进行一个选择。 好比说 stream() 是串行流。parallelStream()是并行流。 还能够经过sequential()or parallel() 来进行修改。 以最后一个被调用的方法为准。 也能够用isParallel()来进行查询流是不是并行流。 * @param <T> the type of the stream elements * @since 1.8 * @see IntStream * @see LongStream * @see DoubleStream * @see <a href="package-summary.html">java.util.stream</a> */ public interface Stream<T> extends BaseStream<T, Stream<T>> { // 具体举例, 源码中有例子 Stream<T> filter(Predicate<? super T> predicate); // 过滤 <R> Stream<R> map(Function<? super T, ? extends R> mapper); //映射 IntStream mapToInt(ToIntFunction<? super T> mapper); LongStream mapToLong(ToLongFunction<? super T> mapper); DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper); <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper); //压平 IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper); LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper); DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper);、 Stream<T> distinct();// 去重 Stream<T> sorted(); //排序 Stream<T> sorted(Comparator<? super T> comparator); Stream<T> peek(Consumer<? super T> action); Stream<T> limit(long maxSize); // 截断 void forEach(Consumer<? super T> action); // 遍历 void forEachOrdered(Consumer<? super T> action); // 遍历时执行操做 Object[] toArray(); // 转数组 T reduce(T identity, BinaryOperator<T> accumulator); // 汇聚, 返回一个汇聚的结果 <R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner); // 收集器 。。。 }
自行参考父接口中的方法;
分割迭代器:
/** * Returns a spliterator for the elements of this stream. * * <p>This is a <a href="package-summary.html#StreamOps">terminal * operation</a>. * * @return the element spliterator for this stream */ Spliterator<T> spliterator();
在公司的学习笔记。
BaseStream 是全部流的父类 。
/** * Base interface for streams, which are sequences of elements supporting * sequential and parallel aggregate operations. The following example * illustrates an aggregate operation using the stream types {@link Stream} * and {@link IntStream}, computing the sum of the weights of the red widgets: * * <pre>{@code * int sum = widgets.stream() * .filter(w -> w.getColor() == RED) * .mapToInt(w -> w.getWeight()) * .sum(); * }</pre> * * See the class documentation for {@link Stream} and the package documentation * for <a href="package-summary.html">java.util.stream</a> for additional * specification of streams, stream operations, stream pipelines, and * parallelism, which governs the behavior of all stream types. * * @param <T> the type of the stream elements * @param <S> the type of of the stream implementing {@code BaseStream} * @since 1.8 * @see Stream * @see IntStream * @see LongStream * @see DoubleStream * @see <a href="package-summary.html">java.util.stream</a> */ public interface BaseStream<T, S extends BaseStream<T, S>> extends AutoCloseable public interface Stream<T> extends BaseStream<T, Stream<T>>
BaseStream(){ Iterator<T> iterator(); 迭代器 Spliterator<T> spliterator(); 分割迭代器 。 这是一个流的终止操做。 boolean isParallel(); 是不是并行。 S sequential(); // 返回一个等价的串行流。 返回S是一个新的流对象 S parallel(); //返回一个并行流。 S unordered(); // 返回一个无序的流。 S onClose(Runnable closeHandler); //当前流.onClose、 当close调用时,调用此方法。 void close(); // 关闭流 }
/** * Returns an equivalent stream with an additional close handler. Close * handlers are run when the {@link #close()} method * is called on the stream, and are executed in the order they were * added. All close handlers are run, even if earlier close handlers throw * exceptions. If any close handler throws an exception, the first * exception thrown will be relayed to the caller of {@code close()}, with * any remaining exceptions added to that exception as suppressed exceptions * (unless one of the remaining exceptions is the same exception as the * first exception, since an exception cannot suppress itself.) May * return itself. * * <p>This is an <a href="package-summary.html#StreamOps">intermediate * operation</a>. * * @param closeHandler A task to execute when the stream is closed * @return a stream with a handler that is run if the stream is closed */ S onClose(Runnable closeHandler);
public static void main(String[] args) { List<String> list = Arrays.asList("hello","world"); NullPointerException nullPointerException = new NullPointerException("myexception"); try (Stream<String> stream = list.stream()){ stream.onClose(()->{ System.out.println("aaa"); // throw new NullPointerException("first"); throw nullPointerException; }).onClose(()->{ System.out.println("aaa"); throw nullPointerException; }).forEach(System.out::println); } // 出现异常会被压制, // 若是是同一个异常对象,只会打印一次异常。 若是是多个异常对象。都会被打印。 }
javadoc 中的介绍比任何资料都详细。
/** * Returns a sequential {@code Stream} with this collection as its source. 返回一个串行流,把这个集合当作源 * <p>This method should be overridden when the {@link #spliterator()} * method cannot return a spliterator that is {@code IMMUTABLE}, * {@code CONCURRENT}, or <em>late-binding</em>. (See {@link #spliterator()} * for details.) 当不能返回 三种方法 中的一个时,这个方法应该被重写。 * @implSpec * The default implementation creates a sequential {@code Stream} from the * collection's {@code Spliterator}. 默认会从集合中建立一个串行流。 返回 * @return a sequential {@code Stream} over the elements in this collection * @since 1.8 */ default Stream<E> stream() { return StreamSupport.stream(spliterator(), false); }
/** * Creates a {@link Spliterator} over the elements in this collection. * * Implementations should document characteristic values reported by the * spliterator. Such characteristic values are not required to be reported * if the spliterator reports {@link Spliterator#SIZED} and this collection * contains no elements. * <p>The default implementation should be overridden by subclasses that * can return a more efficient spliterator. In order to * preserve expected laziness behavior for the {@link #stream()} and * {@link #parallelStream()}} methods, spliterators should either have the * characteristic of {@code IMMUTABLE} or {@code CONCURRENT}, or be * <em><a href="Spliterator.html#binding">late-binding</a></em>. 默认的子类应该被重写。为了保留parallelStream 和 stream的延迟行为。特性须要知足IMMUTABLE 或者CONCURRENT * If none of these is practical, the overriding class should describe the * spliterator's documented policy of binding and structural interference, * and should override the {@link #stream()} and {@link #parallelStream()} * methods to create streams using a {@code Supplier} of the spliterator, * as in: * <pre>{@code * Stream<E> s = StreamSupport.stream(() -> spliterator(), spliteratorCharacteristics) * }</pre> 为何叫分割迭代器。先分割,在迭代。 若是不能知足上述的要求,则重写的时候应该知足上述的需求、 * <p>These requirements ensure that streams produced by the * {@link #stream()} and {@link #parallelStream()} methods will reflect the * contents of the collection as of initiation of the terminal stream * operation. 这些确保了流会返回的内容。 * @implSpec * The default implementation creates a * <em><a href="Spliterator.html#binding">late-binding</a></em> spliterator * from the collections's {@code Iterator}. The spliterator inherits the * <em>fail-fast</em> properties of the collection's iterator. * <p> * The created {@code Spliterator} reports {@link Spliterator#SIZED}. 默认会从集合的迭代器中建立出一个延迟的分割迭代器。 默认的迭代器 会有默认大小的迭代器。 * @implNote * The created {@code Spliterator} additionally reports * {@link Spliterator#SUBSIZED}. * * <p>If a spliterator covers no elements then the reporting of additional * characteristic values, beyond that of {@code SIZED} and {@code SUBSIZED}, * does not aid clients to control, specialize or simplify computation. * However, this does enable shared use of an immutable and empty * spliterator instance (see {@link Spliterators#emptySpliterator()}) for * empty collections, and enables clients to determine if such a spliterator * covers no elements. 若是分割迭代器不包含任何元素。 其余的属性对客户端是没有任何帮助的。 然而会促进分割迭代器共享的做用。 * @return a {@code Spliterator} over the elements in this collection * @since 1.8 */ @Override default Spliterator<E> spliterator() { return Spliterators.spliterator(this, 0); }
/** * An object for traversing and partitioning elements of a source. The source * of elements covered by a Spliterator could be, for example, an array, a * {@link Collection}, an IO channel, or a generator function. * <p>A Spliterator may traverse elements individually ({@link * #tryAdvance tryAdvance()}) or sequentially in bulk * ({@link #forEachRemaining forEachRemaining()}). 一个一个去遍历 tryAdvance() 或者 成块的遍历forEachRemaining() * * <p>A Spliterator may also partition off some of its elements (using * {@link #trySplit}) as another Spliterator, to be used in * possibly-parallel operations. Operations using a Spliterator that * cannot split, or does so in a highly imbalanced or inefficient * manner, are unlikely to benefit from parallelism. Traversal * and splitting exhaust elements; each Spliterator is useful for only a single * bulk computation. Spliterator 能够对元素进行分区。 分红新的Spliterator。 而且以并行的操做来实行。 若是不能分割这些操做,则不能经过并行操做受益。 遍历和分割都会对那一小块是有用的、 * <p>A Spliterator also reports a set of {@link #characteristics()} of its * structure, source, and elements from among {@link #ORDERED}, * {@link #DISTINCT}, {@link #SORTED}, {@link #SIZED}, {@link #NONNULL}, * {@link #IMMUTABLE}, {@link #CONCURRENT}, and {@link #SUBSIZED}. These may * be employed by Spliterator clients to control, specialize or simplify * computation. For example, a Spliterator for a {@link Collection} would * report {@code SIZED}, a Spliterator for a {@link Set} would report * {@code DISTINCT}, and a Spliterator for a {@link SortedSet} would also * report {@code SORTED}. Characteristics are reported as a simple unioned bit * set. 特性值:ORDERED 有序的, DISTINCT 不一样的,SORTED 带排序的,SIZED 肯定大小的, NONNULL 非空的, IMMUTABLE, CONCURRENT ,SUBSIZED 这些特性能够在客户端使用,用来简化计算。是以位操做的形式来表示的。 collector中是以枚举形式来表示的。 * Some characteristics additionally constrain method behavior; for example if * {@code ORDERED}, traversal methods must conform to their documented ordering. * New characteristics may be defined in the future, so implementors should not * assign meanings to unlisted values. 将来可能会定义一下新的特性。 实现者不该该赋予新的含义。 * <p><a name="binding">A Spliterator that does not report {@code IMMUTABLE} or * {@code CONCURRENT} is expected to have a documented policy concerning: * when the spliterator <em>binds</em> to the element source; and detection of * structural interference of the element source detected after binding.</a> A * <em>late-binding</em> Spliterator binds to the source of elements at the * point of first traversal, first split, or first query for estimated size, * rather than at the time the Spliterator is created. A Spliterator that is * not <em>late-binding</em> binds to the source of elements at the point of * construction or first invocation of any method. Modifications made to the * source prior to binding are reflected when the Spliterator is traversed. * After binding a Spliterator should, on a best-effort basis, throw * {@link ConcurrentModificationException} if structural interference is * detected. Spliterators that do this are called <em>fail-fast</em>. The * bulk traversal method ({@link #forEachRemaining forEachRemaining()}) of a * Spliterator may optimize traversal and check for structural interference * after all elements have been traversed, rather than checking per-element and * failing immediately. 当Spliterator 绑定到源上时 , 要考虑 IMMUTABLE 和 CONCURRENT 。 延迟迭代器会在第一次遍历或者分割或者查询大小的时候绑定在源上边。而不是在建立的时候就被绑定在源上了。 非延迟迭代器是在建立的时候就被绑定在源上了。 在迭代器绑定后对源进行了修改。迭代器就能反应出来抛出异常ConcurrentModificationException。 forEachRemaining()会优化遍历,是在全部元素都被操做以后进行操做,而不是一个元素一个元素的检测、 * <p>Spliterators can provide an estimate of the number of remaining elements * via the {@link #estimateSize} method. Ideally, as reflected in characteristic * {@link #SIZED}, this value corresponds exactly to the number of elements * that would be encountered in a successful traversal. However, even when not * exactly known, an estimated value value may still be useful to operations * being performed on the source, such as helping to determine whether it is * preferable to split further or traverse the remaining elements sequentially. 若是 特性值 SIZED 。 那么将要遍历的数量是肯定的。 若是不包含SIZED,一个估算的值对于源的操做也是有帮助的。 * <p>Despite their obvious utility in parallel algorithms, spliterators are not * expected to be thread-safe; instead, implementations of parallel algorithms * using spliterators should ensure that the spliterator is only used by one * thread at a time. This is generally easy to attain via <em>serial * thread-confinement</em>, which often is a natural consequence of typical * parallel algorithms that work by recursive decomposition. A thread calling * {@link #trySplit()} may hand over the returned Spliterator to another thread, * which in turn may traverse or further split that Spliterator. The behaviour * of splitting and traversal is undefined if two or more threads operate * concurrently on the same spliterator. If the original thread hands a * spliterator off to another thread for processing, it is best if that handoff * occurs before any elements are consumed with {@link #tryAdvance(Consumer) * tryAdvance()}, as certain guarantees (such as the accuracy of * {@link #estimateSize()} for {@code SIZED} spliterators) are only valid before * traversal has begun. 分割迭代器并不确保是线程安全的。相反 应该确保分割迭代器一次被一个线程操做、 能够经过递归的方式来实现。 * <p>Primitive subtype specializations of {@code Spliterator} are provided for * {@link OfInt int}, {@link OfLong long}, and {@link OfDouble double} values. * The subtype default implementations of * {@link Spliterator#tryAdvance(java.util.function.Consumer)} * and {@link Spliterator#forEachRemaining(java.util.function.Consumer)} box * primitive values to instances of their corresponding wrapper class. Such * boxing may undermine any performance advantages gained by using the primitive * specializations. To avoid boxing, the corresponding primitive-based methods * should be used. For example, * {@link Spliterator.OfInt#tryAdvance(java.util.function.IntConsumer)} * and {@link Spliterator.OfInt#forEachRemaining(java.util.function.IntConsumer)} * should be used in preference to * {@link Spliterator.OfInt#tryAdvance(java.util.function.Consumer)} and * {@link Spliterator.OfInt#forEachRemaining(java.util.function.Consumer)}. * Traversal of primitive values using boxing-based methods * {@link #tryAdvance tryAdvance()} and * {@link #forEachRemaining(java.util.function.Consumer) forEachRemaining()} * does not affect the order in which the values, transformed to boxed values, * are encountered. 为了不重复的装箱和拆箱,咱们应该使用巨化的方法。 减小使用通用的方法。 * * @apiNote * <p>Spliterators, like {@code Iterator}s, are for traversing the elements of * a source. The {@code Spliterator} API was designed to support efficient * parallel traversal in addition to sequential traversal, by supporting * decomposition as well as single-element iteration. In addition, the * protocol for accessing elements via a Spliterator is designed to impose * smaller per-element overhead than {@code Iterator}, and to avoid the inherent * race involved in having separate methods for {@code hasNext()} and * {@code next()}. 分割迭代器 就像迭代器同样。 用来遍历源当中的元素的。 Spliterator也支持并行的操做。方式是经过解耦,分解,单元素的遍历迭代。 Spliterator相比于Iterator来讲,成本更低。tryAdvance()本质上也避免了hasNext()和next() 的资源上的竞争。 * <p>For mutable sources, arbitrary and non-deterministic behavior may occur if * the source is structurally interfered with (elements added, replaced, or * removed) between the time that the Spliterator binds to its data source and * the end of traversal. For example, such interference will produce arbitrary, * non-deterministic results when using the {@code java.util.stream} framework. 对于可变源来讲,可能会出现问题 * <p>Structural interference of a source can be managed in the following ways * (in approximate order of decreasing desirability): * <ul> * <li>The source cannot be structurally interfered with. * <br>For example, an instance of * {@link java.util.concurrent.CopyOnWriteArrayList} is an immutable source. * A Spliterator created from the source reports a characteristic of * {@code IMMUTABLE}.</li> CopyOnWriteArrayList 适合于 读多写少的场景。 他是一个不可变的源。会返回一个特性值IMMUTABLE * <li>The source manages concurrent modifications. * <br>For example, a key set of a {@link java.util.concurrent.ConcurrentHashMap} * is a concurrent source. A Spliterator created from the source reports a * characteristic of {@code CONCURRENT}.</li> 建立并发源、 特性值 CONCURRENT * <li>The mutable source provides a late-binding and fail-fast Spliterator. * <br>Late binding narrows the window during which interference can affect * the calculation; fail-fast detects, on a best-effort basis, that structural * interference has occurred after traversal has commenced and throws * {@link ConcurrentModificationException}. For example, {@link ArrayList}, * and many other non-concurrent {@code Collection} classes in the JDK, provide * a late-binding, fail-fast spliterator.</li> * <li>The mutable source provides a non-late-binding but fail-fast Spliterator. * <br>The source increases the likelihood of throwing * {@code ConcurrentModificationException} since the window of potential * interference is larger.</li> * <li>The mutable source provides a late-binding and non-fail-fast Spliterator. * <br>The source risks arbitrary, non-deterministic behavior after traversal * has commenced since interference is not detected. * </li> * <li>The mutable source provides a non-late-binding and non-fail-fast * Spliterator. * <br>The source increases the risk of arbitrary, non-deterministic behavior * since non-detected interference may occur after construction. * </li> * </ul> * // 串行的例子: * <p><b>Example.</b> Here is a class (not a very useful one, except * for illustration) that maintains an array in which the actual data * are held in even locations, and unrelated tag data are held in odd * locations. Its Spliterator ignores the tags. * * <pre> {@code * class TaggedArray<T> { * private final Object[] elements; // immutable after construction * TaggedArray(T[] data, Object[] tags) { * int size = data.length; * if (tags.length != size) throw new IllegalArgumentException(); * this.elements = new Object[2 * size]; * for (int i = 0, j = 0; i < size; ++i) { * elements[j++] = data[i]; * elements[j++] = tags[i]; * } * } * * public Spliterator<T> spliterator() { * return new TaggedArraySpliterator<>(elements, 0, elements.length); * } * * static class TaggedArraySpliterator<T> implements Spliterator<T> { * private final Object[] array; * private int origin; // current index, advanced on split or traversal * private final int fence; // one past the greatest index * * TaggedArraySpliterator(Object[] array, int origin, int fence) { * this.array = array; this.origin = origin; this.fence = fence; * } * * public void forEachRemaining(Consumer<? super T> action) { * for (; origin < fence; origin += 2) * action.accept((T) array[origin]); * } * // 让这个迭代器往前走 * public boolean tryAdvance(Consumer<? super T> action) { * if (origin < fence) { * action.accept((T) array[origin]); * origin += 2; * return true; * } * else // cannot advance * return false; * } * // 尝试进行分割, 尽可能均匀的分割成两半. 不成功返回null * public Spliterator<T> trySplit() { * int lo = origin; // divide range in half * int mid = ((lo + fence) >>> 1) & ~1; // force midpoint to be even * if (lo < mid) { // split out left half * origin = mid; // reset this Spliterator's origin * return new TaggedArraySpliterator<>(array, lo, mid); * } * else // too small to split * return null; * } * * public long estimateSize() { * return (long)((fence - origin) / 2); * } * * public int characteristics() { * return ORDERED | SIZED | IMMUTABLE | SUBSIZED; * } * } * }}</pre> * // 并行的例子 * <p>As an example how a parallel computation framework, such as the * {@code java.util.stream} package, would use Spliterator in a parallel * computation, here is one way to implement an associated parallel forEach, * that illustrates the primary usage idiom of splitting off subtasks until * the estimated amount of work is small enough to perform * sequentially. Here we assume that the order of processing across * subtasks doesn't matter; different (forked) tasks may further split * and process elements concurrently in undetermined order. This * example uses a {@link java.util.concurrent.CountedCompleter}; * similar usages apply to other parallel task constructions. * * <pre>{@code * static <T> void parEach(TaggedArray<T> a, Consumer<T> action) { * Spliterator<T> s = a.spliterator(); * long targetBatchSize = s.estimateSize() / (ForkJoinPool.getCommonPoolParallelism() * 8); * new ParEach(null, s, action, targetBatchSize).invoke(); * } * * static class ParEach<T> extends CountedCompleter<Void> { * final Spliterator<T> spliterator; * final Consumer<T> action; * final long targetBatchSize; * * ParEach(ParEach<T> parent, Spliterator<T> spliterator, * Consumer<T> action, long targetBatchSize) { * super(parent); * this.spliterator = spliterator; this.action = action; * this.targetBatchSize = targetBatchSize; * } * * public void compute() { * Spliterator<T> sub; * while (spliterator.estimateSize() > targetBatchSize && * (sub = spliterator.trySplit()) != null) { * addToPendingCount(1); * new ParEach<>(this, sub, action, targetBatchSize).fork(); * } * spliterator.forEachRemaining(action); * propagateCompletion(); * } * }}</pre> * * @implNote * If the boolean system property {@code org.openjdk.java.util.stream.tripwire} * is set to {@code true} then diagnostic warnings are reported if boxing of * primitive values occur when operating on primitive subtype specializations. * 若是 {@code org.openjdk.java.util.stream.tripwire} 被设置成true, 则会给出警告。 * @param <T> the type of elements returned by this Spliterator * * @see Collection * @since 1.8 */ public interface Spliterator<T> { // 。。。 下方列举几个 }
/** * If a remaining element exists, performs the given action on it, * returning {@code true}; else returns {@code false}. If this * Spliterator is {@link #ORDERED} the action is performed on the * next element in encounter order. Exceptions thrown by the * action are relayed to the caller. * * @param action The action * @return {@code false} if no remaining elements existed * upon entry to this method, else {@code true}. * @throws NullPointerException if the specified action is null */ //尝试的去前进。若是有下一个元素,则进行动做。 boolean tryAdvance(Consumer<? super T> action);
/** * Performs the given action for each remaining element, sequentially in * the current thread, until all elements have been processed or the action * throws an exception. If this Spliterator is {@link #ORDERED}, actions * are performed in encounter order. Exceptions thrown by the action * are relayed to the caller. * * @implSpec * The default implementation repeatedly invokes {@link #tryAdvance} until * it returns {@code false}. It should be overridden whenever possible. * * @param action The action * @throws NullPointerException if the specified action is null */ // 针对于剩余的元素进行操做。 default void forEachRemaining(Consumer<? super T> action) { do { } while (tryAdvance(action)); }
/** * If this spliterator can be partitioned, returns a Spliterator * covering elements, that will, upon return from this method, not * be covered by this Spliterator. * 若是这个分割迭代器能被分割,则返回一个新的被分割出来的Spliterator对象。 不会影响当前的spliterator * <p>If this Spliterator is {@link #ORDERED}, the returned Spliterator * must cover a strict prefix of the elements. *若是Spliterator是有序的,则返回的也应该是有序的Spliterator * <p>Unless this Spliterator covers an infinite number of elements, * repeated calls to {@code trySplit()} must eventually return {@code null}. 除非Spliterator 返回的是无穷的元素,其他的最终返回一个null . 表示不能再继续分割了。 * Upon non-null return: 若是返回不为Null的话, * <ul> * <li>the value reported for {@code estimateSize()} before splitting, * must, after splitting, be greater than or equal to {@code estimateSize()} * for this and the returned Spliterator; and</li> 分割前的estimateSize>= 返回的estimateSize * <li>if this Spliterator is {@code SUBSIZED}, then {@code estimateSize()} * for this spliterator before splitting must be equal to the sum of * {@code estimateSize()} for this and the returned Spliterator after * splitting.</li> 若是大小是固定的。则分割后的 estimateSize 的总和 等于分割前的 estimateSize * </ul> * * <p>This method may return {@code null} for any reason, * including emptiness, inability to split after traversal has * commenced, data structure constraints, and efficiency * considerations. * * @apiNote * An ideal {@code trySplit} method efficiently (without * traversal) divides its elements exactly in half, allowing * balanced parallel computation. Many departures from this ideal * remain highly effective; for example, only approximately * splitting an approximately balanced tree, or for a tree in * which leaf nodes may contain either one or two elements, * failing to further split these nodes. However, large * deviations in balance and/or overly inefficient {@code * trySplit} mechanics typically result in poor parallel * performance. *理想状况下,是从中间分割的,容许并行计算。不少状况下不知足这种的、 然而没有效率的分割,会下降效率 * @return a {@code Spliterator} covering some portion of the * elements, or {@code null} if this spliterator cannot be split */ //尝试分割。 Spliterator<T> trySplit();
/** * Returns an estimate of the number of elements that would be * encountered by a {@link #forEachRemaining} traversal, or returns {@link * Long#MAX_VALUE} if infinite, unknown, or too expensive to compute. * * <p>If this Spliterator is {@link #SIZED} and has not yet been partially * traversed or split, or this Spliterator is {@link #SUBSIZED} and has * not yet been partially traversed, this estimate must be an accurate * count of elements that would be encountered by a complete traversal. * Otherwise, this estimate may be arbitrarily inaccurate, but must decrease * as specified across invocations of {@link #trySplit}. * 分的越少,estimateSize要比原来的个数要小。 * @apiNote * Even an inexact estimate is often useful and inexpensive to compute. * For example, a sub-spliterator of an approximately balanced binary tree * may return a value that estimates the number of elements to be half of * that of its parent; if the root Spliterator does not maintain an * accurate count, it could estimate size to be the power of two * corresponding to its maximum depth. *一个不精算的数量也是有用的。 * @return the estimated size, or {@code Long.MAX_VALUE} if infinite, * unknown, or too expensive to compute. */ //估算大小 long estimateSize();
/** * Returns a set of characteristics of this Spliterator and its * elements. The result is represented as ORed values from {@link * #ORDERED}, {@link #DISTINCT}, {@link #SORTED}, {@link #SIZED}, * {@link #NONNULL}, {@link #IMMUTABLE}, {@link #CONCURRENT}, * {@link #SUBSIZED}. Repeated calls to {@code characteristics()} on * a given spliterator, prior to or in-between calls to {@code trySplit}, * should always return the same result. 一个特性值的集合。 重复的调用characteristics 在spliterator以前或者当中,会返回相同的结果。 * <p>If a Spliterator reports an inconsistent set of * characteristics (either those returned from a single invocation * or across multiple invocations), no guarantees can be made * about any computation using this Spliterator. 若是返回了一个不一致的特性值的集合。结果是不被保障的。 * @apiNote The characteristics of a given spliterator before splitting * may differ from the characteristics after splitting. For specific * examples see the characteristic values {@link #SIZED}, {@link #SUBSIZED} * and {@link #CONCURRENT}. * * @return a representation of characteristics */ //特性值。 int characteristics();
/** * Returns {@code true} if this Spliterator's {@link * #characteristics} contain all of the given characteristics. * * @implSpec * The default implementation returns true if the corresponding bits * of the given characteristics are set. * 默认的话,包含 会返回true * @param characteristics the characteristics to check for * @return {@code true} if all the specified characteristics are present, * else {@code false} */ // 判断是否包含给定的特性值。 default boolean hasCharacteristics(int characteristics) { return (characteristics() & characteristics) == characteristics; }
/** * If this Spliterator's source is {@link #SORTED} by a {@link Comparator}, * returns that {@code Comparator}. If the source is {@code SORTED} in * {@linkplain Comparable natural order}, returns {@code null}. Otherwise, * if the source is not {@code SORTED}, throws {@link IllegalStateException}. * * @implSpec * The default implementation always throws {@link IllegalStateException}. * * @return a Comparator, or {@code null} if the elements are sorted in the * natural order. * @throws IllegalStateException if the spliterator does not report * a characteristic of {@code SORTED}. */ //有序的话 返回一个Null。 其余状况 抛异常 default Comparator<? super T> getComparator() { throw new IllegalStateException(); }
/** * Characteristic value signifying that the element source cannot be * structurally modified; that is, elements cannot be added, replaced, or * removed, so such changes cannot occur during traversal. A Spliterator * that does not report {@code IMMUTABLE} or {@code CONCURRENT} is expected * to have a documented policy (for example throwing * {@link ConcurrentModificationException}) concerning structural * interference detected during traversal. */ public static final int IMMUTABLE = 0x00000400; // 不能被修改的
/** * Characteristic value signifying that the element source may be safely * concurrently modified (allowing additions, replacements, and/or removals) * by multiple threads without external synchronization. If so, the * Spliterator is expected to have a documented policy concerning the impact * of modifications during traversal. * * <p>A top-level Spliterator should not report both {@code CONCURRENT} and * {@code SIZED}, since the finite size, if known, may change if the source * is concurrently modified during traversal. Such a Spliterator is * inconsistent and no guarantees can be made about any computation using * that Spliterator. Sub-spliterators may report {@code SIZED} if the * sub-split size is known and additions or removals to the source are not * reflected when traversing. * * @apiNote Most concurrent collections maintain a consistency policy * guaranteeing accuracy with respect to elements present at the point of * Spliterator construction, but possibly not reflecting subsequent * additions or removals. */ public static final int CONCURRENT = 0x00001000;
/** * A Spliterator specialized for primitive values. * * @param <T> the type of elements returned by this Spliterator. The * type must be a wrapper type for a primitive type, such as {@code Integer} * for the primitive {@code int} type. * @param <T_CONS> the type of primitive consumer. The type must be a * primitive specialization of {@link java.util.function.Consumer} for * {@code T}, such as {@link java.util.function.IntConsumer} for * {@code Integer}. * @param <T_SPLITR> the type of primitive Spliterator. The type must be * a primitive specialization of Spliterator for {@code T}, such as * {@link Spliterator.OfInt} for {@code Integer}. * * @see Spliterator.OfInt * @see Spliterator.OfLong * @see Spliterator.OfDouble * @since 1.8 */ public interface OfPrimitive<T, T_CONS, T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>> extends Spliterator<T> { @Override T_SPLITR trySplit(); /** * If a remaining element exists, performs the given action on it, * returning {@code true}; else returns {@code false}. If this * Spliterator is {@link #ORDERED} the action is performed on the * next element in encounter order. Exceptions thrown by the * action are relayed to the caller. * * @param action The action * @return {@code false} if no remaining elements existed * upon entry to this method, else {@code true}. * @throws NullPointerException if the specified action is null */ @SuppressWarnings("overloads") boolean tryAdvance(T_CONS action); /** * Performs the given action for each remaining element, sequentially in * the current thread, until all elements have been processed or the * action throws an exception. If this Spliterator is {@link #ORDERED}, * actions are performed in encounter order. Exceptions thrown by the * action are relayed to the caller. * * @implSpec * The default implementation repeatedly invokes {@link #tryAdvance} * until it returns {@code false}. It should be overridden whenever * possible. * * @param action The action * @throws NullPointerException if the specified action is null */ @SuppressWarnings("overloads") default void forEachRemaining(T_CONS action) { do { } while (tryAdvance(action)); } }
/** * A Spliterator specialized for {@code int} values. * @since 1.8 */ public interface OfInt extends OfPrimitive<Integer, IntConsumer, OfInt> { @Override OfInt trySplit(); @Override boolean tryAdvance(IntConsumer action); @Override default void forEachRemaining(IntConsumer action) { do { } while (tryAdvance(action)); } /** * {@inheritDoc} * @implSpec * If the action is an instance of {@code IntConsumer} then it is cast * to {@code IntConsumer} and passed to * {@link #tryAdvance(java.util.function.IntConsumer)}; otherwise * the action is adapted to an instance of {@code IntConsumer}, by * boxing the argument of {@code IntConsumer}, and then passed to * {@link #tryAdvance(java.util.function.IntConsumer)}. */ @Override default boolean tryAdvance(Consumer<? super Integer> action) { if (action instanceof IntConsumer) { return tryAdvance((IntConsumer) action); } else { if (Tripwire.ENABLED) Tripwire.trip(getClass(), "{0} calling Spliterator.OfInt.tryAdvance((IntConsumer) action::accept)"); return tryAdvance((IntConsumer) action::accept); } } /** * {@inheritDoc} * @implSpec * If the action is an instance of {@code IntConsumer} then it is cast * to {@code IntConsumer} and passed to * {@link #forEachRemaining(java.util.function.IntConsumer)}; otherwise * the action is adapted to an instance of {@code IntConsumer}, by * boxing the argument of {@code IntConsumer}, and then passed to * {@link #forEachRemaining(java.util.function.IntConsumer)}. */ @Override default void forEachRemaining(Consumer<? super Integer> action) { if (action instanceof IntConsumer) { forEachRemaining((IntConsumer) action); } else { if (Tripwire.ENABLED) Tripwire.trip(getClass(), "{0} calling Spliterator.OfInt.forEachRemaining((IntConsumer) action::accept)"); forEachRemaining((IntConsumer) action::accept); } } }
IntConsumer 和 Consumer 是没有任何的关联关系 的。可是为何能(IntConsumer)Consumer
由于jdk自带装箱拆箱操做。 int 和 integer 重叠了。
流执行操做时,先整理把中间的操做整合,当调用终止操做的时候,对每一个元素单个的进行全部的操做。操做中还带有短路操做。
记录下来,而后给别人再讲,你就掌握了。
学完以后忘记了怎么办?记录下来。 笔记 博客。 死记硬背是没有任何用的。
/** * Abstract base class for an intermediate pipeline stage or pipeline source * stage implementing whose elements are of type {@code U}. */ //引用管道 //ReferencePipeline 表示流的源阶段与中间阶段。 //ReferencePipeline.head表示流中的源阶段。 abstract class ReferencePipeline<P_IN, P_OUT> extends AbstractPipeline<P_IN, P_OUT, Stream<P_OUT>> implements Stream<P_OUT> { }
/** * Abstract base class for "pipeline" classes, which are the core * implementations of the Stream interface and its primitive specializations. * Manages construction and evaluation of stream pipelines. * * <p>An {@code AbstractPipeline} represents an initial portion of a stream * pipeline, encapsulating a stream source and zero or more intermediate * operations. The individual {@code AbstractPipeline} objects are often * referred to as <em>stages</em>, where each stage describes either the stream * source or an intermediate operation. 流管道的初始的一部分。 * * <p>A concrete intermediate stage is generally built from an * {@code AbstractPipeline}, a shape-specific pipeline class which extends it * (e.g., {@code IntPipeline}) which is also abstract, and an operation-specific * concrete class which extends that. {@code AbstractPipeline} contains most of * the mechanics of evaluating the pipeline, and implements methods that will be * used by the operation; the shape-specific classes add helper methods for * dealing with collection of results into the appropriate shape-specific * containers. *避免自动拆箱和装箱操做。 * <p>After chaining a new intermediate operation, or executing a terminal * operation, the stream is considered to be consumed, and no more intermediate * or terminal operations are permitted on this stream instance. * 当连接完一个新的中间操做或者执行了终止操做以后, 这个流被认为被消费了。不容许再被操做了。 * @implNote * <p>For sequential streams, and parallel streams without * <a href="package-summary.html#StreamOps">stateful intermediate * operations</a>, parallel streams, pipeline evaluation is done in a single * pass that "jams" all the operations together. For parallel streams with * stateful operations, execution is divided into segments, where each * stateful operations marks the end of a segment, and each segment is * evaluated separately and the result used as the input to the next * segment. In all cases, the source data is not consumed until a terminal * operation begins. 只有终止操做开始的时候,源数据才会被消费。 * @param <E_IN> type of input elements * @param <E_OUT> type of output elements * @param <S> type of the subclass implementing {@code BaseStream} * @since 1.8 */ abstract class AbstractPipeline<E_IN, E_OUT, S extends BaseStream<E_OUT, S>> extends PipelineHelper<E_OUT> implements BaseStream<E_OUT, S> { }
本质上 内部类和lambda不是一回事。只是能完成相同的操做。
lambda不是匿名内部类的语法糖,或者说是缩写。是一种新的形式。
public class LambdaTest { //内部类,和lambda表达式之间的关系。 Runnable r1 = () -> System.out.println(this); // this表示当前类的对象 //匿名内部类 Runnable r2 = new Runnable() { // @Override public void run() { System.out.println(this); // this 表示匿名内部类的对象 } }; public static void main(String[] args) { LambdaTest lambdaTest = new LambdaTest(); Thread t1 = new Thread(lambdaTest.r1); t1.start(); System.out.println("- - -- - "); Thread t2 = new Thread(lambdaTest.r2); t2.start(); //输出结果。 //com.sinosoft.lis.test.LambdaTest@62661526 //com.sinosoft.lis.test.LambdaTest$1@59a30351 } }
使用了模板方法模式。
流是惰性的,是延迟操做的。遇到终止操做时,才会执行操做。
TerminalOp。 终止操做的接口类。
终止操做 只有四种类型, findOp foreachOp matchOp reduceOp
PipelineHelper
BaseStream -》 AbStractpipeline -》ReferencePipeline -》 Head || StatelessOP || statefulOp
最顶层的源 不少源的成员变量 管道 构造流源 无状态的中间操做 有状态的中间操做
流是惰性的,是延迟操做的。遇到终止操做时,才会执行操做。再没有终止操做以前,在整合中间操做(Sink)。
TerminalOp -》 FindOp || ForeachOp || MatchOp || reduceOp
最顶层的
TerminalSink
终止的饮水槽。
在开始学习jdk8.time以前,先接触一下joda-time。
public static void main(String[] args) { // 基本使用方式. DateTime today = new DateTime(); DateTime dateTime = today.plusDays(1); //今天 System.out.println(today.toString("yyyy-MM-dd")); //明天 System.out.println(dateTime.toString("yyyy-MM-dd")); System.out.println("- - - - -"); //当月的第一天 DateTime dateTime1 = today.withDayOfMonth(1); System.out.println(dateTime1.toString("yyyy-MM-dd")); // 当前时间后边三个月的第后一天的日期 LocalDate localDate = new LocalDate(); localDate = localDate.plusMonths(3).dayOfMonth().withMaximumValue(); System.out.println(localDate); // 当前时间后边三个月的第一天的日期 localDate = localDate.plusMonths(3).dayOfMonth().withMinimumValue(); System.out.println(localDate); //计算两年前的第三个月的最后一天的时期 DateTime localDate1 = new DateTime(); localDate1.minusYears(2).monthOfYear().setCopy(3).dayOfMonth().withMaximumValue(); System.out.println(localDate1); }
public class JodaTest2 { // 标准UTC时间. 转换成日期类型 2014-11-11T02:22:22.222z public static Date to2c(String date) { //服务器端转换成客户端的时间 DateTime parse = DateTime.parse(date, DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ")); return parse.toDate(); } public static String toString(Date date) { // 客户端的时间转成服务器的时间 DateTime date1 = new DateTime(date, DateTimeZone.UTC); return date1.toString(); } public static String date2String(Date date,String dateFort) { DateTime dateTime = new DateTime(date); return dateTime.toString(dateFort); } public static void main(String[] args) { System.out.println(JodaTest2.to2c("2014-11-11T02:22:22.222z")); System.out.println(JodaTest2.toString(new Date())); // 标准的时间为 差8个小时 System.out.println(JodaTest2.date2String(new Date(),"yyyy-MM-dd")); } }
Java8中的全部时间都是不可变的,确保了线程安全。
没有必要去研究源代码。会用就能够了。省下时间去学习更重要,更有价值的事情上。
{ public static void main(String[] args) { LocalDate localDate = LocalDate.now(); System.out.println(localDate); //获取年 System.out.println(localDate.getYear()); //获取月 System.out.println(localDate.getMonthValue()); //根据年月日构造 LocalDate localDate1 = LocalDate.of(2030, 3, 22); System.out.println(localDate1); //根据是时分秒构造 LocalDate localDate2 = LocalDate.of(2020,3,25); MonthDay monthDay = MonthDay.of(localDate2.getMonth(), localDate2.getDayOfMonth()); //根据是时分秒构造 LocalTime localTime = LocalTime.now(); System.out.println(localTime); // + 20分钟, -2个小时 LocalTime localTime1 = localTime.plusMinutes(20).minusHours(2); System.out.println(localTime1); System.out.println("- - - - -"); //如今的时间增长两周 (增长的长度,增长的单位) LocalDate localDate3 = LocalDate.now().plus(2, ChronoUnit.WEEKS); System.out.println(localDate3); //如今的时间减两周 LocalDate localDate4 = localDate.minus(2, ChronoUnit.MONTHS); System.out.println(localDate4); // Clock对象 Clock clock = Clock.systemDefaultZone(); System.out.println(clock); // 两个日期进行的判断 LocalDate localDate5 = LocalDate.now(); LocalDate localDate6 = LocalDate.of(2020,1,21); System.out.println(localDate5.isBefore(localDate6)); System.out.println(localDate5.isAfter(localDate6)); System.out.println(localDate5.equals(localDate6)); //关于时区的概念. Set<String> availableZoneIds = ZoneId.getAvailableZoneIds(); availableZoneIds.forEach(System.out::println); //将上边的无序的时区set进行排序 Set treeSet = new TreeSet<String>(){ {addAll(availableZoneIds);} }; treeSet.stream().forEach(System.out::println); //使用时区作一些例子. ZoneId zoneId = ZoneId.of("Asia/Shanghai"); LocalDateTime localDateTime = LocalDateTime.now(); System.out.println(localDateTime); ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, zoneId); System.out.println(zonedDateTime); System.out.println("- - -- - -"); // 年月的对象 YearMonth yearMonth = YearMonth.now(); System.out.println(yearMonth); System.out.println(yearMonth.lengthOfMonth()); System.out.println(yearMonth.isLeapYear()); YearMonth yearMonth1 = YearMonth.of(2019, 2); System.out.println(yearMonth1); System.out.println(yearMonth1.lengthOfMonth()); System.out.println(yearMonth1.lengthOfYear()); System.out.println(yearMonth1.isLeapYear()); // 是否闰年 LocalDate localDate7 = LocalDate.now(); LocalDate localDate8 = LocalDate.of(2017, 3, 22); // Period 周期性的.. 比较两个年份的差异 Period period = Period.between(localDate7, localDate8); // System.out.println(period); System.out.println(period.getDays()); System.out.println("- - -- - - "); // Instant 获取不带时区的UTC的标准时间. System.out.println(Instant.now()); //,,, 剩下的用到的使用自行Google } }
总共50节课,从开始到结束。学习到的不止是技术,更多的是学习方法。
系统的学习jdk8
更多的时间是了解底层是怎么实现的。
2020年02月07日12:03:41 将Java8学习的笔记给整理到了一个文件当中,方便整理。
原文出处:https://www.cnblogs.com/wobushitiegan/p/12315653.html