关于java8:Java-亿级项目架构设计与落地应用海上升明月

download:Java 亿级我的项目架构设计与落地利用Java是当今最为风行的编程语言之一,被宽泛用于大型项目的开发。对于亿级我的项目,架构设计至关重要,因为它波及到高可用性、伸缩性和安全性等方面。在本文中,咱们将探讨Java亿级我的项目的架构设计与落地利用,并重点介绍H2数据库。 架构设计在设计亿级我的项目的架构时,须要思考以下几个方面: 高可用性对于一个亿级我的项目,必须保证系统可能24/7稳固运行,即便呈现故障也应该可能主动复原。为此,能够采纳多节点部署、负载平衡和容错机制等形式来进步零碎的可用性。 高伸缩性因为亿级我的项目通常须要解决海量数据和用户申请,因而须要具备高伸缩性,即可能疾速扩大节点以满足业务需要。这能够通过分布式架构、微服务架构和云计算技术等实现。 安全性对于任何一个大型项目来说,数据安全都是至关重要的问题。因而,在设计亿级我的项目的架构时,必须思考数据的安全性,包含数据加密、权限管制和破绽修复等方面。 H2数据库H2是一款轻量级的Java数据库,具备高性能、嵌入式和分布式反对等特点,非常适合于亿级我的项目的架构设计。 高性能H2的查问速度十分快,能够通过应用索引和缓存来优化性能。此外,H2能够在内存中运行,从而进一步提高性能。 嵌入式反对H2能够作为一个嵌入式数据库应用,这意味着应用程序能够间接拜访数据库,而无需应用独立的数据库服务器。这不仅不便了开发人员,还能够缩小系统资源的占用。 分布式反对对于亿级我的项目,通常须要采纳分布式架构来实现高伸缩性。H2反对分布式部署,能够将数据库扩散到多个节点上,从而实现数据的摊派和负载平衡。 落地利用在理论我的项目中,咱们能够通过以下形式将Java亿级我的项目的架构设计落地利用: 确定业务需要首先,须要明确我的项目的业务需要和指标,以确定所需的架构设计和技术栈。 抉择适当的技术栈依据业务需要和指标,抉择适当的技术栈,包含开发框架、数据库和其余相干技术。 实现架构设计在确定业务需要和技术栈后,能够开始实现架构设计。这通常包含开发底层框架、搭建零碎基础设施、设计数据库架构等。 测试和优化一旦实现了架构设计,就须要对系统进行测试和优化,以确保零碎的稳定性、性能和安全性等方面。 总结在设计Java亿级我的项目的架构时,须要思考高可用性、高伸缩性和安全性等方面。H2数据库是一款非常适合于亿级我的项目的轻量级数据库,具备高性能、嵌入式和分布式反对等特点。通过抉择适当的技术栈和实现架构设计,能够将Java亿级我的项目的架构落地利用,并实现高效、稳固、平安的零碎。

May 19, 2023 · 1 min · jiezi

关于java8:java8-map新特性

如果应用map计数,当map中不存在这个key时,map.put(key, map.getOrDefault(key, 0) + 1);能够应用merge,更优雅的实现.代码如下: @Testpublic void merge() { Integer key = 4; Map<Integer, Integer> map = new HashMap<>(); map.put(3, map.getOrDefault(3, 0) + 1); map.merge(key, 1, Integer::sum); System.out.println(map.get(3)); System.out.println(map.get(key)); Map<Integer, String> map1 = new HashMap<>(); map1.merge(4, "123", String::concat); System.out.println(map1.get(key)); // 待定 如何实现呢? 参考:computeIfAbsent Map<Integer, Set<String>> map2 = new HashMap<>(); // map2.merge(4, "123", Set::add); System.out.println(map2.get(key));}输入: 对于下面代码中待定的问题,能够参考下列的代码: @Testpublic void computeIfAbsent() { Integer key1 = 4; Map<Integer, Set<String>> map = new HashMap<>(); map.computeIfAbsent(key1, HashSet::new).add("456"); Integer key = 3; Set<String> set = new HashSet<>(); set.add("123"); map.put(key, set); map.computeIfAbsent(key, HashSet::new).add("123456"); System.out.println(map);}输入:如果有其余更优雅的写法,欢送留言交换. ...

March 16, 2023 · 1 min · jiezi

关于java8:京东云开发者|深入JDK中的Optional

概述:Optional最早是Google公司Guava中的概念,代表的是可选值。Optional类从Java8版本开始退出奢华套餐,次要为了解决程序中的NPE问题,从而使得更少的显式判空,避免代码净化,另一方面,也使得畛域模型中所暗藏的常识,得以显式体现在代码中。Optional类位于java.util包下,对链式编程格调有肯定的反对。实际上,Optional更像是一个容器,其中寄存的成员变量是一个T类型的value,可值可Null,应用的是Wrapper模式,对value操作进行了包装与设计。本文将从Optional所解决的问题开始,逐层解剖,由浅入深,文中会呈现Optioanl办法之间的比照,实际,误用状况剖析,优缺点等。与大家一起,对这项Java8中的新个性,进行了解和深刻。 1、解决的问题臭名远扬的空指针异样,是每个程序员都会遇到的一种常见异样,任何拜访对象的办法与属性的调用,都可能会呈现NullPointException,如果要确保不触发异样,咱们通常须要进行对象的判空操作。 举个栗子,有一个人(Shopper)进超市购物,可能会用购物车(Trolley)也可能会用其它形式,购物车里可能会有一袋栗子(Chestnut),也可能没有。三者定义的代码如下: PlainJavascriptJavaHTML/XMLMarkdownMakefileGoJSONSQLObjective-cYAMLBashPHPPythonpublic class Shopper { private Trolley trolley; public Trolley getTrolley(){ return trolley; }}public class Trolley { private Chestnut chestnut; public Chestnut getChestnut(){ return chestnut; }}public class Chestnut { private String name; public String getName(){ return name; }}这时想要取得购物车中栗子的名称,像上面这么写,就可能会见到咱们的“老朋友”(NPE) PlainJavascriptJavaHTML/XMLMarkdownMakefileGoJSONSQLObjective-cYAMLBashPHPPythonpublic String result(Shopper shopper){ return shopper.getTrolley().getChestnut().getName();}为了能避免出现空指针异样,通常的写法会逐层判空(多层嵌套法),如下 PlainJavascriptJavaHTML/XMLMarkdownMakefileGoJSONSQLObjective-cYAMLBashPHPPythonpublic String result(Shopper shopper) { if (shopper != null) { Trolley trolley = shopper.getTrolley(); if (trolley != null) { Chestnut chestnut = trolley.getChestnut(); if (chestnut != null) { return chestnut.getName(); } } } return "获取失败辽"; }多层嵌套的办法在对象级联关系比拟深的时候会看的目迷五色的,尤其是那一层一层的括号;另外出错的起因也因为不足对应信息而被含糊(例如trolley为空时也只返回了最初的获取失败。当然也能够在每一层减少return,相应的代码有会变得很简短),所以此时咱们也能够用遇空则返回的卫语句进行改写。 ...

November 7, 2022 · 6 min · jiezi

关于java8:java8的stream将一个List转为按照某个字段分组的map再按照另一个字段取max最终得到一个map

java8的stream将一个List转为依照某个字段分组的map,(Map<String, List<Owner>>)而后再依照 更新日期 字段取分组的每个list里最大的那个,Map<String, Owner>最终失去一个map List<Owner> ---> (Map<String, List<Owner>>) ----> Map<String, Owner>1. Owner对象构造import com.baomidou.mybatisplus.annotation.*;import lombok.AllArgsConstructor;import lombok.Builder;import lombok.Data;import lombok.NoArgsConstructor;import java.io.Serializable;import java.util.Date;@Builder@AllArgsConstructor@NoArgsConstructor@Datapublic class Owner implements Serializable { /** * 成员名称 */ private String name; /** * 身份证号 */ private String idcard; /** * 创立工夫 */ private Date createTime; /** * 更新工夫 */ private Date updateTime;}2. 处理过程 @Test void testList() throws ParseException { List<Owner> list = new ArrayList<>(); // 获得字符串示意的Date对象 Date d1 = DateUtils.toDate("1662-05-04 22:22:22"); Date d2 = DateUtils.toDate("0599-01-23 00:00:00"); Date d3 = DateUtils.toDate("1328-10-21 11:11:11"); Owner o1 = Owner.builder().idcard("1001").updateTime(d1).name("康熙").build(); Owner o2 = Owner.builder().idcard("1001").updateTime(d2).name("李世民").build(); Owner o3 = Owner.builder().idcard("1001").updateTime(d3).name("朱元璋").build(); Owner o4 = Owner.builder().idcard("1002").updateTime(d1).name("张三").build(); Owner o5 = Owner.builder().idcard("1003").updateTime(d1).name("李四").build(); list.add(o1); list.add(o2); list.add(o3); list.add(o4); list.add(o5); // 将List依照Owner对象的 idcard 字段分组 失去map Map<String, List<Owner>> listMap = list.stream().collect(Collectors.groupingBy(Owner::getIdcard)); // java8 Stream max函数应用的比拟器:依照updateTime字段比拟 Comparator<Owner> comparator = Comparator.comparing(Owner::getUpdateTime); // Map转换,获得每个idcard的最初更新的对象(多取一) Map<String, Owner> resultMap = new HashMap<>(); listMap.entrySet().stream().forEach(e-> { Owner owner = e.getValue().stream().max(comparator).get(); resultMap.put(e.getKey(), owner); }); // 最终失去 每个idcard一个对象的map System.out.println(GsonUtils.toGson(resultMap));3. 最终后果:{ "1003":{ "name":"李四", "idcard":"1003", "updateTime":"1662-05-04 22:22:22" }, "1002":{ "name":"张三", "idcard":"1002", "updateTime":"1662-05-04 22:22:22" }, "1001":{ "name":"康熙", "idcard":"1001", "updateTime":"1662-05-04 22:22:22" }}

July 4, 2022 · 1 min · jiezi

关于java8:java8-lambda和Stream-API

java8lambdalambda表达式可作为参数传递给办法应用@FunctionalInterface 自定义函数式接口将接口作为参数传递给办法调用办法时传递lambda表达式java 内置心函数式接口Consumer<T> 消费性接口 泛型是参数 无返回值 调用办法是 void accept (T t)Supplier<T> 供应型接口 无参数 泛型是返回值 调用办法是 T get()Function<T,R> 函数型接口 T泛型为参数 R泛型为返回值 调用办法是 R apply(T t)Predicate<T> 断言式接口 泛型是参数 返回boolean值 调用办法是 boolean test(T t)Stream API创立Stream -> 两头操作 ->终止操作 从一个流转化成另一个流创立Stream list.stream、Array.stream(args[])、stream.of(values ...)、stream.iterate(final T seed, final UnaryOperator<T>f)两头操作:distinct()、 limit(long l)、 skip(long l)、 filter(Predicate p)、 map(Function f)、 flatMap(Function f) 、sorted()(Comparator c)终止操作:allMatch(Predicate p)、anyMatch(Predicate p)、findFirst()、finAny()、count()、max()、min()、reduce(T iden, BinaryOperator b) (BinaryOperator b)collect(Collector c) parallel()与sequential() 并行流与程序流

June 13, 2022 · 1 min · jiezi

关于java8:java8实战学习

[toc] java8实战学习1. lambda表达式1.1 什么是lambda表达式1.2 什么样的场景能应用lambda表达式1.3 lambda表达式实现一个接口的四种写法2. 函数式编程2.1 什么是函数式编程2.2 什么是命令式编程2.3 什么是函数式接口 FunctionalInterface2.4 什么是 default 办法2.5 default办法的意义2.6 java8内置的罕用函数式接口(1). Predicate<T>断言 -> 输出T, 输入 boolean (2). Consumer<T>生产一个输出 -> 输出T, 不输入(void) (3). Supplier<T>生产一个输入 -> 不输出, 输入T (4). Function<T, R>输出T, 输入R的函数 (5). UnaryOperator<T>一元函数: 输出1个输入 1个: 类型都是T (6). BinaryOperatior<T>二元函数: 输出2个输入1个: 类型都是T (7). BiFunction<T, U, R>输出两个输入一个: 输出 T, U 输入 R, 罕用于 reduce/sort等操作, 2.7 办法援用(1). 静态方法的办法援用(2). 实例办法的办法援用(3). 构造方法的办法援用2.8. 变量援用和隐式final为何外部类应用内部变量要是final的3. stream流式编程3.1. 内部迭代和外部迭代(1). 什么是内部迭代(2). 什么是外部迭代3.2. 两头操作/终止操作/惰性求值(1). 什么是两头操作?返回还是流stream的操作, 就是两头操作, 例如 map操作 ...

May 17, 2022 · 3 min · jiezi

关于java8:Java8-判空新写法

引言在文章的结尾,先说下NPE问题,NPE问题就是,咱们在开发中常常碰到的NullPointerException.假如咱们有两个类,他们的UML类图如下图所示 图片 在这种状况下,有如下代码 user.getAddress().getProvince();这种写法,在user为null时,是有可能报NullPointerException异样的。为了解决这个问题,于是采纳上面的写法 if(user!=null){ Address address = user.getAddress(); if(address!=null){ String province = address.getProvince(); }}这种写法是比拟俊俏的,为了防止上述俊俏的写法,让俊俏的设计变得优雅。JAVA8提供了Optional类来优化这种写法,接下来的注释局部进行具体阐明 一个连载多年还在持续更新的收费教程:http://blog.didispace.com/spr... API介绍先介绍一下API,与其余文章不同的是,本文采取类比的形式来讲,同时联合源码。而不像其余文章一样,一个个API列举进去,让人找不到重点。 1、Optional(T value),empty(),of(T value),ofNullable(T value)这四个函数之间具备相关性,因而放在一组进行记忆。 先阐明一下,Optional(T value),即构造函数,它是private权限的,不能由内部调用的。其余三个函数是public权限,供咱们所调用。那么,Optional的实质,就是外部贮存了一个实在的值,在结构的时候,就直接判断其值是否为空。好吧,这么说还是比拟形象。间接上Optional(T value)构造函数的源码,如下图所示 图片 那么,of(T value)的源码如下 public static <T> Optional<T> of(T value) { return new Optional<>(value);}也就是说of(T value)函数外部调用了构造函数。依据构造函数的源码咱们能够得出两个论断: 通过of(T value)函数所结构出的Optional对象,当Value值为空时,仍然会报NullPointerException。通过of(T value)函数所结构出的Optional对象,当Value值不为空时,能失常结构Optional对象。除此之外呢,Optional类外部还保护一个value为null的对象,大略就是长上面这样的 public final class Optional<T> { //省略.... private static final Optional<?> EMPTY = new Optional<>(); private Optional() { this.value = null; } //省略... public static<T> Optional<T> empty() { @SuppressWarnings("unchecked") Optional<T> t = (Optional<T>) EMPTY; return t; }}那么,empty()的作用就是返回EMPTY对象。 ...

April 29, 2022 · 2 min · jiezi

关于java8:Java-之父呼吁弃用-Java-8苹果手机或将改用-USBC-充电器Nodejs-18-发布-思否周刊

40s 新闻速递2023 年 4 月 11 日之后微软将不再为 Office 2013 提供安全更新因不附带充电器,苹果在巴西被判抵偿消费者 7000 元微软或在 Xbox 收费游戏中放广告 最快第三季度启用平安专家发现新型歹意 Windows 11 网站美国上诉法院裁决 Web 抓取非法465 亿美元融资承诺函到手 马斯克思考对 Twitter 提出收买要约欧盟将在所有智能手机中应用 USB-C 充电器,包含苹果被罚 1.5 亿欧元后 Google 发表启用全新 Cookies 同意书macOS 服务器利用进行服务 现有用户可在持续下载应用Java 之父呐喊用户弃用 Java 8Visual Studio 2019 v16.11.13 正式公布eGuideDog Linux 0.9 公布Ubuntu 22.04 LTS (Jammy Jellyfish) 已公布Node.js 18 公布W3C 公布 WebAssembly 2.0 初版草案行业资讯2023 年 4 月 11 日之后微软将不再为 Office 2013 提供安全更新据微软官方消息,在 2023 年 4 月 11 日之后微软将不再为 Office 2013 和 Skype for Business 2015 提供安全更新。 ...

April 23, 2022 · 2 min · jiezi

关于java8:ListT-转-MapK-T通用方法

咱们开发过程中常常遇到把List<T>转成map对象的场景,同时须要对key值雷同的对象做个合并,lambda曾经做得很好了。定义两个实体类别离命名为A、B。 @Dataclass A { private String a1; private String a2; private String a3; public A(String a1, String a2, String a3) { this.a1 = a1; this.a2 = a2; this.a3 = a3; }}@Dataclass B { private String b1; private String b2; private String b3; public B(String b1, String b2, String b3) { this.b1 = b1; this.b2 = b2; this.b3 = b3; }}lambda转换代码: @Testpublic void test1() { List<A> aList = new ArrayList<>(); aList.add(new A("a1", "a21", "a3")); aList.add(new A("a1", "a22", "a3")); aList.add(new A("a11", "a23", "a3")); aList.add(new A("a11", "a24", "a3")); aList.add(new A("a21", "a25", "a3")); System.out.println(aList); Map<String, A> tagMap = CollectionUtils.isEmpty(aList) ? new HashMap<>() : aList.stream().collect(Collectors.toMap(A::getA1, a -> a, (k1, k2) -> k1)); System.out.println("----------------------"); System.out.println(tagMap); System.out.println("----------------------");}能不能把转换的过程提取成公共办法呢?我做了个尝试,公共的转换方法如下: ...

April 19, 2022 · 2 min · jiezi

关于java8:谈谈Java818引入的新特性

Java8于2014年3月18日公布,截止到2022年4月6日,以后最新发行版本是Java18。版本17、11和8是目前反对的长期反对(LTS)版本。这篇文章率领大家回顾从Java 8 开始每个版本的个性,小板凳坐好,发车了! 版本概览Java8 LTS 上一次商业用途的免费软件公共更新是在2019年1月由 Oracle 公布的,而 Oracle 持续更新并公布收费的公共 java8,用于开发和集体用处。java7不再受公众反对。对于java11,Oracle不会为公众提供长期反对; 相同,更宽泛的 OpenJDK 社区,如 Eclipse Adoptium 或其余社区,将会代替Oracle提供这类的反对。 上图展现了从Java SE 8开始到Java SE 18的历史版本公布过程,秉着2017年9月,Java 平台的首席架构师 Mark Reinhold 提议将公布列车改为“每六个月公布一个个性”的约定,也给出了将来到Java SE 21的公布布局。 Java18的个别可用性开始于2022年3月22日,最新的(第三次) LTS Java 17开始于2021年9月14日。java19正在开发中,晚期拜访构建曾经可用。 Java 8 个性Lambda 表达式容许咱们应用函数作为办法参数。 让咱们来看看 Java 8之前的代码,过后咱们必须创立一个匿名类来实现一个简略的接口。 Thread t = new Thread(new Runnable() { public void run() { System.out.println("Start thread"); }});复制代码应用 lambda 表达式,咱们能够这样做。 Thread t1 = new Thread(() -> { System.out.println("Start 1st thread");});复制代码函数接口是只有一个形象办法的接口。此外,Interface 能够有默认办法和静态方法,但只有一个形象办法。 Stream 是java.util.Stream包中的一个接口,它提供了对汇合执行程序和并行操作的办法。Collection Interface 的 Stream ()办法返回给定汇合的类型为 Stream 的元素流。流接口反对过滤、映射或查找流中元素的聚合后果所需的许多操作。 ...

April 6, 2022 · 2 min · jiezi

关于java8:73万字肝爆Java8新特性我不信你能看完建议收藏

大家好,我是冰河~~ 说实话,肝这篇文章花了我一个月的工夫,对于Java8的新个性全在这儿了,倡议先珍藏后浏览。 Java8有哪些新个性? 简略来说,Java8新个性如下所示: Lambda表达式函数式接口办法援用与结构器援用Stream API接口的默认办法与静态方法新工夫日期API其余新个性其中,援用最宽泛的新个性是Lambda表达式和Stream API。 Java8有哪些长处? 简略来说Java8长处如下所示。 速度更快代码更少(减少了新的语法Lambda表达式)弱小的Stream API便于并行最大化缩小空指针异样OptionalLambda表达式什么是Lambda表达式?Lambda表达式是一个匿名函数,咱们能够这样了解Lambda表达式:Lambda是一段能够传递的代码(可能做到将代码像数据一样进行传递)。应用Lambda表达式可能写出更加简洁、灵便的代码。并且,应用Lambda表达式可能使Java的语言表达能力失去晋升。 匿名外部类在介绍如何应用Lambda表达式之前,咱们先来看看匿名外部类,例如,咱们应用匿名外部类比拟两个Integer类型数据的大小。 Comparator<Integer> com = new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return Integer.compare(o1, o2); }};在上述代码中,咱们应用匿名外部类实现了比拟两个Integer类型数据的大小。 接下来,咱们就能够将上述匿名外部类的实例作为参数,传递到其余办法中了,如下所示。 TreeSet<Integer> treeSet = new TreeSet<>(com);残缺的代码如下所示。 @Testpublic void test1(){ Comparator<Integer> com = new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return Integer.compare(o1, o2); } }; TreeSet<Integer> treeSet = new TreeSet<>(com);}咱们剖析下上述代码,在整个匿名外部类中,实际上真正有用的就是上面一行代码。 return Integer.compare(o1, o2);其余的代码实质上都是“冗余”的。然而为了书写下面的一行代码,咱们不得不在匿名外部类中书写更多的代码。 Lambda表达式如果应用Lambda表达式实现两个Integer类型数据的比拟,咱们该如何实现呢? ...

January 5, 2022 · 23 min · jiezi

关于java8:java8之flatMap应用

@Test public void testFlatMap() { Teacher yuwen1 = Teacher.builder().teacherName("飞老师").level(1).build(); Teacher yuwen2 = Teacher.builder().teacherName("木老师").level(2).build(); Teacher shuxue1 = Teacher.builder().teacherName("算老师").level(3).build(); List<Teacher> teacherList = new ArrayList<>(Arrays.asList(yuwen1, yuwen2)); List<Teacher> teacher2List = new ArrayList<>(Arrays.asList(shuxue1)); Student zhangsan = Student.builder().name("张三").gender("男").teacherList(teacherList).build(); Student lisi = Student.builder().name("李四").gender("男").teacherList(teacherList).build(); Student wangwu = Student.builder().name("王五").gender("女").teacherList(teacher2List).build(); List<Student> students = new ArrayList<>(Arrays.asList(zhangsan, lisi, wangwu)); Set<Teacher> allStudentsTeachers = students.stream().flatMap(e -> e.getTeacherList().stream()).collect(Collectors.toSet()); allStudentsTeachers.stream().forEach(System.out::println); }留神是: e -> e.getTeacherList().stream()留神 外部list还要被"化骨绵掌"击为stream!!!

December 17, 2021 · 1 min · jiezi

关于java8:JAVA8新方法也不新啦我们老啦

就记录在这吧,尽管这个名字叫JAVA8新办法,然而实际上JAVA8一点也不新啦,次要是咱们老了list的removeIf办法 List<String> list1 = Arrays.asList("one","two","three","four","five","six","seven");List<String> list2 = new ArrayList<>(list1);//删除boolean result = list2.removeIf(s -> s.length() > 4);System.out.println(result);System.out.println(list2.stream().collect(Collectors.joining(",")));//输入trueone,two,four,five,six//替换list2.replaceAll(s->s.toUpperCase());System.out.println(list2.stream().collect(Collectors.joining(",")));//输入ONE,TWO,FOUR,FIVE,SIX//排序list2.sort(Comparator.naturalOrder());System.out.println(list2.stream().collect(Collectors.joining(",")));//输入FIVE,FOUR,ONE,SIX,TWO比拟 Comparator<Person> comparator = Comparator.comparing(Person::getName).thenComparing(Person::getAge);//反向比拟Comparator<Person> comparatorReversed = comparator.reversed();//默认字母程序Comparator<String> comparator1 = Comparator.naturalOrder();//先按空后再依照字母程序Comparator<String> comparator2 = Comparator.nullsFirst(Comparator.naturalOrder());//先依照字母程序,最初排空Comparator<String> comparator3 = Comparator.nullsLast(Comparator.naturalOrder());//比拟Long max = Long.max(1L,2L);BinaryOperator<Long> sum = (s1,s2) -> s1 + s2;sum = Long::sum;hashCode Long l = 2234324234234324L;int hash = l.hashCode();System.out.println(hash);hash = Long.hashCode(l);System.out.println(hash);//输入642554319642554319Map forEach,getOrDefault,putIfAbsent Map<String,Object> map =new HashMap<>();map.put("key","value");map.forEach((key,value)-> System.out.println(key+" "+value));//输入key value//getOrDefaultPerson deafulPerson = new Person();deafulPerson.setName("Test");Person p = (Person) map.getOrDefault("p",deafulPerson);System.out.println(p.getName());//输入TestPerson p1 = new Person();p1.setName("Test11");//putIfAbsentmap.putIfAbsent("p", p);System.out.println("putIfAbsent=="+map.get("p"));//替换key为p的值为p1map.replace("p", p1);System.out.println("replace=="+map.get("p"));//替换key值为p的为defaultPeronmap.replace("p", p1,deafulPerson);System.out.println("replaceNew=="+map.get("p"));//lambda替换map.replaceAll((key,oldPerson) -> p1);System.out.println("replaceAll=="+map.get("p"));//输入putIfAbsent==Person{name='Test', age=0}replace==Person{name='Test11', age=0}replaceNew==Person{name='Test', age=0}replaceAll==Person{name='Test11', age=0}

October 25, 2021 · 1 min · jiezi

关于java8:ConcurrentHashMap源码深度分析

1、根本变量// Unsafe mechanics//Unsafe类是用来做cas操作的,都是native办法,代码由C++实现,上面的变量示意对应变量的偏移//例如:public final native boolean compareAndSwapInt(Object o, long offset, int expected, int x);// 示意对象o偏移地位offset的变量如果和期望值expected相等,把变量值设置为xprivate static final sun.misc.Unsafe U;private static final long SIZECTL;private static final long TRANSFERINDEX;private static final long BASECOUNT;private static final long CELLSBUSY;private static final long CELLVALUE;private static final long ABASE;private static final int ASHIFT;1、table初始化1、table会提早到第一次put时初始化,同过应用循环+CAS的套路,能够保障一次只有一个线程会初始化table。2、在table为空的时候如果sizeCtl小于0,则阐明曾经有线程开始初始化了,其它线程通过Thread.yield()让出CPU工夫片,期待table非空即可。3、否则应用CAS将sizeCtl的值换为-1,置换胜利则初始化table。4、留神table的大小为sizeCtl,初始化后将sizeCtl的值设为n - (n >>> 2)即0.75n,这个值用来确定是否须要为table扩容。 //Initializes table, using the size recorded in sizeCtl.private final Node<K,V>[] initTable() { Node<K,V>[] tab; int sc; while ((tab = table) == null || tab.length == 0) { //判断是否曾经有线程在初始化,如果有则让出CPU,之后持续自旋判断 if ((sc = sizeCtl) < 0) Thread.yield(); // lost initialization race; just spin //cas操作设置sizeCtl的值 else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) { try { //持续判断双重查看 if ((tab = table) == null || tab.length == 0) { int n = (sc > 0) ? sc : DEFAULT_CAPACITY; @SuppressWarnings("unchecked") //初始化table Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n]; table = tab = nt; sc = n - (n >>> 2);//设置sizeCtl=0.75n } } finally { sizeCtl = sc; } break; } } return tab;}2、put操作(putVal办法)1、首先计算key的hash值2、判断table是否为空,如果是就初始化3、依据hash值取余确定桶的地位,并判断桶是否为空,如果是空,通过cas操作设置进去4、如果桶的第一个节点非空,并且hash=MOVED,阐明有线程正在进行扩容,调用helpTransfer帮忙扩容5、对桶加锁并判断节点是链表还是树,依据不同状况插入节点6、判断是否达到链表转树的阈值7、统计节点数 ...

August 12, 2021 · 6 min · jiezi

关于java8:JAVA8实战-日期API

JAVA8实战 - 日期API前言 这一节咱们来讲讲JAVA8的日期类,源代码的作者其实就是Joda-Time,所以能够看到很多代码的API和Joda类比拟像。日期类始终是一个比拟难用的货色,然而JAVA8给日期类提供了一套新的API让日期类更加好用。 本文代码较多,倡议亲自运行代码了解。 内容概述:对于JDK8日期的三个外围类:LocalDate、LocalTime、LocalDateTime的相干介绍机器工夫和日期格局Instant等对于细粒度的工夫操作介绍TemporalAdjusters 用于更加简单的日期计算,比方计算下一个工作日的时候这个类提供了一些实现DateTimeFormatter 格式化器,十分的灵便多变,属于SimpleDateFormat的替代品。日期API的一些集体工具封装举例,以及在应用JDK8的时候一些集体的踩坑 最初心愿通过本文能帮你解脱new Date() 什么是ISO-8601? 日期离不开ISO-8601,上面对ISO-8601简略形容一下,参考自百度百科: ISO-8601: 国际标准化组织制订的日期和工夫的示意办法,全称为《数据存储和替换模式·信息替换·日期和工夫的示意办法》,简称为ISO-8601。日的示意:小时、分和秒都用2位数示意,对UTC工夫最初加一个大写字母Z,其余时区用理论工夫加时差示意。如UTC工夫下午2点30分5秒示意为14:30:05Z或143005Z,过后的北京工夫示意为22:30:05+08:00或223005+0800,也能够简化成223005+08。日期和工夫的组合示意:合并示意时,要在工夫后面加一大写字母T,如要示意北京工夫2004年5月3日下午5点30分8秒,能够写成2004-05-03T17:30:08+08:00或20040503T173008+08。LocalDate、LocalTime、LocalDateTime JDK8把工夫拆分成了三个大部分,一个是工夫,代表了年月日的信息,一个是日期,代表了时分秒的局部,最初是这两个对象总和具体的工夫。 LocalDate LocalDate:类示意一个具体的日期,但不蕴含具体工夫,也不蕴含时区信息。能够通过LocalDate的静态方法of()创立一个实例,LocalDate也蕴含一些办法用来获取年份,月份,天,星期几等,上面是LocalDate的常见应用形式: @Test public void localDateTest() throws Exception { // 创立一个LocalDate: LocalDate of = LocalDate.of(2021, 8, 9); // 获取以后工夫 LocalDate now = LocalDate.now(); // 格式化 LocalDate parse1 = LocalDate.parse("2021-05-11"); // 指定日期格式化 LocalDate parse2 = LocalDate.parse("2021-05-11", DateTimeFormatter.ofPattern("yyyy-MM-dd")); // 上面的代码会呈现格式化异样 // java.time.format.DateTimeParseException: Text '2021-05-11 11:53:53' could not be parsed, unparsed text found at index 10// LocalDate parse3 = LocalDate.parse("2021-05-11 11:53:53", DateTimeFormatter.ofPattern("yyyy-MM-dd")); // 正确的格式化办法 LocalDate parse3 = LocalDate.parse("2021-05-11 11:53:53", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); // 以后工夫 System.out.println("now() => "+ now); // 获取月份 int dayOfMonth = parse1.getDayOfMonth(); System.out.println("dayOfMonth => " + dayOfMonth); // 获取年份 int dayOfYear = parse1.getDayOfYear(); System.out.println("getDayOfYear => " + dayOfYear); // 获取那一周,留神这里获取的是对象 DayOfWeek dayOfWeek = parse1.getDayOfWeek(); System.out.println("getDayOfWeek => " + dayOfWeek); // 获取月份数据 int monthValue = parse3.getMonthValue(); System.out.println("getMonthValue => " + monthValue); // 获取年份 int year = parse3.getYear(); System.out.println("getYear => " + year); // getChronology 获取的是以后工夫的排序,这里输入后果是 ISO System.out.println("getChronology => " + parse3.getChronology()); System.out.println("getEra => " + parse3.getEra()); // 应用timeField获取值:TemporalField 是一个接口,定义了如何拜访 TemporalField 的值,ChronnoField 实现了这个接口 /* LocalDate 反对的格局如下: case DAY_OF_WEEK: return getDayOfWeek().getValue(); case ALIGNED_DAY_OF_WEEK_IN_MONTH: return ((day - 1) % 7) + 1; case ALIGNED_DAY_OF_WEEK_IN_YEAR: return ((getDayOfYear() - 1) % 7) + 1; case DAY_OF_MONTH: return day; case DAY_OF_YEAR: return getDayOfYear(); case EPOCH_DAY: throw new UnsupportedTemporalTypeException("Invalid field 'EpochDay' for get() method, use getLong() instead"); case ALIGNED_WEEK_OF_MONTH: return ((day - 1) / 7) + 1; case ALIGNED_WEEK_OF_YEAR: return ((getDayOfYear() - 1) / 7) + 1; case MONTH_OF_YEAR: return month; case PROLEPTIC_MONTH: throw new UnsupportedTemporalTypeException("Invalid field 'ProlepticMonth' for get() method, use getLong() instead"); case YEAR_OF_ERA: return (year >= 1 ? year : 1 - year); case YEAR: return year; case ERA: return (year >= 1 ? 1 : 0); * */ // Unsupported field: HourOfDay// System.out.println("ChronoField.HOUR_OF_DAY => " + parse1.get(ChronoField.HOUR_OF_DAY)); // Unsupported field: MinuteOfHour// System.out.println("ChronoField.MINUTE_OF_HOUR => " + parse1.get(ChronoField.MINUTE_OF_HOUR)); // Unsupported field: MinuteOfHour// System.out.println("ChronoField.SECOND_OF_MINUTE => " + parse1.get(ChronoField.SECOND_OF_MINUTE)); System.out.println("ChronoField.YEAR => " + parse1.get(ChronoField.YEAR)); // Unsupported field: MinuteOfHour// System.out.println("ChronoField.INSTANT_SECONDS => " + parse1.get(ChronoField.INSTANT_SECONDS)); }/*运行后果: now() => 2021-08-08 dayOfMonth => 11 getDayOfYear => 131 getDayOfWeek => TUESDAY getMonthValue => 5 getYear => 2021 getChronology => ISO getEra => CE ChronoField.YEAR => 2021 */TemporalField 是一个接口,定义了如何拜访 TemporalField 的值,ChronnoField 实现了这个接口LocalTime LocalTime:和LocalDate相似,区别在于蕴含具体工夫,同时领有更多操作具体工夫工夫的办法,上面是对应的办法以及测试: ...

August 8, 2021 · 8 min · jiezi

关于java8:JAVA8实战-Optional工具类

前言 没错,这又是一个新的专栏,JAVA8能够说是JAVA划时代的一个版本,简直是让JAVA焕发了第三春(第二春在JDK5),当然外面的新个性也是非常重要的,尽管Java当初都曾经到了10几的版本,然而国内少数应用的版本还是JAVA8,所以这个系列将会围绕Java8的新个性和相干工具做一些总结。心愿对大家日常学习和工作中有所帮忙。 概述:日常工作学习咱们大抵是如何躲避空指针的。对于Optional的零碎介绍,常见的应用和解决办法Optional的应用场景以及一些小型案例代码来看看《Effective Java》这个作者如何对待Optional这个工具类>空指针躲避 在讲述Optional之前,咱们来看下通常状况下咱们是如何避免空指针的。 字符串equals 字符串的操作是最常见的操作,应用字符串的equals办法很有可能抛出空指针异样,比方像上面的代码,如果a变量为Null,则毫无疑问会抛出空指针异样: a.equals("aaa"); 倡议:应用Objects.equals()或者应用其余工具类办法代替,或者确保obj.equals(target)的obj对象不会为null,比方"test".equals(target)。 比方咱们应用上面的办法保障equals的时候统一: public Tank createTank(String check){ Tank tank = null; if(Objects.equals(check, "my")){ tank = new MyTank(); }else if(Objects.equals(check, "mouse")){ tank = new MouseTank(); }else if (Objects.equals(check, "big")){ tank = new BigTank(); }else { throw new UnsupportedOperationException("unsupport"); } return tank;} 变量 == 操作 变量的==操作也是用的非常多,通常状况下和null搭配的比拟多,咱们通常须要留神上面这些事项: 确保比拟类型统一,比方最经典的Integer和int比拟在超过127的时候为false的问题。应用框架工具类的equals() 进行代替应用Objects.equals()办法代替 特别强调一下Integer的 ==操作的一些陷阱,特地留神最初一个打印是False,具体的起因有网上很多材料,这里就不啰嗦了: public static void main(String[] args) { Integer a = 1; Integer b = 256; System.out.println(a == null); System.out.println(a == b); System.out.println(a == 1); System.out.println(b == 256); System.out.println(b == 257); }/*运行后果: false false true true false */汇合元素为null 如果在一个List或者Set中存在Null元素,那么遍历的时候也很容易呈现空指针的问题,通常状况下咱们能够应用Stream.filter进行过滤,比方像上面这样,这里应用了StringUtils::isNotBlank来判断是否为空字符串并过滤掉所有的空字符串和Null元素: ...

August 8, 2021 · 6 min · jiezi

关于java8:CompletableFuture详解2

这篇文章介绍 Java 8 的 CompletionStage API 和它的规范库的实现 CompletableFuture。API通过例子的形式演示了它的行为,每个例子演示一到两个行为。 既然CompletableFuture类实现了CompletionStage接口,首先咱们须要了解这个接口的契约。它代表了一个特定的计算的阶段,能够同步或者异步的被实现。你能够把它看成一个计算流水线上的一个单元,最终会产生一个最终后果,这意味着几个CompletionStage能够串联起来,一个实现的阶段能够触发下一阶段的执行,接着触发下一次,接着…… 除了实现CompletionStage接口, CompletableFuture也实现了future接口, 代表一个未实现的异步事件。CompletableFuture提供了办法,可能显式地实现这个future,所以它叫CompletableFuture。 1、 创立一个实现的CompletableFuture 最简略的例子就是应用一个预约义的后果创立一个实现的CompletableFuture,通常咱们会在计算的开始阶段应用它。 static void completedFutureExample() { CompletableFuture cf = CompletableFuture.completedFuture("message");assertTrue(cf.isDone());assertEquals("message", cf.getNow(null));}getNow(null)办法在future实现的状况下会返回后果,就比方下面这个例子,否则返回null (传入的参数)。 2、运行一个简略的异步阶段 这个例子创立一个一个异步执行的阶段: static void runAsyncExample() { CompletableFuture cf = CompletableFuture.runAsync(() -> { assertTrue(Thread.currentThread().isDaemon()); randomSleep();});assertFalse(cf.isDone());sleepEnough();assertTrue(cf.isDone());}通过这个例子能够学到两件事件: CompletableFuture的办法如果以Async结尾,它会异步的执行(没有指定executor的状况下), 异步执行通过ForkJoinPool实现, 它应用守护线程去执行工作。留神这是CompletableFuture的个性, 其它CompletionStage能够override这个默认的行为。 参考浏览:工作并行执行神器:Fork&Join框架 3、在前一个阶段上利用函数 上面这个例子应用后面 #1 的实现的CompletableFuture, #1返回后果为字符串message,而后利用一个函数把它变成大写字母。 static void thenApplyExample() { CompletableFuture cf = CompletableFuture.completedFuture("message").thenApply(s -> { assertFalse(Thread.currentThread().isDaemon()); return s.toUpperCase();});assertEquals("MESSAGE", cf.getNow(null));}留神thenApply办法名称代表的行为。 then意味着这个阶段的动作产生以后的阶段失常实现之后。本例中,以后节点实现,返回字符串message。 Apply意味着返回的阶段将会对后果前一阶段的后果利用一个函数。 函数的执行会被阻塞,这意味着getNow()只有打斜操作被实现后才返回。 另外,关注公众号Java技术栈,在后盾回复:面试,能够获取我整顿的 Java 并发多线程系列面试题和答案,十分齐全。 4、在前一个阶段上异步利用函数 通过调用异步办法(办法后边加Async后缀),串联起来的CompletableFuture能够异步地执行(应用ForkJoinPool.commonPool())。 static void thenApplyAsyncExample() { ...

July 18, 2021 · 4 min · jiezi

关于java8:Java-8-StreamBox

Java 8 StreamBox Java 8的装箱流1. 什么是 盒装流(Boxed Stream)在java8 中,如果咱们想把一个对象流转变成一个汇合,咱们能够应用Collectors 类中的一个静态方法 List<String> strings = Stream.of("how", "to", "do", "in", "java") .collect(Collectors.toList());然而对于根本类型的数据缺失不适合的 // 编译谬误IntStream.of(1,2,3,4,5)// .collect(Collectors.toList());如果想不呈现编译不出错,咱们必须打包这个元素,而后再汇合中收集被包装的对象,这种类型的流称为 盒装流 2. 将 int 流转换成 Integer 汇合List<Integer> ints = IntStream.of(1,2,3,4,5) .boxed() .collect(Collectors.toList()); System.out.println(ints); //间接对流进行操作,获取最大值Optional<Integer> max = IntStream.of(1,2,3,4,5) .boxed() .max(Integer::compareTo); System.out.println(max)3. LongStream将 long 类型的流转换成成 Long 类型 List<Long> longs = LongStream.of(1l,2l,3l,4l,5l) .boxed() .collect(Collectors.toList());4. doubleStreamList<Double> doubles = DoubleStream.of(1d,2d,3d,4d,5d) .boxed() .collect(Collectors.toList());

July 14, 2021 · 1 min · jiezi

关于java8:Java-Stream-API

Java Stream API [TOC] Java8 中 的Steam 能够定义为来自起源的元素序列,Streams反对对元素进行聚合操作,这里的元素指的是为流提供数据的汇合和 数组,在聚合操作中咱们能够依据咱们需要来获取出合乎咱们要求的数据 在操作Stream 流之前咱们应该晓得,Streams API 都是间接针对流的操作,因而首先咱们要先会创立一个 Steam。 在粒度级别,Collection 和 Stream 之间的区别与计算事物的工夫无关。甲Collection是一个存储器内数据结构,其中认为所述数据结构以后具备的所有值。必须先计算汇合中的每个元素,而后能力将其增加到汇合中。Stream 在概念上是一个管道,其中元素是按需计算的。 这个概念带来了显着的编程劣势。这个想法是,用户将仅从 Stream 中提取他们须要的值,并且这些元素仅在须要时(对用户不可见)生成。这是生产者-消费者关系的一种模式。 在 Java 中,java.util.Stream示意能够对其执行一个或多个操作的流。流操作要么是两头的,要么是终端的。 的终端操作返回一个特定类型的后果和两头操作返回流自身,所以咱们能够连锁的一排的多个办法,以在多个步骤中执行该操作。 流是在源上创立的,例如java.util.Collection喜爱List或Set。在Map不间接反对,咱们能够创立映射键,值。 流操作能够程序或并行执行。当并行执行时,它被称为并行流 1. 创立流上面给出了一些创立流的形式 1.1 Stream.of() public static void main(String[] args) { // 通过Stream.of 办法获取一个数据流 Stream<Integer> stream = Stream.of(1,2,3,4,5,6,7,8,9); stream.forEach(p -> System.out.println(p)); }1.2 Stream.of(数组)咱们能够通过引入一个数组的形式生成一个流 public static void main(String[] args) { Stream<Integer> stream = Stream.of( new Integer[]{1,2,3,4,5,6,7,8,9} ); stream.forEach(p -> System.out.println(p)); }1.3 列表.steam( 罕用)工作中咱们常常应用通过一个汇合来获取一个流,流中的元素都是来自List ...

July 14, 2021 · 2 min · jiezi

关于java8:02-遍历-foreach

遍历 foreachJava 8的foreach() 办法 是一种无效的形式,用来遍历书架汇合,能够对List,Stream 进行遍历,该办法曾经被增加到以下接口中 Iterable 接口-Map 接口Stream 接口1. Iterable foreach1.1 foreach 办法上面的代码中给定了Iterable 接口中foreach 办法的默认实现 default void forEach(Consumer<? super T> action) { Objects.requireNonNull(action); for (T t : this) { action.accept(t); }}该foreach 办法action 对每个元素执行给定,Iterable 直到所有的元素都解决或 action 引发异样 实例1,应用 foreach 遍历list 的java 程序 List<String> names = Arrays.asList("Alex", "Brian", "Charles"); names.forEach(System.out::println);输入: AlexBrianCharles1.2 创立消费者行为--- consumer在下面的实例中,action 示意承受单个输出参数并且不返回任何数据, 它是Consumer 接口的实例,通过这样的创立消费者操作. 咱们制订要以相似办法的语法 执行多个语句 public static void main(String[] args) { List<String> names = Arrays.asList("Alex", "Brian", "Charles"); // 创立一个生产之操作 Consumer<String> makeUpperCase = new Consumer<String>() { @Override public void accept(String o) { System.out.println(o.toUpperCase()); } }; names.forEach(makeUpperCase); }// 后果ALEXBRIANCHARLES应用匿名函数外部类的形式,当初能够应用 lanmbda 表达式代替 ...

July 14, 2021 · 2 min · jiezi

关于java8:java字符串拼接的多种方式1

字符串拼接的多种形式1. 起因:在公司的时候,自研的框架会应用到字符串的拼接,所以在这里想将多种拼接字符串的形式进行一个小的总结2. 形式1:应用+号拼接(最不倡议应用)①不倡议用+号的起因:String底层是常量char数组,具体不可变性,在jvm中是通过字符串常量池来进行存储的。因为底层对加号应用了运算符的重载(c++内容),他在每次拼接的时候都会创立StringBuilder对象,通过StringBuilder对象的append(Stirng str)进行拼接,再通过new String(StringBuilder)来创立String对象。然而这样频繁的创建对象是很耗费性能的,因而不举荐应用+号进行拼接操作。3. 形式2:应用concat函数进行拼接①代码举例String strA = "Hello";String strB = "world";String concat = strA.concat(",").concat(strB);System.out.println(concat);//后果为hello,world②底层源码调用函数图 ③底层源码解析之横向调用(复制原String的值)//String中concat函数public String concat(String str) {//如果增加的字符串为空字符串,返回自身 int otherLen = str.length(); if (otherLen == 0) { return this; } int len = value.length; char buf[] = Arrays.copyOf(value, len + otherLen);//复制原来的String到新的buf数组中-------------------------------------下面的是横向,上面是纵向//复制增加的str到新的buf数组中 str.getChars(buf, len); return new String(buf, true);}//在concat函数中调用了Arrays中copyOf函数//将源数组全副复制到从索引0开始的copy数组中public static char[] copyOf(char[] original, int newLength) { char[] copy = new char[newLength]; System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy;}④底层源码解析之System.arraycopy(对数组进行管制,比copyOf更加灵便)一维数组测试System.arraycopy是否为同一存储空间 ...

July 7, 2021 · 2 min · jiezi

关于java8:java8-LocalDateTime时间方法

1、字符串类型转成LocalDateTime public static LocalDateTime string2LocalDateTime(String dateStr) { return LocalDateTime.parse(dateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); }2、两个日期比拟 if (nowDate.compareTo(endTimeDate) < 0) { // 代码逻辑}3、计算日期相差工夫(参考地址:https://www.cnblogs.com/jpfss...) java.time.Duration duration = java.time.Duration.between(LocalDateTime startTime, LocalDateTime endTime );例如: duration.toMinutes() //两个时间差的分钟数toNanos()//纳秒toMillis()//毫秒toMinutes()//分钟toHours()//小时toDays()//天数

May 11, 2021 · 1 min · jiezi

关于java8:理解枚举类型

枚举的定义public enum AccountActionTypeEnum {LOGIN,REGISTER,EDIT\_INFO;private AccountActionTypeEnum() {}}值个别是大写的字母,多个值之间以逗号分隔。 枚举常量在类型安全性和便捷性都很有保障,如果呈现类型问题编译器也会提醒咱们改良。上面看看如何在其余类中应用枚举类型 public static void main(String[] args){//间接援用AccountActionTypeEnum type =AccountActionTypeEnum.LOGIN;}枚举实现原理咱们大略理解了枚举类型的定义与简略应用后,当初来理解一下枚举类型的根本实现原理。实际上在应用关键字enum创立枚举类型并编译后,编译器会为咱们生成一个相干的类,这个类继承了Java API中的java.lang.Enum类,也就是说通过关键字enum创立枚举类型在编译后事实上也是一个类类型而且该类继承自java.lang.Enum类。上面咱们编译后面定义的AccountActionTypeEnum.java并查看生成的class文件来验证这个论断: javac AccountActionTypeEnum.java   #编译java文件生成AccountActionTypeEnum.class文件而后通过jad来反编译AccountActionTypeEnum.class .jad -sjava .AccountActionTypeEnum.class  #我这里的jad.exe放在AccountActionTypeEnum的同级目录,如果有退出环境变量的话,能够间接jad反编译AccountActionTypeEnum.class的后果 // Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.// Jad home page: http://www.kpdus.com/jad.html// Decompiler options: packimports(3)// Source File Name:   AccountActionTypeEnum.java<br>public final class AccountActionTypeEnum extends Enum{// 编译器重写的办法public static AccountActionTypeEnum[] values(){return (AccountActionTypeEnum[])$VALUES.clone();}// 编译器重写的办法public static AccountActionTypeEnum valueOf(String s){return (AccountActionTypeEnum)Enum.valueOf(AccountActionTypeEnum, s);}// 公有private AccountActionTypeEnum(String s, int i){ // 调用enum的构造方法super(s, i);}// 定义的四种枚举// 定义类变量,这也就是为什么咱们能够间接以AccountActionTypeEnum.LOGIN的模式应用的起因了public static final AccountActionTypeEnum LOGIN;public static final AccountActionTypeEnum REGISTER;public static final AccountActionTypeEnum EDIT\_INFO;private static final AccountActionTypeEnum $VALUES[];//动态代码块复制初始化类变量,在初始化阶段执行,实例化枚举实例static{LOGIN = new AccountActionTypeEnum("LOGIN", 0);REGISTER = new AccountActionTypeEnum("REGISTER", 1);EDIT\_INFO = new AccountActionTypeEnum("EDIT\_INFO", 2);$VALUES = (new AccountActionTypeEnum[] {LOGIN, REGISTER, EDIT\_INFO});}}从反编译的代码能够看出编译器的确帮忙咱们生成了一个AccountActionTypeEnum类(留神该类是final类型的,将无奈被继承)而且该类继承自java.lang.Enum类,该类是一个抽象类,除此之外,编译器还帮忙咱们生成了4个AccountActionTypeEnum类型的实例对象别离对应枚举中定义的三种type和一个type数组。留神编译器还为咱们生成了两个静态方法,别离是values()和 valueOf(),到此咱们也就明确了,应用关键字enum定义的枚举类型,在编译期后,也将转换成为一个实实在在的类,而在该类中,会存在每个在枚举类型中定义好变量的对应实例对象,如上述的LOGIN枚举类型对应public static final AccountActionTypeEnum LOGIN;,同时编译器会为该类创立两个办法,别离是values()和valueOf()。上面咱们深刻理解一下java.lang.Enum类以及values()和valueOf()的用处。 ...

January 28, 2021 · 2 min · jiezi

关于java8:从零开始学习Java8-Stream看这篇就够了

为何须要引入流在咱们平时的开发中简直每天都会有到List、Map等汇合API,若是问Java什么API应用最多,我想也应该是汇合了。举例:如果我有个汇合List,外面元素有1,7,3,8,2,4,9,须要找出外面大于5的元素,具体实现代码: public List<Integer> getGt5Data() { List<Integer> data = Arrays.asList(1, 7, 3, 8, 2, 4, 9); List<Integer> result = new ArrayList<>(); for (Integer num : data) { if (num > 5) { result.add(num); } } return result;}这个实现让咱们感觉到了汇合的操作不是太完满,如果是数据库的话,咱们只须要简略的在where前面加一个条件大于5就能够失去咱们想要的后果,为什么Java的汇合就没有这种API呢?其次,如果咱们遇到有大汇合须要解决,为了进步性能,咱们可能须要应用到多线程来解决,然而写并行程序的复杂度有进步了不少。 基于以上的问题,所有Java8推出了Stream Stream简介Stream有哪些特点: 元素的序列:与汇合一样能够拜访外面的元素,汇合讲的是数据,而流讲的是操作,比方:filter、map源: 流也须要又一个提供数据的源,程序和生成时的程序统一数据的操作:流反对相似于数据库的操作,反对程序或者并行处理数据;下面的例子用流来实现会更加的简洁public List<Integer> getGt5Data() { return Stream.of(1, 7, 3, 8, 2, 4, 9) .filter(num -> num > 5) .collect(toList());}流水线操作:很多流的办法自身也会返回一个流,这样能够把多个操作连接起来,造成流水线操作外部迭代:与以往的迭代不同,流应用的外部迭代,用户只须要专一于数据处理只能遍历一次: 遍历实现之后咱们的流就曾经生产完了,再次遍历的话会抛出异样应用StreamJava8中的Stream定义了很多办法,根本能够把他们分为两类:两头操作、终端操作;要应用一个流个别都须要三个操作: 定义一个数据源定义两头操作造成流水线定义终端操作,执行流水线,生成计算结果构建流应用Stream.of办法构建一个流Stream.of("silently","9527","silently9527.cn") .forEach(System.out::println);应用数组构建一个流int[] nums = {3, 5, 2, 7, 8, 9};Arrays.stream(nums).sorted().forEach(System.out::println);通过文件构建一个流应用java.nio.file.Files.lines办法能够轻松构建一个流对象 ...

December 16, 2020 · 2 min · jiezi

关于java8:Java8新特性函数式编程StreamFunctionOptionalConsumer

Java8新引入函数式编程形式,大大的进步了编码效率。本文将对波及的对象等进行对立的学习及记录。 首先须要分明一个概念:函数式接口;它指的是有且只有一个未实现的办法的接口,个别通过FunctionalInterface这个注解来表明某个接口是一个函数式接口。函数式接口是Java反对函数式编程的根底。 本文目录: 1 Java8函数式编程语法入门2 Java函数式接口 2.1 Consumer2.2 Function2.3 Predicate3 函数式编程接口的应用 3.1 Stream 3.1.1 Stream对象的创立3.1.2 Stream对象的应用 3.1.2.1 filter3.1.2.2 map3.1.2.3 flatMap3.1.2.4 takeWhile3.1.2.5 dropWhile3.1.2.6 reduce与collect3.2 Optional 3.2.1 Optional对象创立 3.2.1.1 empty3.2.1.2 of3.2.1.3 ofNullable3.2.2 办法3.2.3 应用场景 3.2.3.1 判断后果不为空后应用3.2.3.2 变量为空时提供默认值3.2.3.3 变量为空时抛出异样,否则应用1 Java8函数式编程语法入门Java8中函数式编程语法可能精简代码。 应用Consumer作为示例,它是一个函数式接口,蕴含一个形象办法accept,这个办法只有输出而无输入。 当初咱们要定义一个Consumer对象,传统的形式是这样定义的: Consumer c = new Consumer() { @Override public void accept(Object o) { System.out.println(o); }};而在Java8中,针对函数式编程接口,能够这样定义: Consumer c = (o) -> { System.out.println(o);};下面已阐明,函数式编程接口都只有一个形象办法,因而在采纳这种写法时,编译器会将这段函数编译后当作该形象办法的实现。 如果接口有多个形象办法,编译器就不晓得这段函数应该是实现哪个办法的了。 因而,=前面的函数体咱们就能够看成是accept函数的实现。 输出:->后面的局部,即被()突围的局部。此处只有一个输出参数,实际上输出是能够有多个的,如两个参数时写法:(a, b);当然也能够没有输出,此时间接就能够是()。函数体:->前面的局部,即被{}突围的局部;能够是一段代码。输入:函数式编程能够没有返回值,也能够有返回值。如果有返回值时,须要代码段的最初一句通过return的形式返回对应的值。当函数体中只有一个语句时,能够去掉{}进一步简化: Consumer c = (o) -> System.out.println(o);然而这还不是最简的,因为此处只是进行打印,调用了System.out中的println静态方法对输出参数间接进行打印,因而能够简化成以下写法: ...

November 27, 2020 · 4 min · jiezi

关于java8:CompletableFuture让你的代码免受阻塞之苦

前言当初大部分的CPU都是多核,咱们都晓得想要晋升咱们应用程序的运行效率,就必须得充分利用多核CPU的计算能力;Java早曾经为咱们提供了多线程的API,然而实现形式稍微麻烦,明天咱们就来看看Java8在这方面提供的改善。 假如场景当初你须要为在线教育平台提供一个查问用户详情的API,该接口须要返回用户的根本信息,标签信息,这两个信息寄存在不同地位,须要近程调用来获取这两个信息;为了模仿近程调用,咱们须要在代码外面提早 1s; public interface RemoteLoader { String load(); default void delay() { try { Thread.sleep(1000L); } catch (InterruptedException e) { e.printStackTrace(); } }}public class CustomerInfoService implements RemoteLoader { public String load() { this.delay(); return "根本信息"; }}public class LearnRecordService implements RemoteLoader { public String load() { this.delay(); return "学习信息"; }}同步形式实现版本如果咱们采纳同步的形式来实现这个API接口,咱们的实现代码: @Testpublic void testSync() { long start = System.currentTimeMillis(); List<RemoteLoader> remoteLoaders = Arrays.asList(new CustomerInfoService(), new LearnRecordService()); List<String> customerDetail = remoteLoaders.stream().map(RemoteLoader::load).collect(toList()); System.out.println(customerDetail); long end = System.currentTimeMillis(); System.out.println("总共破费工夫:" + (end - start));}不出所料,因为调用的两个接口都是提早了 1s ,所以后果大于2秒 ...

November 22, 2020 · 3 min · jiezi

关于java8:Java中NullPointerException的完美解决方案

null在Java中带来的麻烦我置信所有的Java程序猿肯定都遇到过NullPointerException,空指针在Java程序中是最常见的,也是最烦人的;它让咱们很多程序猿产生了积重难返的感觉,所有可能产生空指针的中央都的加上if-else查看,然而这带给咱们很多麻烦 Java自身是强类型的,然而null毁坏了这个规定,它能够被赋值给任何对象Java的设计是让程序猿对指针无感知,然而null指针是个例外它会是代码变得很臃肿,到处都充斥着if-else的空查看,甚至是多层嵌套,代码可读性降落null自身毫无意义,示意不了无前两点不须要特地的阐明,后两点举个例子来阐明一下:如果一个人领有一个手机,每个手机都有生成厂商,每个厂商都会有个名字,用类示意的话: public class Person { private Phone phone; public Phone getPhone() { return phone; }}public class Phone { private Producer producer; public Producer getProducer() { return producer; }}public class Producer { private String name; public String getName() { return name; }}在这个例子中,如果咱们须要取到手机生成厂商的名字 public String getPhoneProducerName(Person person) { return person.getPhone().getProducer().getName();}因为不肯定每个人都会有一个手机,所有在调用getProducer()时可能会呈现NullPointerException。 一门设计语言原本就是来形容世界的,在这个事例中有的人有手机,有的人也可能没有手机,所以在调用person.getPhone()返回的值就应该蕴含有和无这两种状况,当初通过返回null来示意无,然而在调用getProducer()却又会抛出异样,这样就不太合乎事实逻辑;所以把null来用来示意无不适合 在遇到这种状况通常的做法是做null查看,甚至是每个中央可能产生null指针的做查看。 public String getPhoneProducerName(Person person) { if (person.getPhone() == null) { return "无名字"; } if (person.getPhone().getProducer() == null) { return "无名字"; } return person.getPhone().getProducer().getName();}这里我曾经试图在缩小代码的层级,如果应用的是if-else,代码的层级会更深,代码可读性降落。 ...

November 18, 2020 · 2 min · jiezi

关于java8:JAVASE2-复习

产生一个随机数 -- n -- 产生n以内的整数,默认从0开始int random = new Random().nextInt(100) ;//[0,100) 变量--1,随着变量呈现的地位不同,作用和名字都不同.--2,呈现在成员地位(在类里办法外)的变量叫做成员变量--整个类中都无效--不必赋值也有默认值--3,呈现在部分地位(办法里)的变量叫做局部变量--办法里无效--必须手动赋值--4,变量应用时有一个准则:就近准则//测试 变量public class Test3_Variable { //2,呈现在类里办法外的变量--是成员变量--作用于整个类中--能够不赋值,会有默认值 //4,成员变量,都有默认值. //整数类型默认值是0,小数类型默认值是0.0,boolean类型默认值是false int count ; int age = 10; boolean flag; //单元测试JUnit办法: //要求:@Test public void 办法名(){办法体} //测试:选中办法名,右键,run as...junit test... @Test public void show() { //1,呈现在办法里的变量--是局部变量--必须初始化--作用于办法里 int age = 0; System.out.println(age);//3,就近准则 - 输入0 System.out.println(count); if(! flag) {//flag的默认值是false,取反,就是true,条件成立,输入1. System.out.println(1); } } }

September 23, 2020 · 1 min · jiezi

关于java8:Java8新特性-Lambda底层实现原理

前言常常会在写业务代码的时候,有这样的需要: 筛选出条件为XX的实体类ID List List<Long> waitTaskList = wflInsTaskList.stream().filter(wflInsTask -> { return wflInsTask.getArrivalStatus().equals(WflInsTask.ARRIVAL_STATUS_NOT_ARRIVED); }).map(WflInsTask::getTaskId).distinct().collect(Collectors.toList());Java8之Lambda下文内容默认以JDK8为前提 什么是LambdaLambda 表达式是 JDK8 的一个新个性,能够取代大部分的匿名外部类,写出更优雅的Java代码,尤其在汇合的遍历和其余汇合操作中,能够极大地优化代码构造。 Lambda 表达式形容了一个代码块(或者叫匿名办法),能够将其作为参数传递给构造方法或者一般办法以便后续执行。如: () -> System.out.println("hello");() 为 Lambda 表达式的参数列表(容许没有参数),-> 标识这串代码为 Lambda 表达式(也就是说,看到 -> 就晓得这是 Lambda,Groovy的闭包语法也相似),System.out.println("hello") 就是执行的代码,将“hello”打印到规范输入流。 以Runnable接口为例,原来咱们创立一个线程并启动它是这样的: public class Test { public static void main(String[] args) { new Thread(new Runnable() { @Override public void run() { System.out.println("hello"); } }).start(); }}通过 Lambda 只须要这样: public class Test { public static void main(String[] args) { new Thread(() -> System.out.println("hello")).start(); }}咱们看Runnable接口源码: ...

August 25, 2020 · 3 min · jiezi

Java8-list-stream-测试用例小结

一、测试对象package com.demo.crwien.test;public class Student { private Integer id; private String groupId; private String name; private Integer age;}二、测试用例package com.demo.lee.util;import org.junit.Test;import java.util.Arrays;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.function.Function;import java.util.stream.Collectors;import static java.util.stream.Collectors.groupingBy;/** * @author lee */public class ListCollectionTest { @Test public void test1() { //1.分组计数 List<Student> list = Arrays.asList( new Student(1, "one", "zhao",11), new Student(2, "one", "qian",22), new Student(3, "two", "sun",33), new Student(4, "two", "lee",18)); //1.1依据某个属性分组计数 Map<String, Long> result1 = list.stream().collect(Collectors.groupingBy(Student::getGroupId, Collectors.counting())); System.out.println(result1); //1.2依据整个实体对象分组计数,当其为String时常应用 Map<Student, Long> result2 = list.stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); System.out.println(result2); //1.3依据分组的key值对后果进行排序、放进另一个map中并输入 Map<String, Long> xMap = new HashMap<>(); result1.entrySet().stream().sorted(Map.Entry.<String, Long>comparingByKey().reversed()) //reversed不失效 .forEachOrdered(x -> xMap.put(x.getKey(), x.getValue())); System.out.println(xMap); } @Test public void test2() { List<Student> list = Arrays.asList( new Student(1, "one", "zhao",11), new Student(2, "one", "qian",22), new Student(3, "two", "sun",33), new Student(4, "two", "lee",18)); //2.分组,并统计其中一个属性值得sum或者avg:id总和 Map<String, Integer> result3 = list.stream().collect( Collectors.groupingBy(Student::getGroupId, Collectors.summingInt(Student::getId)) ); System.out.println(result3); } @Test public void test3(){ List<Student> list = Arrays.asList( new Student(1, "one", "zhao",11), new Student(2, "one", "qian",22), new Student(3, "two", "sun",33), new Student(4, "two", "lee",18)); //3.依据某个属性过滤 List<Student> list1 = list.stream().filter(a -> a.getName().contains("a")).collect(Collectors.toList()); System.out.println(list1); } @Test public void test4(){ List<Student> list = Arrays.asList( new Student(1, "one", "zhao",11), new Student(2, "one", "qian",22), new Student(3, "two", "sun",33), new Student(4, "two", "lee",18)); //4.依据对象属性进行分组,自行编辑分组条件 Map<String, List<Student>> collect = list.stream().collect(groupingBy(s -> { Integer age = s.getAge(); if (0<age && age<=10){ return "baby"; }else if (10<age && age<=20){ return "teenager"; }else if (20<age && age<=30){ return "youth"; }else { return "old"; } })); System.out.println(collect); }@testpublic void test5(){ List<Student> list = Arrays.asList( new Student(1, "one", "zhao",11), new Student(2, "one", "qian",22), new Student(3, "two", "sun",33), new Student(4, "two", "lee",18)); //对象属性拼字符串 String investor = list.stream().map(Student::getName).collect(Collectors.joining(",")}@testpublic void test6(){ List<Student> list = Arrays.asList( new Student(1, "one", "zhao",11), new Student(2, "one", "qian",22), new Student(3, "two", "sun",33), new Student(4, "two", "lee",18)); //对象属性求和 Integer result = list.stream().collect(Collectors.summingInt(Student::getAge)); System.out.println("所有学生年龄之和 : " + reuslt);}@testpublic void test7(){ List<Student> list = Arrays.asList( new Student(1, "one", "zhao",11), new Student(2, "one", "qian",22), new Student(3, "two", "sun",33), new Student(4, "two", "lee",18)); //list转map Map<Integer,String> map = userlist.stream().collect(Collectors.toMap(User::getAge,User::getName));}@testpublic void test8(){ //按名称形容排序 List<ECLabelEnum> enumList = Arrays.stream(ECLabelEnum.values()).sorted(Comparator.comparing(ECLabelEnum::desc)).collect(Collectors.toList());}//排序@testpublic void test9(){ //倒序,从大到小 list.stream().sorted(Comparator.comparing(Student::getAge)); //正序,从小到大 list.stream().sorted(Comparator.comparing(Student::getAge).reversed()) }}三、实战Map<String, String> dataMap = new HashMap<>(10);List<String> dataList = request.getDataList();// 获取未加密的字符串(过滤不符合条件的)List<String> unEncryptData = dataList.stream().filter(s -> !isEncryptData(s)).collect(Collectors.toList());// 移除未加密的dataList.removeAll(unEncryptData);if (encryptData != null && encryptData.size() > 0) { collect = encryptData.stream().collect(Collectors.toMap(x -> x, x -> x,(k1,k2) -> k1)); }

July 17, 2020 · 2 min · jiezi

java8实战学习总结1

1. lambda表达式1.1 什么是lambda表达式1.2 什么样的场景能应用lambda表达式1.3 lambda表达式实现一个接口的四种写法2. 函数式编程2.1 什么是函数式编程2.2 什么是命令式编程2.3 什么是函数式接口 FunctionalInterface2.4 什么是 default 办法2.5 default办法的意义2.6 java8内置的罕用函数式接口(1). Predicate<T>断言 -> 输出T, 输入 boolean (2). Consumer<T>生产一个输出 -> 输出T, 不输入(void) (3). Supplier<T>生产一个输入 -> 不输出, 输入T (4). Function<T, R>输出T, 输入R的函数 (5). UnaryOperator<T>一元函数: 输出1个输入 1个: 类型都是T (6). BinaryOperatior<T>二元函数: 输出2个输入1个: 类型都是T (7). BiFunction<T, U, R>输出两个输入一个: 输出 T, U 输入 R, 罕用于 reduce/sort等操作, 2.7 办法援用(1). 静态方法的办法援用(2). 实例办法的办法援用(3). 构造方法的办法援用2.8. 变量援用和隐式final为何外部类应用内部变量要是final的3. stream流式编程3.1. 内部迭代和外部迭代(1). 什么是内部迭代(2). 什么是外部迭代3.2. 两头操作/终止操作/惰性求值(1). 什么是两头操作?返回还是流stream的操作, 就是两头操作, 例如 map操作 ...

July 14, 2020 · 3 min · jiezi

Java8方法引用

办法援用就是通过类名或办法名援用曾经存在的办法来简化lambda表达式。那么什么时候须要用办法援用呢?如果lamdba体中的内容曾经有办法实现了,咱们就能够应用办法援用。 一、办法援用的三种语法格局1. 对象::实例办法名lamdba写法: @Testvoid test1(){ Consumer<String> con = x -> System.out.println(x);}办法援用写法: @Testvoid test2(){ PrintStream out = System.out; Consumer<String> con = out::println;}consumer接口: @FunctionalInterfacepublic interface Consumer<T> { void accept(T t);}留神:被调用的办法的参数列表和返回值类型须要与函数式接口中形象办法的参数列表和返回值类型要统一。 2. 类::静态方法名lamdba写法: @Testvoid test3(){ Comparator<Integer> com = (x, y) -> Integer.compare(x,y);}办法援用写法: @Testvoid test4(){ Comparator<Integer> com = Integer::compare;}Comparator接口: @FunctionalInterfacepublic interface Comparator<T> { int compare(T o1, T o2);}Integer类局部内容: public final class Integer extends Number implements Comparable<Integer> { public static int compare(int x, int y) { return (x < y) ? -1 : ((x == y) ? 0 : 1); }}留神:被调用的办法的参数列表和返回值类型须要与函数式接口中形象办法的参数列表和返回值类型要统一。 ...

July 14, 2020 · 1 min · jiezi

Java8-streams-map-示例

在开发过程中,经常会对list进行遍历操作,有时候操作后也需要返回List。这时候可以使用java8的 stream map进行操作。如下面的示例说明 具体应用1 /* addressList是一个地址列表,把实体数据都转换成dto数据。返回给addressDTOList */List<AddressDTO> addressDTOList = addressList.stream().map(item->addressMapper.entityToDto(item)).collect(Collectors.toList());具体应用2 /* 将字符串转换成大写 */List<String> alpha = Arrays.asList("a", "b", "c", "d");// Java8之前的写法List<String> alphaUpper = new ArrayList<>();for (String s : alpha) { alphaUpper.add(s.toUpperCase());}System.out.println(alpha); //[a, b, c, d]System.out.println(alphaUpper); //[A, B, C, D] // Java8之后的写法 List<String> collect = alpha.stream().map(String::toUpperCase).collect(Collectors.toList());System.out.println(collect); //[A, B, C, D]// 其他数据类型的应用List<Integer> num = Arrays.asList(1,2,3,4,5);List<Integer> collect1 = num.stream().map(n -> n * 2).collect(Collectors.toList());System.out.println(collect1); //[2, 4, 6, 8, 10]

July 5, 2020 · 1 min · jiezi

玩转Java8中的-Stream-之从零认识-Stream

作者:litesky来源: http://www.jianshu.com/p/11c9... 相信Java8的Stream 大家都已听说过了,但是可能大家不会用或者用的不熟,文章将带大家从零开始使用,循序渐进,带你走向Stream的巅峰。 操作符什么是操作符呢?操作符就是对数据进行的一种处理工作,一道加工程序;就好像工厂的工人对流水线上的产品进行一道加工程序一样。 Stream的操作符大体上分为两种:中间操作符和终止操作符 中间操作符对于数据流来说,中间操作符在执行制定处理程序后,数据流依然可以传递给下一级的操作符。 中间操作符包含8种(排除了parallel,sequential,这两个操作并不涉及到对数据流的加工操作): map(mapToInt,mapToLong,mapToDouble) 转换操作符,把比如A->B,这里默认提供了转int,long,double的操作符。flatmap(flatmapToInt,flatmapToLong,flatmapToDouble) 拍平操作比如把 int[]{2,3,4} 拍平 变成 2,3,4 也就是从原来的一个数据变成了3个数据,这里默认提供了拍平成int,long,double的操作符。limit 限流操作,比如数据流中有10个 我只要出前3个就可以使用。distint 去重操作,对重复元素去重,底层使用了equals方法。filter 过滤操作,把不想要的数据过滤。peek 挑出操作,如果想对数据进行某些操作,如:读取、编辑修改等。skip 跳过操作,跳过某些元素。sorted(unordered) 排序操作,对元素排序,前提是实现Comparable接口,当然也可以自定义比较器。 终止操作符数据经过中间加工操作,就轮到终止操作符上场了;终止操作符就是用来对数据进行收集或者消费的,数据到了终止操作这里就不会向下流动了,终止操作符只能使用一次。 collect 收集操作,将所有数据收集起来,这个操作非常重要,官方的提供的Collectors 提供了非常多收集器,可以说Stream 的核心在于Collectors。count 统计操作,统计最终的数据个数。findFirst、findAny 查找操作,查找第一个、查找任何一个 返回的类型为Optional。noneMatch、allMatch、anyMatch 匹配操作,数据流中是否存在符合条件的元素 返回值为bool 值。min、max 最值操作,需要自定义比较器,返回数据流中最大最小的值。reduce 规约操作,将整个数据流的值规约为一个值,count、min、max底层就是使用reduce。forEach、forEachOrdered 遍历操作,这里就是对最终的数据进行消费了。toArray 数组操作,将数据流的元素转换成数组。这里只介绍了Stream,并没有涉及到IntStream、LongStream、DoubleStream,这三个流实现了一些特有的操作符,我将在后续文章中介绍到。Java知音公众号内回复“面试题聚合”,送你一份各大公司面试汇总宝典。 说了这么多,只介绍这些操作符还远远不够;俗话说,实践出真知。那么,Let‘s go。 代码演练Stream 的一系列操作必须要使用终止操作,否者整个数据流是不会流动起来的,即处理操作不会执行。 map,可以看到 map 操作符要求输入一个Function的函数是接口实例,功能是将T类型转换成R类型的。 map操作将原来的单词 转换成了每个单的长度,利用了String自身的length()方法,该方法返回类型为int。这里我直接使用了lambda表达式,关于lambda表达式 还请读者们自行了解吧。 public class Main { public static void main(String[] args) { Stream.of("apple","banana","orange","waltermaleon","grape") .map(e->e.length()) //转成单词的长度 int .forEach(e->System.out.println(e)); //输出 }}当然也可以这样,这里使用了成员函数引用,为了便于读者们理解,后续的例子中将使用lambda表达式而非函数引用。 ...

June 28, 2020 · 4 min · jiezi

你使用过Java8中的parallelStream

前言并行编程势不可挡,Java从1.7开始就提供了Fork/Join 支持并行处理。java1.8 进一步加强。 并行处理就是将任务拆分子任务,分发给多个处理器同时处理,之后合并。 Stream APIJava 8 引入了许多特性,Stream API是其中重要的一部分。区别 InputStream OutputStream,Stream API 是处理对象流而不是字节流。 执行原理如下,流分串行和并行两种执行方式 // 串行执行流stream().filter(e -> e > 10).count();// 并行执行流.parallelStream().filter(e -> e > 10).count() ParallelStreams执行原理并行执行时,java将流划分为多个子流,分散在不同CPU并行处理,然后进行合并。 并行一定比串行更快吗?这不一定,取决于两方面条件: 处理器核心数量,并行处理核心数越多自然处理效率会更高。处理的数据量越大,优势越强。这也很好理解,比如十个人干一个人就能完成的活儿会比它自己干更便宜?ParallelStreams注意事项使用并行流时,不要使用collectors.groupingBy,collectors.toMap,替代为 collectors.groupingByConcurrent , collectors.toConcurrentMap,或直接使用串行流。 原因,并行流执行时,通过操作Key来合并多个map的操作比较昂贵。详细大家可以查看官网介绍。 https://docs.oracle.com/javas...Map<String, List<Person>> byGender = roster .stream() .collect(Collectors.groupingBy(Person::getGender));ConcurrentMap<String, List<Person>> byGender = roster .parallelStream() .collect(Collectors.groupingByConcurrent(Person::getGender));ParallelStreams 默认使用 ForkJoinPool.commonPool()线程池。 注意:默认情况下,你写的 ParallelStreams 都是通过该线程池调度执行,整个应用程序都共享这个线程池。 看一个例子,我们查询一批新闻数据,可以利用并行化来处理远程新闻下载。 public List<News> queryNews(Stream<String> ids) { return ids.parallel() .map(this::getNews) // 网络操作,新闻下载 .collect(toList());}因为是网络操作,存在很多不确定性,假如某个任务运行时间较长,导致线程池资源占据,阻塞其它线程,这样就阻止了其他的并行流任务正常进行。 如果解决这个问题的其中一种方式,进行线程池隔离。那么如何自定义并行流的线程池呢? ...

June 5, 2020 · 1 min · jiezi

第一章简介

1.1 为什么再次修改Java多核CPU的出现,大大提高了计算机的处理能力。人们开发的java.util.concurrent包和很多第三方类库,试图将并发抽象化,帮助程序员写出在多核CPU上运行良好的程序。很可惜,目前成果还不够。处理大型数据集合就是一个很好的例子。面对大型数据集合,java还欠缺高效的并行操作。开发者能够使用java8编写复杂的集合处理算法,只需要简单修改一个方法,就能让代码在多核CPU高效执行。为了编写这类处理批量数据的并行类库,需要在语言层面修改现有的java:增加Lambda表达式。1.2 什么是函数式编程每个人对函数式编程有不同的理解,其核心是:使用不可变值和函数,函数对一个值进行处理,映射成另一个值。1.3 示例后面示例主要围绕一个常见问题进行领域构造:音乐 Artist:创建音乐的个人或团队 name:艺术家的名字 member:乐队成员 origin:乐队来自于哪里 Track:专辑的一支曲目 name:曲目名称 Album:专辑,有若干曲目组成 name:专辑名 tracks:专辑上所有曲目的列表 musicians:参与创作本专辑的艺术家列表

June 4, 2020 · 1 min · jiezi

java8的stream流练习2-改选自java8实战书

import lombok.extern.slf4j.Slf4j;import java.util.Arrays;import java.util.Comparator;import java.util.List;import java.util.Optional;import java.util.stream.Collectors;/** * @Author weijun.nie * @Date 2020/5/26 10:35 * @Version 1.0 */@Slf4jpublic class TranTestDemo { public static void main(String[] args) { Trader niuj = new Trader("nj牛进", "上海"); Trader maik = new Trader("mk买康", "香港"); Trader niuf = new Trader("nf牛发", "上海"); Trader jiny = new Trader("jy靳扬", "上海"); List<Transaction> transactions = Arrays.asList( new Transaction(jiny, 2011, 300), new Transaction(niuj, 2012, 1000), new Transaction(niuj, 2011, 400), new Transaction(maik, 2012, 710), new Transaction(maik, 2012, 700), new Transaction(niuf, 2012, 950) ); // (1) 找出2011年发生的所有交易,并按交易额排序(从低到高)。 // (1-1). 打印 log.info("======================遍历打印1==============================="); transactions.stream().filter(t -> 2011 == t.getYear()).sorted((t1, t2) -> Integer.valueOf(t1.getValue()).compareTo(Integer.valueOf(t2.getValue()))).forEach(System.out::println); log.info("======================遍历打印2==============================="); transactions.stream().filter(t -> 2011 == t.getYear()).sorted(Comparator.comparingInt(Transaction::getValue)).forEach(System.out::println); log.info("======================遍历打印3==============================="); transactions.stream().filter(t -> 2011 == t.getYear()).sorted(Comparator.comparing(Transaction::getValue)).forEach(System.out::println); log.info("======================返回集合==============================="); // (1-2). 返回List<Transaction> List<Transaction> result1List = transactions.stream().filter(t -> 2011 == t.getYear()).sorted(Comparator.comparingInt(Transaction::getValue)).collect(Collectors.toList()); log.info("找出2011年发生的所有交易,并按交易额排序(从低到高):\t{}", result1List); // (2) 交易员都在哪些不同的城市工作过? log.info("====================================================="); List<String> cities = transactions.stream().map(t -> t.getTrader().getCity()).distinct().collect(Collectors.toList()); log.info("交易员都在哪些不同的城市工作过:\t{}", cities); // (3) 查找所有来自于上海的交易员,并按姓名排序。 log.info("====================================================="); List<Trader> SHTradersSorted = transactions.stream().map(Transaction::getTrader).filter(t -> t.getCity().equals("上海")).sorted(Comparator.comparing(Trader::getName)).collect(Collectors.toList()); log.info("查找所有来自于上海的交易员,并按姓名排序:\t{}", SHTradersSorted); // (4) 返回所有交易员的姓名字符串,按字母顺序排序。 log.info("====================================================="); List<String> traderNamesList = transactions.stream().map(t -> t.getTrader().getName()).distinct().sorted().collect(Collectors.toList()); log.info("返回所有交易员的姓名字符串,按字母顺序排序:\t{}", traderNamesList); // (5) 有没有交易员是在北京工作的? log.info("====================================================="); boolean hasInBeijing = transactions.stream().filter(t -> t.getTrader().getCity().equals("北京")).findAny().isPresent(); log.info("有没有交易员是在北京工作的:{}", hasInBeijing); // (6) 打印生活在上海的交易员的所有交易额。 log.info("====================================================="); List<Integer> valuesInShanghai = transactions.stream().filter(t -> t.getTrader().getCity().equals("上海")).map(t -> t.getValue()).collect(Collectors.toList()); log.info("打印生活在上海的交易员的所有交易额:\t{}", valuesInShanghai); // (7) 所有交易中,最高的交易额是多少? log.info("====================================================="); Optional<Integer> max = transactions.stream().map(t -> t.getValue()).max(Comparator.comparingInt(Integer::intValue)); log.info("所有交易中,最高的交易额是多少\t{}", max.get()); // (8) 找到交易额最小的交易。 log.info("====================================================="); Transaction minTransanction = transactions.stream().collect(Collectors.minBy(Comparator.comparing(t -> t.getValue()))).get(); log.info("找到交易额最小的交易\t:{}", minTransanction); }}======================遍历打印1==============================={Trader{name='jy靳扬', city='上海'}, year: 2011, value:300}{Trader{name='nj牛进', city='上海'}, year: 2011, value:400}======================遍历打印2==============================={Trader{name='jy靳扬', city='上海'}, year: 2011, value:300}{Trader{name='nj牛进', city='上海'}, year: 2011, value:400}======================遍历打印3==============================={Trader{name='jy靳扬', city='上海'}, year: 2011, value:300}{Trader{name='nj牛进', city='上海'}, year: 2011, value:400}======================返回集合=============================== ...

May 27, 2020 · 2 min · jiezi