JAVA8问题处理回顾-持续更新

金额累加问题 使用Reduce进行累加操作,参考这里 List<BigDecimal> bdList = new ArrayList<>(); //populate list BigDecimal result = bdList.stream().reduce(BigDecimal.ZERO, BigDecimal::add); 查找集合的最后一个元素 JAVA8的Stream只提供了FindFirst功能,没有FindLast功能,可以使用Reduce来实现查找最后一个元素的效果 import java.util.*; import java.util.stream.*; public class GetLastEleFromCollection { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("aaa"); list.add("idddd"); list.add("bbbb"); String lastElement = list.stream() .reduce((first, second) -> second) .orElse(null); System.out.println(lastElement); } } bbbb 比较两个时间是否是同一天 import java.time.*; import java.time.temporal.*; public class CompareDay { public static void main(String[] args) { final LocalDateTime now = LocalDateTime.now(); final LocalDateTime localDateTime = LocalDateTime.of(2019, 9, 29, 0, 0, 0); System.out.println(localDateTime.truncatedTo(ChronoUnit.DAYS).isEqual(now.truncatedTo(ChronoUnit.DAYS))); } } true 实现与Python的zip函数功能 import java.util.*; import java.util.function.*; public class Zip { public static void main(String[] args) { List<List<Integer>> result = handle(Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6), (i, j) -> Arrays.asList(i, j)); System.out.println(result); } public static <T, U, R> List<R> handle(List<T> list, List<U> list1, BiFunction<T, U, R> biFunction) { List<R> result = new ArrayList<>(); for(int i = 0; i < list.size(); i ++) { result.add(biFunction.apply(list.get(i), list1.get(i))); } return result; } } [[1 (\, 4)] (\, [2 (\, 5)]) (\, [3 (\, 6)])] 多个Predicate链 import java.util.*; import java.util.stream.*; import java.util.function.*; public class MorePredicate { public static void main(String[] args) { List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6); final Predicate<Integer> predicate = i -> i % 2 == 0; final Predicate<Integer> predicate1 = predicate.and(integer -> integer > 5); List<Integer> result = list.stream() .filter(predicate1) .collect(Collectors.toList()); System.out.println(result); } } [6]

2019-08-24 · 2 min · 220 words · tomyli

设计模式学习之代理模式

说明 代理模式是设计模式中使用频率非常的高的模式,像日常生活中的房产中介、外卖平台都属于代理。代理模式就是在访问真正的业务之时不会直接与真正的业务进行调用,而是与一个与真正业务对象有着相同功能声明的代理来进行处理,但是最终的处理还是由真正的业务类来进行(决定),比如房产中介,他们会帮助找房者根据条件来对可选房屋进行筛选,但是最终订与不订的权利还是由找房者来决定。常见的代理有保护代理、虚拟代理、远程代理。 代理模式 我们常用的后台系统一般会根据用户权限的不同对用户展示不同的业务菜单,拥有高权限的人会展示相对多的菜单进行操作,在这个过程中还要记录用户的操作日志,用户点了什么,执行了什么操作都需要进行记录,达到有据可查。在这个业务场景下,就可以使用代理模式进行实现。代理对象会持有一个真正业务对象的实例,在代理对象中还引用日志服务与权限服务,所有的请求都经过这个代理类来进行,这样就可以根据操作的用户的状态来进行相应的处理了。具体的代码实现如下: 定义一个查询接口,在这里定义一个查询用户收入的方法,如下: package cn.imcompany.proxy; /** * Created by tomyli on 2018/6/28. * Github: https://github.com/peng051410 */ public interface Search { void queryIncome(String username); } 再定义一个实现该接口的具体业务类: package cn.imcompany.proxy; /** * Created by tomyli on 2018/6/28. * Github: https://github.com/peng051410 */ public class SearchService implements Search { @Override public void queryIncome(String username) { System.out.println(username + "开始查询"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(username + "查询完成"); } } 在上面代码中就实现了查询收入的方法,简单的打印了两行日志。 ...

2018-07-16 · 1 min · 189 words · tomyli

设计模式学习之委托模式

说明 委托模式不属于23种设计模式中,但是它在Spring框架中使用的很频繁,Spring的作用在Java的开发是非常大,所以需要学习一下委托模式。委托模式是指两个对象都有相同的方法与功能,比如A、B两个对象都有相同的方法,但是有调用A的method方法,A不会自己来处理而是直接调用了B的同名方法,由两个对象参与同一个请求,接受请求的对象将委托给另一个对象来处理。 委托模式 在一般的公司中,都会分为老板、项目经理、开发人员结构,老板负责制定决策,分配给项目经理后,他不会自己来完成,而是把需要的功能进行分解,交给擅长的开发人员进行实现。虽然项目经理也可以完成,但是是他把这些事情委托给了多个开发人员来做,加快了完成任务的速度。就以这个需求来说,使用委托模式来进行实现: 定义抽象的人类接口: package cn.imcompany.delegate; /** * Created by tomyli on 2018/6/27. * Github: https://github.com/peng051410 */ public interface Member { void showName(); void showSkill(); void doWork(); } 上面代码中定义了抽象的人类接口,显示这个人的名字,拥有的技能,工作的状态情况,接下来实现需求中的每个人。 定义老板(BOSS): package cn.imcompany.delegate; /** * Created by tomyli on 2018/6/27. * Github: https://github.com/peng051410 */ public class Boss implements Member { @Override public void showName() { System.out.println("i am boss"); } @Override public void showSkill() { System.out.println("send commend"); } @Override public void doWork() { } } 定义项目经理和员工: ...

2018-07-07 · 2 min · 282 words · tomyli

设计模式学习之观察者

说明 观察者模式在日常开发中使用频率也是非常高的,它建立了对象与对象之间的关系,一个对象的行为改变会通知到另一个对象,被通知的对象根据通知做出相应的处理动作。在观察者中分为目标对象(被观察者)、观察者。观察者模式是一种对象行为模式。 观察者模式 现在很多人都购买股票,在市面上有很多的股票软件供广大股民使用。股票软件一般会在用户关注的股票有变动时发送消息来通知股民。在这里,某一支股票就是目标对象,广大股民与股票软件就是观察者,他们根据股票的行情变化来做出相应买入或者卖出操作。这一需求可以使用观察者模式进行实现。代码如下: 先来定义一个抽象的购买股票的股民们,他们有喜有悲的心情: package cn.imcompany.observer.stock; /** * Created by tomyli on 2018/6/23. * Github: https://github.com/peng051410 */ public interface Buyer { void setName(String name); String getName(); void happy(); void sad(); } 再来定义具体的股民行为实现类: package cn.imcompany.observer.stock; /** * Created by tomyli on 2018/6/23. * Github: https://github.com/peng051410 */ public class ConcrectBuyer implements Buyer { private String name; @Override public void setName(String name) { this.name = name; } @Override public String getName() { return name; } @Override public void happy() { System.out.println(this.getName() + ":happy"); } @Override public void sad() { System.out.println(this.getName() + ":sad"); } } 具体的股民实现了喜与悲的方法,这样观察者已经准备就绪。下面来定义股票软件: ...

2018-07-04 · 2 min · 244 words · tomyli

设计模式学习之装饰器

说明 装饰器设计模式是使用比较频繁的设计模式,它在不改变原物体的情况对原物体实现了功能的增加,原物体还是一个可单独使用的个体。在JAVA的类库中应该会马上想到IO类,各种的InputStrem,OutputStrem。 装饰器模式 在用户登录的中过程,我们需要对用户输入的密码进行加密操作,在设计时会提供好多种加密的算法,例如简单的BASE64加密,复杂的如MD5、DSA加密。直接把用户的密码存入数据库是真的在耍流氓。在使用这些算法时,我们想灵活的使用,比如使用完简单加密还可以再进行一下MD5的加密。针对这样的需求,可以使用装饰器模式进行实现。大体思路如下: 加密接口,定义加密方法。 在装饰器中,最原始的被装饰者是目标实现,它们一般会实现加密定义的具体方法。 装饰者会针对目标对象进行装饰,所以它要同样实现加密接口的方法,一般情况下这个装饰器会定义为抽象的形式,在这个装饰器父类中维护着对目标对象的引用。 具体装饰器继承抽象装饰器来实现对目标对象的真正装饰操作。 以上的情况在代码上体现为如下形式: 加密接口 package cn.imcompany.decorator.encrypt; /** * Created by tomyli on 2018/6/25. * Github: https://github.com/peng051410 */ public interface Encryptor { void encrypt(); } 具体加密类,实现加密处理接口 package cn.imcompany.decorator.encrypt; /** * Created by tomyli on 2018/6/25. * Github: https://github.com/peng051410 */ public class ConcreteEncryptor implements Encryptor { @Override public void encrypt() { System.out.println("base encrypt!"); } } 抽象加密装饰器 package cn.imcompany.decorator.encrypt; /** * Created by tomyli on 2018/6/25. * Github: https://github.com/peng051410 */ public abstract class EncryptDecorator implements Encryptor { private Encryptor encrypt; public EncryptDecorator(Encryptor encrypt) { this.encrypt = encrypt; } @Override public void encrypt() { encrypt.encrypt(); } } 上面的抽象装饰器实现的加密接口,在这个类中维护加密接口的实体,加密方法直接调用其维护实体的加密方法。 ...

2018-07-02 · 2 min · 236 words · tomyli

设计模式学习之适配器

说明 在前面的文章中介绍了一些关于支付相关的功能,现在转向登录,在早些时期的系统登录就是用户使用用户名与密码进行注册,注册成功后就可以进行登录了。随着时代的发展,出现很多三方的平台,它们对外提供了获取平台用户信息的功能,例如微信、qq、微博等三方登录,在接入这些三方登录时都是遵循相应的规则,老的登录的方式需要保留,对接新的登录方式还想要使用老的登录服务,这样可以使用适配器模式来实现。 适配器模式 比如我们平常使用的转接头一样,就是一种适配器的模式。它使两个不相关的物体很好的关联在一起。对于要接入的新的登录方式,首先定义新的三方登录的接口,定义要使用的三方登录方式,如下代码示例: package cn.imcompany.adapter; /** * Created by tomyli on 2018/6/22. * Github: https://github.com/peng051410 */ public interface ThirdLogin { void wechatLogin(String accessToken); void qqLogin(String accessToken); void sinaLogin(String accessToken); } 如上定义了微信、qq、微博三种登录方式,它们都是使用accessToken来进行认证,经用户同意后获取相应的用户的信息调用方使用。下面来进行具体的实现: package cn.imcompany.adapter; /** * Created by tomyli on 2018/6/22. * Github: https://github.com/peng051410 */ public class ThirdLoginAdapter implements ThirdLogin { private LoginService loginService; public ThirdLoginAdapter() { this.loginService = new LoginService(); } @Override public void wechatLogin(String accessToken) { System.out.println("微信获取用户信息"); loginService.login(accessToken, null); } @Override public void qqLogin(String accessToken) { System.out.println("qq获取用户信息"); loginService.login(accessToken, null); } @Override public void sinaLogin(String accessToken) { System.out.println("微博获取用户信息"); loginService.login(accessToken, null); } } 在上面的实现,并没有重新写登录的逻辑,除了要调用三方平台的代码,登录的功能是直接使用老的登录服务实现的。在这个实现类中引用了老的服务,然后使用其已经非常成熟的功能来完成登录的操作。这样以最少的代码达到了新的需求也使老的服务可以正常运行。免去了很多测试的功能点。这种适配器叫做对象适配器。 ...

2018-06-26 · 2 min · 217 words · tomyli

设计模式学习之模板模式

说明 在一般实现处理用户支付订单时,通常都会在一个单独的回调项目中来处理用户的支付方式回调。一般情况下,回调的处理过程都是相似的,大体的步骤就是获取参数->验证参数->验证签名->验证支付状态(可选)->订单状态为成功增加用户的充值金额。具体的过程由于不同的支付方式不同而处理的不同。这种需求可以使用模板的模板模式来实现。 模板设计模式实现 模板模式就是由一个类来声明整个处理流程的步骤,具体的实现由各个实现类来进行实现。处理的流程不变,变是就是里面具体的实现。针对上面的支付回调,可以声明一个抽象类来声明具体的流程方法,代码如下: package cn.imcompany.callback; import java.util.Map; /** * Created by tomyli on 2018/6/21. * Github: https://github.com/peng051410 */ public abstract class PayCallback { public abstract Map<String, String> getParam(); public abstract boolean checkParam(Map<String, String> param); public abstract boolean validSign(); /** * 定义了一个钩子方法来让子类控制流程实现 * @return true:强制返回,false:不强制返回 */ public boolean forceReturn() { return false; } public String doService() { Map<String, String> map = getParam(); if (!checkParam(map)) { return "param fail"; } if (!validSign()) { return "sign fail"; } if (!map.get("status").equals("success")) { if (forceReturn()) { return "order fail"; } } return "success"; } } 在上面的PayCallback类中声明了getParam(获取参数),checkParam(验证参数),validSign(验证签名),验证支付状态四个步骤,具体的支付回调类要来实现这里声明的方法即可。下面是一个微信支付的回调类的代码实现: ...

2018-06-25 · 2 min · 224 words · tomyli

设计模式学习之策略模式

说明 策略模式是设计模式中使用频率很高的模式,主要的就是实现对行为的包装,达到结果的方式有多种,使用者可以选择任何一个方式来得到想要结果,在增加新的方式时更加的方便与灵活。它是为了适应算法的灵活性而产生的。 策略模式实现 以常用的购物为例,一般情况下购物分为浏览商品,下单,支付。在支付时消费者可以选择多种不同的支付方式,如支付宝、微信、京东支付、银联支付等。在支付中流程就可以使用到策略模式,网站为用户提供了这些支付方式可供选择,用户只需要选择自己喜欢的支付方式来进行充值就可以得到商品了。在一般情况下都会定义一个抽象类来定义支付的一些行为,如金额,商品简介等信息。实现的抽象类如以下定义: package cn.imcompany.pay; /** * Created by tomyli on 2018/6/20. * Github: https://github.com/peng051410 */ public interface Payment { boolean pay(String param); } 这样就定义了支付方式的行为,剩下的就由不同的支付方式来进行实现,比如支付宝支付、微信支付,示例代码如下: package cn.imcompany.pay; /** * Created by tomyli on 2018/6/20. * Github: https://github.com/peng051410 */ public class AliPay implements Payment { @Override public boolean pay(String param) { System.out.println("AliPay"); return true; } } public class WechatPay implements Payment { @Override public boolean pay(String param) { System.out.println("WechatPay"); return true; } } 要是再增加一种支付方式则可以实现Payment接口进行实现就可以了,一般情况下会有一个维护支付方式的常量类,由它来维护可用的支付方式。这个常量类的简化代码如下: ...

2018-06-20 · 1 min · 159 words · tomyli

设计模式学习之工厂模式

说明 工厂设计模式是23种设计模式中使用频率非常高的,属于创建型模式。主要特点是实现了实体创建与使用的分离,达到了解耦的目的。工厂设计模式一般分为简单工厂、工厂方法、抽象工厂。 前提准备 4年一界世界杯即将到来,啤酒厂商又要大嫌一笔。我们先准备好要生产的啤酒实体。 package cn.imcompany; /** * Created by tomyli on 2018/5/27. * Github: https://github.com/peng051410 */ public interface Beer { String getName(); } public class JinShiBai implements Beer { @Override public String getName() { return "金士百"; } } public class QingDao implements Beer { @Override public String getName() { return "青岛"; } } public class BaiWei implements Beer { @Override public String getName() { return "百威"; } } 在上面定义三种啤酒,它们都由抽象类Beer继承而来。下面使用简单工厂来给消费者提供啤酒。 ...

2018-06-12 · 2 min · 413 words · tomyli

设计模式学习之原型模式

特点 原型设计模式就是系统中产生的每一个对象都不相同,通过原型来创建新的对象,原型模式属于创建型模式。 实现方式 一般情况可以通过对象克隆的方式来根据一个对象创建出来多个对象,每个对象在内存占用的内存地址都不一样。在JAVA中克隆又分为浅克隆与深克隆。 浅克隆 JAVA中是按值进行传递。实现克隆的方式就是实现Cloneable接口,这样就可以重写Object对象的clone方法来进行对象的克隆。代码如下: /** * Created by tomyli on 2018/5/30. * Github: https://github.com/peng051410 */ public class Apple implements Cloneable { public String name; public double weight; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } 测试代码如下: public static void main(String[] args) throws Exception { Apple apple = new Apple(); apple.name = "apple"; apple.weight = 2.23; try { Apple clone = (Apple)apple.clone(); System.out.println(clone == apple); } catch (Exception e) { e.printStackTrace(); } } 测试代码中clone与apple是两个完全不同的对象,这样就通过apple这个原型创建出来一个全新的对象。但是这里存在一个问题,现在Apple对象中只包含了值类型的成员变量,如果包含了其它对象会克隆也会成功吗?我们在Apple对象中增加一个Stone对象的集合,代码: ...

2018-06-09 · 1 min · 195 words · tomyli