精华内容
下载资源
问答
  • Java不足我见

    2021-03-04 01:18:55
    2005年01月19日许多人都在使用Java开发程序,本人也是其中之一,作为一名有一定软件工作经历的开发人员,我想也有必要将目前的Java开发的不足之处作一比较客观的表述,以引起业界人士对Java的优劣之处有一比较客观的...

    Java不足之我见

    作者:未知    文章来源:www.jspcn.net

    发布日期:2005年01月19日

    许多人都在使用Java开发程序,本人也是其中之一,作为一名

    有一定软件工作经历的开发人员,我想也有必要将目前的Java开发

    的不足之处作一比较客观的表述,以引起业界人士对Java的优劣之

    处有一比较客观的认识,而避免奉之过高。

    Java的许多优点,以及一些细节上的缺点在许多书上,以及网

    上评价上都有较多的描述,可是对于Java从总体上的面向对象的编

    程思想(其庞大的AWT和SWING类库)的缺点却少见贬词,且不说AWT

    和SWING的技术在许多地方互为矛盾(同时使用易出错)、互为重复

    (功能有互为重复之处),难道业界不觉得这套编程思想过于复杂吗?

    太复杂,以至于:

    1. 学习、掌握Java的多级复杂类库有一定的难度,大量掌握需

    要很多时间,而且掌握之后,一旦该编程人员不使用Java编程,那么

    掌握的类库对于其它编程语言基本无用; 而且,对于本身不是很通俗

    易懂,而是比较令人费解的程序,即便是开发人员已经掌握,而一旦

    稍长时间不接触,此种编程的许多技巧就会被忘记,除非留有带着非

    常详细注释的原代码。

    2. 编程易于或可能进入复杂的涉及多级类结构的耗时编程及调

    试的状态,象陷入乱麻之中一样;

    3. 如此复杂的程序,其他开发人员难以接手,书面详细设计方

    案上也很难表述这种立体式的复杂结构,以及上下互相之间的复杂关

    系(包括方法调用、接口的隐式调用(接口可能被自动调用)、某个方

    法是重载还是不重载(如果对上面各级类库的方法种类不是很清楚,

    从代码貌看上去,怎么知道是否是重载的呢)),等等。

    也许有人会说,你没有全部掌握,当然会有很多困难,可是Java

    庞大类库中很多都是与界面设计有关的类库,而纯粹的界面设计技术

    在应用系统之中,往往不是系统功能的核心部分,为了开发这种不是

    核心部分的界面程序,需要投入那么多的时间、精力,从这一点上来

    说,难道这种开发方式具有很大的实用意义吗?

    也许有人会认为,开发人员或许没有资格这样评价用于开发的语

    言或工具,可是:用户就是上帝,这句话永远是有道理的,既然客户

    可以评价我们开发的应用产品,我们就可以评价用于开发的语言或工

    具。

    也许有人会认为,评价的人本身也不太懂,可是,如果评价的人

    什么都懂,那他也不是Java编程人员了,那他也快要成为设计Java本

    身的技术人员了,难道Java的原创的目的就是为了让使用Java编程的

    人员都变成设计Java的人员吗?而不是为了让大家用起来都比较简单,

    从而创作出许多有用的成果吗?

    最后,作为抛砖引玉的一些结论:

    1.面向对象的编程思想,应该更多地融合或融化到可视化的开发

    环境中去,而不是仍然较多地使用语句或语言本身来描述,后者会很

    复杂,因为本来立体式的类结构,使用平面化的语句来表述,这本身

    就是很复杂,而且是勉为其难的事情;对象使用可视化的开发环境表

    示之后,编程代码(语句)应该尽可能简单易懂。

    2.庞大而且复杂的类库结构,这并不能代表着设计者的水平,对

    于使用者来说,设计者将原先复杂、庞大的东西,变得让使用者觉得

    简单而且合理,才是真正有水平的。

    在上面两点上,PowerBuilder开发工具在过去几年当中,而且直

    到现在,都是做得最好的,当然PB的PFC类库也不实用(其代码量、复

    杂度,与其实现的功能相比,显得太重,本文作者曾经重新设计PB的

    类库,功能比PFC类库强大,但使用简单,因而相对实用)。

    PB的程序封装也比Java好,PB程序封装在统一的PBL文件中,不象

    其它语言或开发工具形成多种文件,如使用JB编写的Java程序就包括

    扩展名为:jpr、html、java的文件,封装不好,程序员管理自己的代

    码就比较麻烦。

    3.面向对象的编程方式,不管采取哪一种方式,作为应用编程人

    员,在编程过程中,牵扯到类的继承级数不能太多(指系统提供的,而

    且编程过程中经常需要查阅的上级类库,加上编程人员自己设计的类),

    否则所编的程序的结构会很复杂,立体式的很复杂,会导致一些难以

    遇见的隐式错误,而且很难被发现、排除。

    4.Java在字符串类型、整数类型等细节方面也使用类的编程方式,

    这是将面向对象编程思想走向极端化的表现,实际上,使用´类´这种

    表示事物的方式,一般是在比较宏观的事物中,才显得比较方便,而

    在字符串类型、整数类型等细节微观方面,使用´类´的定义,并不方

    便,因为这不符合一般人的思维习惯,在细节微观方面,其实只要使

    用传统的非面向对象编程思想就可以了。而且,Java对于整数类型,

    既有´类´的表示方式,又有不是´类´的表示方式,以及字符串类型的

    ´类´的表示方式,这几种方式之间,牵涉到的方法名称以及使用方式

    上面互相之间都不统一,让人觉得:Java为什么要这样,这么麻烦,

    又有什么好? Java编程全是高一脚、低一脚的走路方式,为什么要这

    样,难道Java的设计者有病,为什么走路不能坦坦荡荡一些呢?

    5.正是因为上述的这些缺点,使得现在Java面向对象的编程方式,

    很难取代某些传统的编程方式,比如UNIX系统上的C编程,后者不存在

    前者的上述缺点。

    大凡伟大的创见,其在哲学上面,必然有强有力的依据,可是Java

    的上述缺点,其在哲学上面,又有什么可觉得可以说得通的呢......

    此文未及进一步整理,见谅。

    望业界人士对于此文,见仁见智,不到之处,也请斧正。

    展开全文
  • Jodd 是一个开源的 Java 工具集, 包含一些实用的工具类和小型框架。简单,却很强大!Jodd = Tools + IoC + MVC + DB + AOP + TX + JSON ...

    Jodd 是一个开源的 Java 工具集, 包含一些实用的工具类和小型框架。简单,却很强大!

    Jodd = Tools + IoC + MVC + DB + AOP + TX + JSON + HTML < 1.7 Mb

    Jodd 被分成众多模块,按需选择,其中

    • 工具类模块有:

    • jodd-core 一些工具类,包括Printf、JDateTime、StringUtil、Fast buffers等等

    • jodd-bean BeanUtil以及类型检查转换工具

    • jodd-props 更强大的Java Properties替代

    • jodd-email 更简单易用的e-mail收发

    • jodd-upload 处理HTTP上传

    • jodd-servlets 一些Servlet相关的工具类, 附带一套漂亮的JSP标签库

    • jodd-http 轻巧的HTTP客户端

    • 小型框架模块有:

    • jodd-madvoc 一个MVC框架

    • jodd-petite 一个依赖注入容器

    • jodd-lagarto HTML/XML解析器,包含Jerry和CSSelly,让你像jQuery一样筛选HTML节点

    • jodd-lagarto-web Lagarto的Web扩展,包含Decora、HtmlStapler等等

    • jodd-proxetta 帮你实现动态代理,获取函数参数名

    • jodd-dboom 数据库访问的轻量级封装,可看作一个简单的ORM

    • jodd-json JSON解析、序列化

    • jodd-vtor  一个基于注解的字段验证框架

    项目地址

    开源地址:https://gitee.com/mirrors/Jodd

    推荐阅读:

    世界的真实格局分析,地球人类社会底层运行原理

    企业IT技术架构规划方案

    华为内网最火的文章:什么是内卷?

    不是你需要中台,而是一名合格的架构师(附各大厂中台建设PPT)

    华为内部几近满分的项目管理PPT,牛逼了

    阿里达摩院《机器学习算法学习指南》火了,限时开放下载!

    小米用户画像实战,48页PPT下载

    GO语言版《算法进阶指南》火了,完整版PDF下载!

    展开全文
  • java内存溢出之Java heap space

    千次阅读 2021-03-08 09:31:48
    而内存溢出又是程序员常遇到的错误一,如果你对JVM的原理足够了解,那么解决这样的问题就不在是一件困难的事情。关于内存溢出,一般有下面这八个症状,本文将说明引发特定错误的原因,提供了可能导致此类错误的...

    作为一个java程序员,大家都应该认识JVM。JVM作为java的核心,实在太重要了。而内存溢出又是程序员常遇到的错误之一,如果你对JVM的原理足够了解,那么解决这样的问题就不在是一件困难的事情。

    关于内存溢出,一般有下面这八个症状,本文将说明引发特定错误的原因,提供了可能导致此类错误的代码示例,并提供了解决方案的修复准则,希望对做开发的小伙伴能有一定的帮助。

    本篇是第1小篇。

    OutOfMemoryError之Java heap space

    OutOfMemoryError之GC overhead limit exceeded

    OutOfMemoryError之Permgen space

    OutOfMemoryError之Metaspace

    OutOfMemoryError之Unable to create new native thread

    OutOfMemoryError之Out of swap space?

    OutOfMemoryError之Requested array size exceeds VM limit

    OutOfMemoryError之Kill process or sacrifice child

    每个Java程序都只能使用一定量的内存, 这种限制是由JVM的启动参数决定的。而更复杂的情况在于, Java程序的内存分为两部分: 堆内存(Heap space)和 永久代(Permanent Generation, 简称 Permgen):

    4454216b4022

    java内存溢出之Java heap space(1/8)

    这两个区域的最大内存大小, 由JVM启动参数 -Xmx 和 -XX:MaxPermSize 指定. 如果没有明确指定, 则根据平台类型(OS版本+ JVM版本)和物理内存的大小来确定。

    假如在创建新的对象时, 堆内存中的空间不足以存放新创建的对象, 就会引发java.lang.OutOfMemoryError: Java heap space 错误。

    不管机器上还没有空闲的物理内存, 只要堆内存使用量达到最大内存限制,就会抛出 java.lang.OutOfMemoryError: Java heap space 错误。

    原因分析

    产生 java.lang.OutOfMemoryError: Java heap space 错误的原因, 很多时候, 就类似于将 XXL 号的对象,往 S 号的 Java heap space 里面塞。其实清楚了原因, 就很容易解决对不对? 只要增加堆内存的大小, 程序就能正常运行. 另外还有一些比较复杂的情况, 主要是由代码问题导致的:

    超出预期的访问量/数据量。 应用系统设计时,一般是有 “容量” 定义的, 部署这么多机器, 用来处理一定量的数据/业务。 如果访问量突然飙升, 超过预期的阈值, 类似于时间坐标系中针尖形状的图谱, 那么在峰值所在的时间段, 程序很可能就会卡死、并触发 java.lang.OutOfMemoryError: Java heap space 错误。

    内存泄露(Memory leak). 这也是一种经常出现的情形。由于代码中的某些错误, 导致系统占用的内存越来越多. 如果某个方法/某段代码存在内存泄漏的, 每执行一次, 就会(有更多的垃圾对象)占用更多的内存. 随着运行时间的推移, 泄漏的对象耗光了堆中的所有内存, 那么 java.lang.OutOfMemoryError: Java heap space 错误就爆发了。

    具体示例

    一个非常简单的示例

    以下代码非常简单, 程序试图分配容量为 2M 的 int 数组. 如果指定启动参数 -Xmx12m, 那么就会发生 java.lang.OutOfMemoryError: Java heap space 错误。而只要将参数稍微修改一下, 变成 -Xmx13m, 错误就不再发生。

    public class OOM {

    static final int SIZE=2*1024*1024;

    public static void main(String[] a) {

    int[] i = new int[SIZE];

    }

    }

    内存泄漏示例

    这个示例更真实一些。在Java中, 创建一个新对象时, 例如 Integer num = new Integer(5); , 并不需要手动分配内存。因为 JVM 自动封装并处理了内存分配. 在程序执行过程中, JVM 会在必要时检查内存中还有哪些对象仍在使用, 而不再使用的那些对象则会被丢弃, 并将其占用的内存回收和重用。这个过程称为 垃圾收集. JVM中负责垃圾回收的模块叫做 垃圾收集器(GC)。

    Java的自动内存管理依赖 GC, GC会一遍又一遍地扫描内存区域, 将不使用的对象删除. 简单来说, Java中的内存泄漏, 就是那些逻辑上不再使用的对象, 却没有被 垃圾收集程序 ****给****干掉. 从而导致垃圾对象继续占用堆内存中, 逐渐堆积, 最后造成 java.lang.OutOfMemoryError: Java heap space 错误。

    很容易写个BUG程序, 来模拟内存泄漏:

    import java.util.*;

    public class KeylessEntry {

    static class Key {

    Integer id;

    Key(Integer id) {

    this.id = id;

    }

    @Override

    public int hashCode() {

    return id.hashCode();

    }

    }

    public static void main(String[] args) {

    Map m = new HashMap();

    while (true){

    for (int i = 0; i < 10000; i++){

    if (!m.containsKey(new Key(i))){

    m.put(new Key(i), "Number:" + i);

    }

    }

    System.out.println("m.size()=" + m.size());

    }

    }

    }

    粗略一看, 可能觉得没什么问题, 因为这最多缓存 10000 个元素嘛! 但仔细审查就会发现, Key 这个类只重写了 hashCode() 方法, 却没有重写 equals() 方法, 于是就会一直往 HashMap 中添加更多的 Key。

    随着时间推移, “cached” 的对象会越来越多. 当泄漏的对象占满了所有的堆内存, GC 又清理不了, 就会抛出 java.lang.OutOfMemoryError:Java heap space 错误。

    解决办法很简单, 在 Key 类中恰当地实现 equals() 方法即可:

    @Override

    public boolean equals(Object o) {

    boolean response = false;

    if (o instanceof Key) {

    response = (((Key)o).id).equals(this.id);

    }

    return response;

    }

    说实话, 在寻找真正的内存泄漏原因时, 你可能会死掉很多很多的脑细胞。

    一个SpringMVC中的场景

    译者曾经碰到过这样一种场景:

    为了轻易地兼容从 Struts2 迁移到 SpringMVC 的代码, 在 Controller 中直接获取 request.

    所以在 ControllerBase 类中通过 ThreadLocal 缓存了当前线程所持有的 request 对象:

    public abstract class ControllerBase {

    private static ThreadLocal requestThreadLocal = new ThreadLocal();

    public static HttpServletRequest getRequest(){

    return requestThreadLocal.get();

    }

    public static void setRequest(HttpServletRequest request){

    if(null == request){

    requestThreadLocal.remove();

    return;

    }

    requestThreadLocal.set(request);

    }

    }

    然后在 SpringMVC的拦截器(Interceptor)实现类中, 在 preHandle 方法里, 将 request 对象保存到 ThreadLocal 中:

    /**

    * 登录拦截器

    */

    public class LoginCheckInterceptor implements HandlerInterceptor {

    private List excludeList = new ArrayList();

    public void setExcludeList(List excludeList) {

    this.excludeList = excludeList;

    }

    private boolean validURI(HttpServletRequest request){

    // 如果在排除列表中

    String uri = request.getRequestURI();

    Iterator iterator = excludeList.iterator();

    while (iterator.hasNext()) {

    String exURI = iterator.next();

    if(null != exURI && uri.contains(exURI)){

    return true;

    }

    }

    // 可以进行登录和权限之类的判断

    LoginUser user = ControllerBase.getLoginUser(request);

    if(null != user){

    return true;

    }

    // 未登录,不允许

    return false;

    }

    private void initRequestThreadLocal(HttpServletRequest request){

    ControllerBase.setRequest(request);

    request.setAttribute("basePath", ControllerBase.basePathLessSlash(request));

    }

    private void removeRequestThreadLocal(){

    ControllerBase.setRequest(null);

    }

    @Override

    public boolean preHandle(HttpServletRequest request,

    HttpServletResponse response, Object handler) throws Exception {

    initRequestThreadLocal(request);

    // 如果不允许操作,则返回false即可

    if (false == validURI(request)) {

    // 此处抛出异常,允许进行异常统一处理

    throw new NeedLoginException();

    }

    return true;

    }

    @Override

    public void postHandle(HttpServletRequest request,

    HttpServletResponse response, Object handler, ModelAndView modelAndView)

    throws Exception {

    removeRequestThreadLocal();

    }

    @Override

    public void afterCompletion(HttpServletRequest request,

    HttpServletResponse response, Object handler, Exception ex)

    throws Exception {

    removeRequestThreadLocal();

    }

    }

    在 postHandle 和 afterCompletion 方法中, 清理 ThreadLocal 中的 request 对象。

    但在实际使用过程中, 业务开发人员将一个很大的对象(如占用内存200MB左右的List)设置为 request 的 Attributes, 传递到 JSP 中。

    JSP代码中可能发生了异常, 则SpringMVC的postHandle 和 afterCompletion 方法不会被执行。

    Tomcat 中的线程调度, 可能会一直调度不到那个抛出了异常的线程, 于是 ThreadLocal 一直 hold 住 request。 随着运行时间的推移,把可用内存占满, 一直在执行 Full GC, 系统直接卡死。

    后续的修正: 通过 Filter, 在 finally 语句块中清理 ThreadLocal。

    @WebFilter(value="/*", asyncSupported=true)

    public class ClearRequestCacheFilter implements Filter{

    @Override

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,

    ServletException {

    clearControllerBaseThreadLocal();

    try {

    chain.doFilter(request, response);

    } finally {

    clearControllerBaseThreadLocal();

    }

    }

    private void clearControllerBaseThreadLocal() {

    ControllerBase.setRequest(null);

    }

    @Override

    public void init(FilterConfig filterConfig) throws ServletException {}

    @Override

    public void destroy() {}

    }

    教训是:可以使用 ThreadLocal, 但必须有受控制的释放措施、一般就是 try-finally 的代码形式。

    说明: SpringMVC 的 Controller 中, 其实可以通过 @Autowired 注入 request, 实际注入的是一个 HttpServletRequestWrapper 对象, 执行时也是通过 ThreadLocal 机制调用当前的 request。

    常规方式: 直接在controller方法中接收 request 参数即可。

    解决方案

    如果设置的最大内存不满足程序的正常运行, 只需要增大堆内存即可, 配置参数可以参考下文。

    但很多情况下, 增加堆内存空间并不能解决问题。比如存在内存泄漏, 增加堆内存只会推迟 java.lang.OutOfMemoryError: Java heap space 错误的触发时间。

    当然, 增大堆内存, 可能会增加 GC pauses 的时间, 从而影响程序的 吞吐量或延迟。

    要从根本上解决问题, 则需要排查分配内存的代码. 简单来说, 需要解决这些问题:

    哪类对象占用了最多内存?

    这些对象是在哪部分代码中分配的。

    要搞清这一点, 可能需要好几天时间。下面是大致的流程:

    获得在生产服务器上执行堆转储(heap dump)的权限。“转储”(Dump)是堆内存的快照, 稍后可以用于内存分析. 这些快照中可能含有机密信息, 例如密码、信用卡账号等, 所以有时候, 由于企业的安全限制, 要获得生产环境的堆转储并不容易。

    在适当的时间执行堆转储。一般来说,内存分析需要比对多个堆转储文件, 假如获取的时机不对, 那就可能是一个“废”的快照. 另外, 每次执行堆转储, 都会对JVM进行“冻结”, 所以生产环境中,也不能执行太多的Dump操作,否则系统缓慢或者卡死,你的麻烦就大了。

    用另一台机器来加载Dump文件。一般来说, 如果出问题的JVM内存是8GB, 那么分析 Heap Dump 的机器内存需要大于 8GB. 打开转储分析软件(我们推荐Eclipse MAT , 当然你也可以使用其他工具)。

    检测快照中占用内存最大的 GC roots。详情请参考: Solving OutOfMemoryError (part 6) – Dump is not a waste。 这对新手来说可能有点困难, 但这也会加深你对堆内存结构以及navigation机制的理解。

    接下来, 找出可能会分配大量对象的代码. 如果对整个系统非常熟悉, 可能很快就能定位了。

    打个广告, 我们推荐 Plumbr, the only Java monitoring solution with automatic root cause detection。 Plumbr 能捕获所有的 java.lang.OutOfMemoryError , 并找出其他的性能问题, 例如最消耗内存的数据结构等等。

    Plumbr 在后台负责收集数据 —— 包括堆内存使用情况(只统计对象分布图, 不涉及实际数据),以及在堆转储中不容易发现的各种问题。 如果发生 java.lang.OutOfMemoryError , 还能在不停机的情况下, 做必要的数据处理. 下面是Plumbr 对一个 java.lang.OutOfMemoryError 的提醒:

    4454216b4022

    java内存溢出之Java heap space(1/8)

    强大吧, 不需要其他工具和分析, 就能直接看到:

    哪类对象占用了最多的内存(此处是 271 个 com.example.map.impl.PartitionContainer 实例, 消耗了 173MB 内存, 而堆内存只有 248MB)

    这些对象在何处创建(大部分是在 MetricManagerImpl 类中,第304行处)

    当前是谁在引用这些对象(从 GC root 开始的完整引用链)

    得知这些信息, 就可以定位到问题的根源, 例如是当地精简数据结构/模型, 只占用必要的内存即可。

    当然, 根据内存分析的结果, 以及Plumbr生成的报告, 如果发现对象占用的内存很合理, 也不需要修改源代码的话, 那就增大堆内存吧。在这种情况下,修改JVM启动参数, (按比例)增加下面的值:

    -Xmx1024m

    这里配置Java堆内存最大为 1024MB。可以使用 g/G 表示 GB, m/M 代表 MB, k/K 表示 KB.

    下面的这些形式都是等价的, 设置Java堆的最大空间为 1GB:

    # 等价形式: 最大1GB内存

    java -Xmx1073741824 com.mycompany.MyClass

    java -Xmx1048576k com.mycompany.MyClass

    java -Xmx1024m com.mycompany.MyClass

    java -Xmx1g com.mycompany.MyClass

    展开全文
  • Stream API了解StreamJava8中有两个比较大的改变Lambda表达式Stream API (java.util.stream.*)Stream是Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找,过滤和映射数据...

    Stream API

    了解Stream

    Java8中有两个比较大的改变

    Lambda表达式

    Stream API (java.util.stream.*)

    Stream是Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找,过滤和映射数据等操作。使用Stream API对集合数据进行操作,就类似于使用SQL执行的数据库查询,也可以使用Stream API来并行操作,简而言之,Stream API提供了一种高效且易于使用的处理数据的方式。

    区别

    这里的Stream流和IO流是有区别的,这里是我们在数据源流向 目标源的时候,会产生一系列流水线式的中间操作,最后产生一个新流,同时原来的数据源是不会改变的。

    这里的中间操作可能是:切片,排序,筛选等

    什么是Stream

    Stream是数据渠道,用于操作数据源(集合,数组等)所生成的元素序列,“集合讲的是数据,流讲的是计算”!

    注意:

    Stream 自己不会存储元素

    Stream 不会改变源对象,相反,他们会返回一个持有结果的新Stream

    Stream 操作是延迟的,这就意味着他们会等到需要结果的时候才执行的

    Stream操作的三部曲

    创建流

    一个数据源(如:集合,数组),获取一个流

    通过Collection系列集合的 stream() 或者 parallelStream()获取流

    List list = new ArrayList<>();

    Stream stream = list.stream();

    通过Arrays 中的静态方法,获取数组流

    Employee[] employees = new Employee[10];

    Stream stream1 = Arrays.stream(employees);

    通过Stream中的静态方法of(),获取流

    Stream stream3 = Stream.of("aa", "bb", "cc");

    创建无限流

    Stream stream4 = Stream.iterate(0, (x) -> x +2 );

    中间操作

    一个中间操作链,对数据源的数据进行处理

    终止操作

    一个终止操作,执行中间操作链,并产生结果

    Stream流的操作

    多中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否者中间操作不会执行任何的处理,而在终止操作时一次性全部处理,这样被称为 惰性求值

    筛选与切片

    filter( Predicate p):接收Lambda,从流中排除某些元素

    distinct():筛选,通过流所生成的hashCode()和equals()去除重复元素

    limit(long maxSize):截断流,使其元素不超过给定数量

    skip(long n):跳过元素,返回一个扔掉了前n个元素的流,若流中元素不足n个,则返回一个空流

    List employees = Arrays.asList(

    new Employee("张三", 18, 3333),

    new Employee("李四", 38, 55555),

    new Employee("王五", 50, 6666.66),

    new Employee("赵六", 16, 77777.77),

    new Employee("田七", 8, 8888.88)

    );

    Stream stream = employees.stream();

    stream.filter((x) -> x.getAge() > 30)

    .limit(2)

    .forEach(System.out::println);

    映射

    map接收Lambda,将元素转换成其它形式或提取信息,接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新元素。flatMap 接收一个函数作为参数,将流中的每个值都转换成另一个流,然后把所有流连接成一个流。

    public static void test2() {

    List list = Arrays.asList("aaa", "bbb", "ccc", "ddd");

    list.stream().map((x) -> x.toUpperCase()).forEach(System.out::println);

    }

    排序

    sorted():自然排序

    sorted(Comparator com):定制排序

    public static void test3() {

    List list = Arrays.asList("aaa", "bbb", "ccc", "ddd");

    // 自然排序,按照字典进行排序

    list.stream().sorted().forEach(System.out::println);

    // 定制排序

    List employees = Arrays.asList(

    new Employee("张三", 18, 3333),

    new Employee("李四", 38, 55555),

    new Employee("王五", 50, 6666.66),

    new Employee("赵六", 16, 77777.77),

    new Employee("田七", 8, 8888.88)

    );

    employees.stream().sorted((e1, e2) -> {

    if(e1.getAge() == e2.getAge()) {

    return e1.getName().compareTo(e2.getName());

    } else {

    return Integer.compare(e1.getAge(), e2.getAge());

    }

    }).forEach(System.out::println);

    }

    输出结果:

    aaa

    bbb

    ccc

    ddd

    Employee{name='田七', age=8, salary=8888.88}

    Employee{name='赵六', age=16, salary=77777.77}

    Employee{name='张三', age=18, salary=3333.0}

    Employee{name='李四', age=38, salary=55555.0}

    Employee{name='王五', age=50, salary=6666.66}

    终止操作

    执行下列操作后,Stream流就会进行终止执行

    查找与匹配

    allMatch:检查是否匹配所有元素

    anyMatch:检查是否至少匹配一个元素

    noneMatch:检查是否一个都没匹配

    findFirst:返回第一个元素

    findAny:返回当前流中任意一个元素

    count:返回流中元素的个数

    max:返回当前流中最大值

    min:返回当前流中最小值

    forEach:内部迭代

    public static void test4() {

    // 定制排序

    List employees = Arrays.asList(

    new Employee("张三", 18, 3333),

    new Employee("李四", 38, 55555),

    new Employee("王五", 50, 6666.66),

    new Employee("赵六", 16, 77777.77),

    new Employee("田七", 8, 8888.88)

    );

    Boolean isAllMatch = employees.stream().allMatch((x) -> x.getAge() > 10);

    System.out.println("是否匹配所有元素:" + isAllMatch);

    Boolean isAnyMatch = employees.stream().anyMatch((x) -> x.getAge() > 10);

    System.out.println("是否匹配至少一个元素:" + isAnyMatch);

    }

    规约

    格式:reduce(T identity, BinaryOperator) / reduce(BinaryOperator)可以将流中元素反复结合,得到一个新值

    这个reduce,其实有点类似于Hadoop中的mapReduce,先做map操作,然后做reduce操作

    List list = Arrays.asList(1, 2, 3, 4, 5 ,6 ,7 ,8 , 9, 10);

    // 按照下面的规则进行累加操作

    // reduce的规约,就是把前面定义的起始值,作为了x

    Integer num = list.stream().reduce(0, (x, y) -> x + y);

    System.out.println(num);

    收集

    Collection将流转换成其它形式,接收一个Collector接口实现,用于给Stream中元素做汇总的方法

    格式:collect(Collector c)

    Collector接口实现方法的实现决定了如何对流执行收集操作(如收集到List,Set,Map)。但是Collectors实用类提供了很多静态方法,可以方便地创建常用收集器实例

    /**

    * 收集器

    */

    public static void test6() {

    List employees = Arrays.asList(

    new Employee("张三", 18, 3333),

    new Employee("李四", 38, 55555),

    new Employee("王五", 50, 6666.66),

    new Employee("赵六", 16, 77777.77),

    new Employee("田七", 8, 8888.88)

    );

    // 收集放入list中

    List list = employees.stream().map(Employee::getName).collect(Collectors.toList());

    list.forEach(System.out::println);

    }

    展开全文
  • 在开发中大型Java软件项目时,很多Java架构师都会遇到数据库读写瓶颈,如果你在系统架构时并没有将缓存策略考虑进去,或者并没有选择更优的 缓存策略,那么到时候重构起来将会是一个噩梦。本文主要是分享了5个常用的...
  • JavaCV推流到媒体服务器,再用播放器在线播放
  • 借助JavaCV,完成本地摄像头和麦克风数据推送到媒体服务器的操作,并用VLC验证
  • Java中最强大的技术一  反射  获取Class类1、反射概述2、类的加载过程3、获取Class类的三种方式3.1 通过 class.forname()来获取Class对象3.2 通过类名.class来获取Class对象3.3 通过对象的...
  • Java常见设计模式总结

    万次阅读 多人点赞 2021-09-18 17:18:54
    项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现实中都有相应的原理来与对应,每种模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。...
  • Java之Resource接口

    2021-03-21 08:48:47
    接口简介JDK中提供了java.net.URL这个类来用于获取不同种类的资源(根据不同前缀的url可以获取不同种类的资源)。但是URL这个类没有获取classpath和ServletContext下的资源的能力。因此Spring提供了Resource接口,用于...
  •  file.rtf, "A File.docx") Here is a Java method and C++ function that takes the filename as an argument and prints the file: Java public void printWordFile(String filename){ System.getRuntime().exec...
  • javascript与java有什么区别

    千次阅读 2021-03-17 23:48:33
    2020-06-10 19:19:20来源:亿速云阅读:186作者:鸽子Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。...
  • java之——注解

    千次阅读 2021-03-09 23:56:13
    Annoation(注解)是Java提供的一种对元程序中元素关联信息和元数据(metadata)的途径和方法。Annotation是一个接口,程序可以通过反射来获取指定元素的Annotation对象,然后通过该Annotation对象来获取注解中的元数据...
  • Java强大

    千次阅读 2021-03-16 19:27:20
    Java强大:手机大头手机大头是业内首家开创性地将手机浏览器、手机音乐、手机铃声、手机视频等多功能有机整合于一身的手机端的多媒体软件。特点是整合度很高,只在用户需要安装的时候才安装需要使用的那一部分功能...
  • 业务中,经常会遇到类似将...),一般手写一个函数就能转换,下面使用流提供的强大功能,提供一个静态的方法转换任意list集合。 Skin类: public class Skin { public int getId() { return id; } public in
  • 史上最全Java初中级面试题,发现网上很多Java初级面试题都没有答案,所以花了很长时间搜集整理出来了这套Java面试题大全,希望对大家有帮助哈~ 本人发现网上虽然有不少Java相关的面试题,但第一未必全,第二未必有...
  • 是什么技术如此强大
  • Java 16 虽然是 2021 年 3 月 16 号发布的最新正式版本,但 6 个月后也要停止更新了,虽然这个版本带来了很多漂亮的新特性,但生命周期有限,对 Java 8 的伤害性有限。 自从 JDK 1.0 发布以来,Java 已经发布了数次...
  • import java.util.List; public interface DAO { void insert(T t); T findById(String id); List findAll(); void delete(String id); } 一、再根据要求,先把四个类的属性类建立起来: 1.Admin类(管理员类)...
  • java自带的强大工具 jconsole:简易的可视化控制台 jvisualvm:功能强大的控制台
  • 详解java NIOChannel(通道)

    千次阅读 2021-02-18 22:51:14
    通道(Channel)是java.nio的第二个主要创新。它们既不是一个扩展也不是一项增强,而是全新、极好的Java I/O示例,提供与I/O服务的直接连接。Channel用于在字节缓冲区和位于通道另一侧的实体(通常是一个文件或套接...
  • 借助JavaCV,将摄像头的视频和麦克风的音频保存到mp4文件中
  • Java

    2021-06-13 18:16:02
    Java发展史 1991年,James Gosling在SUN公司的工程师小组想要设计这样一种小型计算机语言。该语言主要用于像电视盒这样的消费类电子产品。另外,由于不同的厂商选择不同的CPU和操作系统,因此,要求该语言不能和特定...
  • 现在很多业务都是面向于B/S模式的开发,JAVA也不另外。所以JAVA的程序员对J2EE部分的知识非常了解。却对J2SE的知识点半知半解。甚至有一些只是听过而以。笔者在进入JAVA企业开发之前也曾用过Awt和Swing开发PC端的...
  • import ...import java.util.*;public class a123 {public static void main(String args[]) {int m, n;Scanner in = new Scanner(System.in);while ((m = in.nextInt()) != 0 | (...
  • JavaCV的摄像头实战八:人脸检测

    千次阅读 多人点赞 2021-12-05 16:14:04
    } 运行main方法即可启动程序,如下图,预览窗口中如果有人像,人脸上就会出现红框(为了不侵犯群众演员的肖像权,手动对面部做了马赛克处理): 至此,本地窗口预览集成人脸检测的功能就完成了,得益于JavaCV的强大,...
  • Java日志

    千次阅读 2021-02-12 17:02:39
    日志对于一个系统来说非常重要,查找异常信息、分析系统运行情况等都需要用到...JDK的java.util.logging包第三方日志工具(commons-logging/slf4j,log4j/logback)JDK的java.util.logging包JDK1.4引入了java.util....
  • JAVA和C#在占位符方面有些区别,C#提供的占位符是用{num}这种形式,Java需要用%s这种形式,不太习惯,经查发现MessageFormat提供了花括号占位符的功能。【转自】...
  • 对于更加特殊的需求,还可以考虑通过 JNI 的方法直接调用系统 API 来实现,能提供更加强大和灵活的功能,这里就不再赘述了。 原文链接: ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 565,336
精华内容 226,134
关键字:

java的强大之处

java 订阅