前言由于本人的性格,笔者很难安下心来进行认真的系统学习。总喜欢折腾一些奇怪的技能。这一次,我想分享一下我所知道的如何编写最少代码的技巧。Java:我要返回多个返回值ShowGo的多个返回值:packagemainimport"fmt"//returnX+YandX*YfuncComputer(X,Yint)(int,int){returnX+Y,X*Y}众所周知,Java只支持单一的返回值。一般来说,如果我们需要返回多个对象,我们会根据代码语义选择一个容器或者新建一个类来包装我们需要的数据。这样做有什么问题吗?当然没有问题,但缺陷是:可能存在没有语义但又不得不存在的中间类。我个人非常讨论这类代码,那么如何解决这个问题呢?首先,你需要知道解决方案必须满足几个要求:代码复用性必须清晰和安全这种情况下,我们可以使用泛型来满足复用和语义清晰的要求,使用中间类来满足代码的要求安全。代码如下:publicclassMultipleTwoReturn{/**第一个返回值**/privatefinalAfirst;/**第二个返回值**/privatefinalBsecond;publicMultipleTwoReturn(Afirst,Bsecond){this.first=first;this.second=second;}//省略Get方法}同时我们可以依靠继承让工具类扩展更多的参数:publicclassMultipleThreeReturnextendsMultipleTwoReturn{/**第三个返回值**/privatefinalCthird;publicMultipleThreeReturn(Afirst,Bsecond,Cthird){super(first,second);this.third=third;}}测试类:publicclassMultipleApp{publicstaticvoidmain(String[]args){MultipleTwoReturnreturnTest=MultipleApp.getReturnTest();System.out.println(returnTest.getFirst());System.out.println(returnTest.getSecond());}privatestaticMultipleTwoReturngetReturnTest(){MultipleTwoReturndemo=newMultipleTwoReturn<>(0,"KerwinDemo.");returndemo;}}本质还是一个普通的对象,但是加入泛型后威力猛增!因为泛型约束是在方法定义的时候强制执行的,所以语义非常清晰,同时,上面提到的非语义中间类完全可以去掉,当然一些必要的有业务意义的组装类,不推荐这种方法泛型:我认为new是一个对象。刚开始学习Java泛型的时候是不是也有这样的想法呢?我想把它作为一个泛型约束,但是我需要一个newT,但是java拿不到new。😂编写一个通用的Java爬虫接口,具有传入目标网页获取不同网页设计bean的功能,如下:publicinterfaceSpiderBeansHandle{/**GetUrl**/StringgetUrl();/**获取Cookie**/StringgetCookie();/**获取CSSselector**/StringgetSelector();//...}中间的重点就是如何获取这个Bean。那时我只有一个想法:新的AT事实证明我太天真了🙄不过换个思路,既然new不上了,那我就return了,所以放出代码~publicinterfaceSpiderBeansHandle{/***GetUrl*/StringgetUrl();/***GetCookie*/StringgetCookie();/****获取CSSselector*/StringgetSelector();/****解析元素*@paramelementelement*/TparseElement(Elementelement);/****GetBeans*@paramhandleBeanobject|handleobject*@paramBean类型*@returnList*/staticListgetBeans(SpiderBeansHandlehandle){Listlist=newArrayList<>();Listelements=SpiderUtils.getElementWithCookie(handle.getUrl(),handle.getSelector(),handle.getCookie());for(Elementelement:elements){Tbean=handle.parseElement(element);if(bean!=null){list.add(bean);}}returnlist;}}关键步骤是:/*****parseElement*@paramelementelement*/TparseElement(Elementelement);那么这个小技巧有什么用呢?如果你仔细看,你觉得它看起来像一个设计模式的变体吗?是的!只有一个事实:模板方法模式。刚才提到需要一个通用的接口来处理爬虫,因为简单的爬虫无非就是获取url并发起请求,将解析细节封装到自己的Bean中,然后获取一个列表,然后就是类似在开发业务代码的时候,肯定有一定的场景和需求是高度一致的,那么采用这种设计方案是可以大大减少重复代码的~方法:你想做什么?你在写代码的时候遇到过这种问题吗?我写了一个工具方法,但是功能太单一了。单一的原理虽然还好,但是一个小逻辑写一堆方法总感觉别扭,怎么解决?Java8提供的函数式编程可以在一定程度上帮助我们解决这类问题,比如://写一个获取文件的列表,判断是否为txt最后的工具类方法,新手会写publicstaticFilegetFileWithTxt(Stringpath)throwsIOException{Filefile=newFile(path);if(!file.exists()){thrownewIOException("Fileisnotexist.");}if(file.getName().endsWith(".txt")){returnfile;}returnull;}老手一般都会传入.txt作为参数,但是有一天我需要判断文件大小,文件长度,甚至文件内容,怎么办?多写N?最好的方案是传入Predicate谓词,让调用者自定义处理逻辑,然后基于这个方法重写最常用的逻辑,扩展性Max!代码如下:/****文件夹谓词匹配*@paramfile文件*@parampredicate谓词匹配*@returnList*@throwsIOExceptionIOException*/publicstaticListlistFilesInDirWithFilter(Filefile,Predicatepredicate)throwsIOException{if(!file.exists()){thrownewIOException("Fileisnotexist.");}ListfileList=newArrayList<>();if(file.isDirectory()){File[]files=file.listFiles();for(Filef:Objects.requireNonNull(files)){fileList.addAll(listFilesInDirWithFilter(f,predicate));}}else{if(predicate.test(file.getName()))){fileList.add(file);}}returnfileList;}同理,比如处理IO,直接添加代码:publicstaticvoidreadLine(BufferedReaderbr,Consumerhandle,booleanclose){Strings;try{while(((s=br.readLine())!=null)){handle.accept(s);}}catch(IOExceptione){e.printStackTrace();}最后{if(close&&br!=null){try{br.close();}catch(IOExceptione){e.printStackTrace();}}}方法说你想做什么?!算了,想怎么写就怎么写吧,请随意😎~过载:多写More是为了少写。多写也是为了少写。这句话乍一看很矛盾,但是有丰富编程经验的朋友应该能体会到方法重载的威力,尤其是在写工具类或者底层接口的时候,建议先写一个大而全的综合内部方法,然后根据需要稍微重载一下,会有意想不到的好处最简单的例子如下://根方法privatestaticvoidreadLine(BufferedReaderbr,Consumerhandle,booleanclose){Strings;try{while(((s=br.readLine())!=null)){handle.accept(s);}}catch(IOExceptione){e.printStackTrace();}finally{if(close&&br!=null){try{br.close();}catch(IOExceptione){e.printStackTrace();}}}}//重载方法publicstaticvoidreadLine(Stringpath,Consumerhandle,booleanclose){try{BufferedReaderbr=newBufferedReader(newFileReader(path));readLine(br,handle,close);}catch(FileNotFoundExceptione){e.printStackTrace();}}//重载方法2publicstaticvoidreadLine(Stringpath,Consumerhandle){readLine(path,handle,true);}重载可以让我们的方法调用方法丰富多彩,语义清晰在这种情况下,写代码是就像天赐之物。通过函数式编程,可以大大增强工具类或底层接口的能力。同时,当我们需要对某个方法的逻辑进行调整时,也可以采用不断重载的方法,将影响降到最低,尽量不要动其他模块的代码。Ultimate:FromDesignPatternstoAbstraction与其说是如何写最少的代码,不如说是:如何只写真正有价值的代码。面对这类问题,我们的第一反应肯定是设计模式,比如上面泛型部分提到的模板方法模式,小推荐一下我之前的文章:【一起学习系列】模板方法:它只需要我5分钟写出SSO设计模式通篇:从为什么需要原理到实际实现通过一个好的设计模式或者它的变体,我们可以获得高内聚低耦合的代码。这是一个很好的主意。另一种思路,大家都认同:程序=算法+数据结构,选择正确的数据结构可以事半功倍,比如我们在做类似文件夹需求的时候,就会想到使用链表或者树结构,如:如何高效地给用户发送生日短信时,会想到使用堆结构(将堆中的最大值与当前时间进行比较,如果满足则继续迭代减少遍历)和很快。这些实际上是抽象,或深或浅。刚开始学Java的时候,老师会说:万物皆对象。让我们看看上面每个技能对应的是什么。多返回值:封装对象+泛型约束泛型:封装对象的公共接口,高度抽象的功能方式:将方法重载为对象:对象方法(行为)的不断进化那么如何只写真正有价值的代码呢?官方的说法是:抽象变化,那么怎么画呢?这需要我们一点点探索。毕竟奇异技能只是一个小道尔,还需我继续探索。