{"id":22111292,"url":"https://github.com/huangbuhuan/java8","last_synced_at":"2025-03-24T04:29:06.654Z","repository":{"id":190132049,"uuid":"88883839","full_name":"huangbuhuan/java8","owner":"huangbuhuan","description":"Java8学习","archived":false,"fork":false,"pushed_at":"2017-05-29T07:25:48.000Z","size":82,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-29T10:29:57.204Z","etag":null,"topics":["java-8","simple"],"latest_commit_sha":null,"homepage":"https://github.com/huangbuhuan/java8","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/huangbuhuan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2017-04-20T15:52:05.000Z","updated_at":"2022-01-06T02:01:40.000Z","dependencies_parsed_at":"2023-08-23T11:27:56.367Z","dependency_job_id":null,"html_url":"https://github.com/huangbuhuan/java8","commit_stats":null,"previous_names":["huangbuhuan/java8"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/huangbuhuan%2Fjava8","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/huangbuhuan%2Fjava8/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/huangbuhuan%2Fjava8/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/huangbuhuan%2Fjava8/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/huangbuhuan","download_url":"https://codeload.github.com/huangbuhuan/java8/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245209519,"owners_count":20578065,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["java-8","simple"],"created_at":"2024-12-01T10:38:02.563Z","updated_at":"2025-03-24T04:29:06.631Z","avatar_url":"https://github.com/huangbuhuan.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"## 高效Java 8编程\n\n用来记录Java 8学习，以及常用API的使用。\n\n![](https://img.shields.io/wercker/ci/wercker/docs.svg)\n![](https://img.shields.io/badge/java%20support-8-green.svg)\n![](https://img.shields.io/david/strongloop/express.svg)\n\n## 目录:\n\n- [函数式编程](#函数式编程)\n- [Lambda表达式](#Lambda表达式)\n\t* [函数式接口](#函数式接口)\n\t* [Java 8中重要的函数式接口](#Java8中重要的函数式接口)\n- [Stream流](#Stream流)\n\t* [collect方法](#collect方法)\n\t* [filter方法](#filter方法)\n\t* [map方法](#map方法)\n\t* [flatMap方法](#flatMap方法)\n\t* [max和min方法](#max和min方法)\n\t* [reduce方法](#reduce方法)\n\t* [创建无限流](#创建无限流)\n\t* [其他方法](#其他方法)\n- [高效Java 8编程](#高效Java8编程)\n- [其他](#其他)\n\t* [Optional](#Optional) \n\t* [DateTime](#DateTime)\t\n- [参考链接](#参考链接) \t\n\n\u003ca name=\"函数式编程\"\u003e\u003c/a\u003e\n## 函数式编程\n函数式编程是一种编程范式，它的主要思想是把函数过程尽量写成一系列嵌套的函数调用。具有以下几个特点\n\n* 函数是一等公民:函数和其他数据类型一样，可以赋值给其他变量，也可以作为参数，传递给另外一个函数，或者作为返回值返回。\n\n* 没有副作用，不修改状态。\n\n* 强调将计算过程分解成可复用的函数。\n\u003ca name=\"Lambda表达式\"\u003e\u003c/a\u003e\n\n## Lambda表达式\n\n\u003eLambda表达式没有名字，当它有参数列表、函数主体、返回类型，可能还有一个可以抛出的异常列表。\n\n|使用案例|Lambda示例|\n|---|---|\n|布尔表达式|(List\u003cString\u003e list) -\u003e list.isEmpty()|\n|创建对象|() -\u003e new User()|\n|消费一个对象|(User user) -\u003e {System.out.println(user.getName;)}|\n|从一个对象中选择/抽取|(String s) -\u003e s.length()|\n|组合两个值|(int a, int b) -\u003e a * b|\n|比较两个对象|(User a1, User a2)|\n\n\u003ca name=\"函数式接口\"\u003e\u003c/a\u003e\n### 函数式接口\n\n函数式接口就是仅仅声明了一个抽象方法的接口，不过函数式接口可以包含默认方法和静态方法。如下：\n\t\n\t@FunctionalInterface\n\tpublic interface FunctionInterfaceDemo {\n\t\n\t    void test();\n\t\n\t    static void say() {\n\t        System.out.println(\"hello\");\n\t    }\n\t\n\t    default void play() {\n\t\n\t    }\n\t}\n\n\u003ca name=\"Java8中重要的函数式接口\"\u003e\u003c/a\u003e\n### Java8中重要的函数式接口\n\n下面是Java 8中一些常用的函数式接口。\n\n|接口名|参数|返回类型|示例|\n|:--|:--|:--|:--|\n|Predicate\\\u003cT\u003e|\\\u003cT\u003e|boolean|判断是否|\n|Consumer\\\u003cT\u003e|\\\u003cT\u003e|void|输出一个值|\n|Function\\\u003cT\u003e|\\\u003cT\u003e|R|获得Artist对象的名字|\n|Supplier\\\u003cT\u003e|None|T|工厂方法|\n|UnaryOperator\\\u003cT\u003e|T|T|逻辑非(!)|\n|BinaryOperator\\\u003cT\u003e|(T, T)|T|求两个数的乘积(*)|\n\n简单的使用例子：\n\n\tPredicate\u003cInteger\u003e predicate = x -\u003e x == 1;\n\tConsumer\u003cInteger\u003e consumer = x -\u003e System.out.println(x);\n\tFunction\u003cInteger, Integer\u003e function = x -\u003e x = x + 1;\n\tSupplier\u003cInteger\u003e supplier = () -\u003e 1;\n\tUnaryOperator\u003cInteger\u003e unaryOperator = x -\u003e x + 1;\n\tBinaryOperator\u003cInteger\u003e binaryOperator = (x, y) -\u003e x * y;\n\n\u003ca name=\"Stream流\"\u003e\u003c/a\u003e\n## Stream流\n\n![UML关系图](./img/WX20170422-014241@2x.png)\n\nStream是一个借口继承了BaseStream接口，BaseStream接口继承了AutoCloseable接口。它只能被消费一次，如果想要继续使用，需要重新创建一个流。如下会抛出异常。\n\t\n\tList\u003cString\u003e strs = Arrays.asList(\"A\", \"B\", \"C\");\n\tStream\u003cString\u003e s = strs.stream();\n\ts.forEach(System.out::println);\n\ts.forEach(System.out::println);\n\t\n### 内部迭代实现机制\n外部迭代:首先调用Iterator方法，产生一个新的Iterator对象，进行控制迭代过程。\n\n内部迭代:首先调用stream方法，它的作用和iterator()方法一样，不过它返回的是内部迭代中相应的接口Stream。这样做的好处就是在迭代时要进行多次操作时可以不用多次循环，只需要迭代一次就好了。\n像filter这种不产生新集合的方法叫做[惰性求值](https://zh.wikipedia.org/wiki/%E6%83%B0%E6%80%A7%E6%B1%82%E5%80%BC)方法，像count这样最终会从Stream产生值的方法叫作及早求值方法。\n\n例子：\n\n\tUser jack = User.of(\"Jack\", 21, \"杭州\");\n\tUser rose = User.of(\"Rose\", 18, \"杭州\");\n\tList\u003cUser\u003e users = Arrays.asList(jack, rose);\n\tusers.stream()\n\t     .filter(user -\u003e {\n\t         System.out.println(user.getName());\n\t         return user.getAge() \u003e 20;\n\t     });\n\tSystem.out.println(\"------------\");\n\tusers.stream()\n\t     .filter(user -\u003e {\n\t         System.out.println(user.getName());\n\t         return user.getAge() \u003e 20;\n\t     }).count();\n\n输出：\n![](./img/WX20170423-004514@2x.png)\n结论：只有在需要的时候进行计算可以更好的提示效率\n\u003ca name=\"collect方法\"\u003e\u003c/a\u003e\n\n## 常用的方法\n\n### collect方法\n将Stream流转换为一个集合\n\t\n\t#输入\n\tStream\u003cString\u003e stream = Stream.of(\"a\", \"b\", \"c\");\n\tList\u003cString\u003e strs = stream.collect(Collectors.toList());\n\tstrs.forEach(System.out::println);\n\t#输出\n\ta\n\tb\n\tc\n\t\n\u003ca name=\"filter方法\"\u003e\u003c/a\u003e\n### filter方法\n过滤掉流中不符合条件的元素\n\t\n\t#输入\n\tStream\u003cInteger\u003e nums = Stream.of(18, 19 ,20);\n\tnums.filter(num -\u003e num \u003e 18).forEach(System.out::println);\n\t\n\t#输出\n\tc\n\u003ca name=\"map方法\"\u003e\u003c/a\u003e\n### map方法\n将流中的元素转换为另外一个元素。\n\n\t#输入\n\tStream\u003cInteger\u003e nums = Stream.of(18, 19 ,20);\n\tmap(num -\u003e num + 100).forEach(System.out::println);\n\t\n\t#输出\n\t118\n\t119\n\t120\n\u003ca name=\"flatMap方法\"\u003e\u003c/a\u003e\n### flatMap方法\n将底层的元素全部抽出来放到一起，如下将List中的元素全部抽取出来，流中只包含Integer元素。\n\n\tList\u003cInteger\u003e nums1 = Arrays.asList(1, 2, 3);\n\tList\u003cInteger\u003e nums2 = Arrays.asList(4, 6);\n\tStream.of(nums1, nums2).flatMap(num -\u003e num.stream()).forEach(System.out::println);\n\u003ca name=\"reduce\"\u003e\u003c/a\u003e\n### reduce方法\n将Stream流中的数据聚合成一个数据\n![图片来源](https://segmentfault.com/img/bVGyNp?w=1216\u0026h=867)\n\n\n\t#输入\n\tint ages = Stream.of(1, 2, 34).reduce(0, (a, b) -\u003e a + b);\n\tSystem.out.println(ages);\n\t\n\t#输出\n\t37\n\n\u003ca name=\"创建无限流\"\u003e\u003c/a\u003e\n### 创建无限流\nStream的API提供了两个静态方法创建无限流：iterate和generate。由两个静态方法创建的流会根据给定的函数按需创建流一般会使用limit限制流的大小。iterate方法会对每个新生成的值都调用函数,generate方法不会对每个新生成的值应用函数.\n\t\n\t// 从0开始，生成10个偶数。\n\tStream.iterate(0, n -\u003e n + 2).limit(10).forEach(System.out::println);\n\t// 生成10个随机数。\n\tStream.generate(Math::random). limit(10).forEach(System.out::println);\n\n\u003ca name=\"其他方法\"\u003e\u003c/a\u003e\n### 其他方法\n* skip：跳过指定个数的流。\n* limit：返回不超过给定长度的流。\n* max：找到最大的元素\n* min：找到最小的元素\n* findFirst：找到第一个匹配元素\n* findAny：获取任意一个元素\n* anyMatch：是否存在一个匹配元素\n* noneMatch：是否全部不匹配\n* allMatch：是否全部匹配\n* sorted：排序\n* distinct：去重\n\n\u003ca name=\"高效Java8编程\"\u003e\u003c/a\u003e\n## 高效Java8编程\n\n\n## 其他\n\n### Optional\nOptional是为了减少NullPointException，增加代码的可读性。Optional是一个final类型的类\n\t\n\tOptional\u003cUser\u003e optUser = Optional.of(user);\n\t\n* empty：返回一个空的Optional实例。\n* filter：如果满足提交返回Optional对象，否则返回一个空的Optional对象。\n* flatMap：如果值存在，就使用mapping函数调用，返回一个Optional对象，否则返回一个空对象。\n* get：如果值存在返回用Optional封装返回，否则抛出NoSuchElementException异常\n* ifPresent：如果值存在，就返回该方法的调用，否则什么也不做。\n* isPresent：如果值存在，就返回true，否则返回false。\n* map：如果值存在，就执行提供的mapping函数调用。\n* of：如果值不存在就抛出异常，否则返回一个Optional封装的对象。\n* ofNullable：如果值为空就返回一个空的Optional对象，否则调用of方法。\n* orElse：如果值存在就返回该值，否则返回默认值。\n* orElseGet：如果值存在就返回该值，否则返回一个函数接口生成的值。\n* orElseThrow：如果值存在就返回该值，否则抛出一个接口生成的异常。\n\n### DateTime\n\n在Java 8 以前需要使用Date和SimpdateFormatter操作时间，而且都不是线程安全的，Date不仅包含日期还包含时间和毫秒数，使用起来非常的困难，而Java 8把日期分成了LocalDate和LocalTime，还有LocalDateTime。\n\n使用LocalDate操作日期\n\n\t// 获取当前日期\n    LocalDate now = LocalDate.now();\n\n    // 用静态方法创建日期\n    LocalDate date = LocalDate.of(2017, 5, 1);\n\n    // 将String类型转换为日期类型.注：02不能写成2，否则会抛出DateTimeParseException\n    LocalDate endOfFeb = LocalDate.parse(\"2017-02-28\");\n\n    // 获取这个月的第一天的日期\n    now.with(TemporalAdjusters.firstDayOfMonth())\n\n    // 获取这个月的最后一天\n    now.with(TemporalAdjusters.lastDayOfMonth())\n\n使用LocalTime操作时间\n\n\t// 获取当前时间\n    LocalTime now = LocalTime.now();\n\n    // 舍弃纳秒\n    now.withNano(0);\n    \n    /*\n     * 获取特定的时间\n     * Localtime.MIN 00:00\n     * Localtime.MIDNIGHT 00:00\n     * Localtime.NOON 12:00\n     * LocalTime.MAX 23:59:59.999999999\n     */\n    now.with(LocalTime.MIN);\n    now.with(LocalTime.MIDNIGHT);\n    now.with(LocalTime.NOON);\n    now.with(LocalTime.MAX);\n    \n    // of可以传入四个参数\n    LocalTime zero = LocalTime.of(23, 59, 59, 999_999_999);\n    \n    // parse方法可以转换的格式有 HH:mm:ss.nnnnnnnnn HH:mm:ss HH:mm\n    LocalTime last = LocalTime.parse(\"23:59:59.999999999\");\n    \n    // 也可以自定义转换格式\n    DateTimeFormatter formatter = DateTimeFormatter.ofPattern(\"HH:mm:ss\");\n    LocalTime start = LocalTime.parse(\"00:00:00\", formatter);\n\nJDBC映射和新类型关联\n\n\tdate -\u003e LocalDate\n\ttime -\u003e LocalTime\n\ttimestamp -\u003e LocalDateTime\n\n## 代码地址\t\n[https://github.com/huangbuhuan/java8](https://github.com/huangbuhuan/java8)\n\n\u003ca name=\"参考链接\"\u003e\u003c/a\u003e\n## 参考链接\n\n\n1. [函数式编程入门教程](http://www.ruanyifeng.com/blog/2017/02/fp-tutorial.html7)\n2. [Java 8开发的4大顶级技巧](http://www.importnew.com/22417.html)\n3. [Java 8 Optional: How to Use it](http://blog.jhades.org/java-8-how-to-use-optional/)\n4. [Java 8 时间日期库的20个使用示例](http://www.codeceo.com/article/java-8-20-datetime.html)\n5. [如何在Java 8中愉快地处理日期和时间](http://www.liaoxuefeng.com/article/00141939241051502ada88137694b62bfe844cd79e12c32000)\n5. [Java 8学习资料汇总](http://ifeve.com/java8-learning-resources/)\n6. [Java 8中Stream详解](https://www.ibm.com/developerworks/cn/java/j-lo-java8streamapi/)\n7. [Java 8 API在线版地址](http://docs.oracle.com/javase/8/docs/api/index.html)\n8. [《Java8实战》](https://book.douban.com/subject/25912747/)\n9. [《Java8函数式编程》](https://book.douban.com/subject/26346017/)\n10. [《写给大忙人看的Java SE 8》](https://book.douban.com/subject/26274206/comments/hot?p=1)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhuangbuhuan%2Fjava8","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhuangbuhuan%2Fjava8","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhuangbuhuan%2Fjava8/lists"}