V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
ojh
V2EX  ›  程序员

关于 Java 笨重一说

  •  
  •   ojh · 2022-05-07 23:31:10 +08:00 · 8827 次点击
    这是一个创建于 934 天前的主题,其中的信息可能已经有所发展或是发生改变。

    今天有个帖子是说 Java 笨重、Spring 框架笨重,看完了总结了“笨重”的几点

    • 内存占用多
    • JRE 很大
    • 配置很复杂
    • 依赖很多包,打包出来很大( Srping/SpringBoot )

    内存占用多

    这个无可厚非,毕竟运行在虚拟机上。但是之前看过一篇博客对比了 Quarkus (印象中) JIT 和 AOT 两种模式下运行内存的占用,启动初期 AOT 完胜 JIT ,但是高负载情况下两者差不多,所以我想了解下是如果同等高负载的情况下,C++/Go 这类的服务端程序的内存占用跟 Java (最新) 比差距大不大呢。

    JRE 很大

    这个如果在最新 Java 下面用 jlink 并且压缩一下应该 50MB (包含 JavaFX 了,不包含的没试过) 左右,一个带 JRE 的 Java 应用 50MB 应该还可以接受吧。其实我疑惑的是很多人吐槽 JRE 大,没人吐槽 NodeJS 或者 Python 大么

    配置很复杂

    估计指的是 Servlet 那套 web.xml 配置以及远古时代 Spring 的 context.xml ,这个我也想吐槽,不过 SpringBoot 应该缓解了这个问题

    打出来的包很大

    Srping/SpringBoot 为了方便开发提供了很多大而全的东西所以很大,如果你的程序就简单的接口,业务代码也很简单,什么依赖注入、切面、请求体转换、参数校验等等功能都用不到,那也没必要用 Spring 框架。顺便问一句有什么好 Java Web 框架脱离 Servlet 体系又很瘦小的

    其实对于我这个 Java 菜鸡来说上面问题都不是让我郁闷的,真正让我郁闷的是 Java 为什么这么多规范!这么多规范真的好吗?

    • Servlet 规范,大环境下啥时候可以脱离这玩意啊
    • Getter 、Setter 方法,我见了很多类的 Getter 、Setter 根本就没什么逻辑在里面,为什么不直接 Public 呢?
    • 面向接口编程,特别 Spring 开发模式,很多 xxxService/xxxServiceImpl ,经常要改变实现类?我没见过要改的。这种规范搞到一个简单的请求处理分了好几层,写得贼难受,但是公司项目就这样必须做到统一
    第 1 条附言  ·  2022-05-08 00:14:54 +08:00
    可能我标题加粗有误,这个不是吐槽帖子是讨论帖子
    89 条回复    2022-05-10 06:14:03 +08:00
    ikas
        1
    ikas  
       2022-05-07 23:49:10 +08:00   ❤️ 1
    本来想一一回复的..发现没有意义..

    还是多学点吧
    thinkershare
        2
    thinkershare  
       2022-05-07 23:51:59 +08:00
    Java 整个体系没啥大问题, 除了啰嗦了点. 否则也不会成为如今后端的 TOP 1 了, 虽然有历史的进程原因.
    1. Servlet 规范是没法抛弃的, 这个本质上就是整个 JAVA 生态的原初理念
    2. 字段不应该直接暴露, 这个和有无逻辑毫无关系, 暴露细节违反了面向对象最基础封装特性, 这个几乎没有争议
    3. 面向接口编程没啥问题, Java 一些解决方案的复杂化是因为大家都过渡追求复用, 然后过度抽象. 如果你确定一个东西不会更改, 你完全就可以直接 new, 你看你的代码是不是到处都在直接构造 String 这些基本类型. 最佳实践都是人们踩过的坑后慢慢总结出来的, 因此公司项目还是要以规范性为主, 因为你需要和其它人协作, 多人协作一致性是最重要的一条原则.
    ojh
        3
    ojh  
    OP
       2022-05-07 23:59:01 +08:00
    @ikas 大佬请指点下迷津,特别 Getter 、Setter 方法你有什么看法
    geekvcn
        4
    geekvcn  
       2022-05-07 23:59:06 +08:00   ❤️ 3
    培训班出来的半吊子太多了,把自己的缺点说成语言的缺点。
    Leviathann
        5
    Leviathann  
       2022-05-08 00:01:17 +08:00
    对外暴露的是 property
    不一定需要对应一个 field
    而具体有没有对应一个 field 外界不需要知道
    连 js 都有 getter setter 了
    ojh
        6
    ojh  
    OP
       2022-05-08 00:01:54 +08:00
    @thinkershare 但是这些好像就唯独 Java 特有,其他后端语言也没这么麻烦
    golangLover
        7
    golangLover  
       2022-05-08 00:04:44 +08:00 via Android
    @ojh 学一下 lombok
    geekvcn
        8
    geekvcn  
       2022-05-08 00:07:15 +08:00
    第一点内存占用多,你为什么不用 C++写项目?有人逼着你用 Java 写? Java 跑在 JVM 上,天生就多了 JVM 的内存占用,真内存敏感还非要用真的是你自己的问题。
    JRE 很大,如果你是上世纪的电脑我还能理解,如今的电脑 JRE 那大小算个屁。
    配置很复杂,依赖很多,打出来的包很大 这两条就更离谱了?你是把框架的问题算到 Java 头上了,你不满意现有轮子,自己造轮子不就行了,没人逼你用这些框架吧?
    Leviathann
        9
    Leviathann  
       2022-05-08 00:07:51 +08:00   ❤️ 1
    大部分 springer 都把对象当成是函数的命名空间或者数据的载体在用,而不是真把它当成一个状态与行为的聚合体
    实际上就是在写假装是面向对象的过程式代码
    ojh
        10
    ojh  
    OP
       2022-05-08 00:10:08 +08:00
    @geekvcn 大佬莫激动,我是总结另外一个帖子,然后再发表了一下自己认为的解决方案,这个是讨论帖子不是吐槽帖😂
    ojh
        11
    ojh  
    OP
       2022-05-08 00:11:24 +08:00
    @Leviathann 可能我对 Java 的 field 和 property 欠缺理解,要去补补了
    yesterdaysun
        12
    yesterdaysun  
       2022-05-08 00:31:44 +08:00
    我觉得相比老的 j2ee, Spring/SpringBoot 已经算轻的了, 虽然离云原生的标准还差了不少, 但是毕竟也是有其他优势的, 就是生态好, 工具 /社区丰富, 也隐藏了一些复杂的底层细节, 所谓"笨重"应该不是首要考虑的问题

    此外, Getter/Setter 我觉得是必要的, 如果是真纯数据类型, 已经有 record 类了, 如果要加上一些行为的话, 隐藏在 Getter/Setter 后面是最方便自然的了, 如果只是怕麻烦, 可以用 lombok, 很方便

    IService/ServiceImpl 这个应该是如果是接口的话, 底层就会用 JDK 动态代理实现, 如果是有一个 Service 的话, 用的 CGLIB, 据说性能稍微差一点, 反正我的话, 如果接口有多个实现, 就用接口, 如果只是单个实现, 就不要接口

    你说一个请求要好几层的话, 这个和接口什么的没有关系, 是设计的问题, 要看你的项目架构怎么设计和定义的了, 一般都得分个请求层 /服务层 /数据层之类的, 如果说 3 层都闲多, 要目你的项目太简单是真不需要, 要么就是还没遇到合在一起遇到的麻烦事.

    如果说的是单 Service 层有好几层, 那要看具体情况了, 如果只是单单说是公司规定, 全是模版代码, 我建议如果不能说服老大, 那自己做一个模版代码生成器会方便很多
    secondwtq
        13
    secondwtq  
       2022-05-08 00:35:57 +08:00
    内存占用和 JIT 、AOT 是没关系的,主要是 Tracing GC 的问题。Tracing GC 就意味着任一时刻内存中必然有一部分数据是“无用”的,造成内存空间的“浪费”。
    其他 Tracing GC 的语言也一样,并且 GC 调优有时候还需要用更多的“无用”内存占用换取 GC 更少触发。
    其实不用 Tracing GC 也会有其他问题,比如用了对象池 /内存池。在这些情况下,内核看到的内存占用其实都不能代表应用程序的“真实”内存占用,但是这些“没用”的内存又确确实实被占着。
    techstay
        14
    techstay  
       2022-05-08 01:04:35 +08:00
    getter 和 setter 这属于历史遗留问题,当初不算什么问题,现在各种语言说白了也只是用语法糖包装一下。各种规范也没啥吧,Python 不是也是一堆 PEP
    WebKit
        15
    WebKit  
       2022-05-08 01:11:05 +08:00 via Android
    要不试试 kotlin 的 ktor
    billlee
        17
    billlee  
       2022-05-08 01:49:22 +08:00
    java 的内存问题不单是 tracing gc 带来的占用内存多的问题,还有个更复杂的问题是对象类型的变量是引用,无法嵌套对象。这个不但有内存使用量的开销,还有因为内存布局无法控制可能带来性能损耗。

    有些对内存局部性敏感的算法用 java 写出来就是要比 C++ 慢,有时为了优化性能,必须放弃面向对象的写法,把对象数组改成每个属性拆出来单独存数组, 写出来的代码就和 matlab 差不多。

    拿 C++ 的话来说,就是 java 的面向对象抽象不是零开销的。
    SeaTac
        18
    SeaTac  
       2022-05-08 02:41:16 +08:00 via iPhone
    Getter/setter 这个问题,看看 lombok ?
    pengtdyd
        19
    pengtdyd  
       2022-05-08 03:45:47 +08:00
    那么问题来了,什么是轻?汇编够轻了吧!!!
    muhuan
        20
    muhuan  
       2022-05-08 07:19:25 +08:00 via iPhone
    Macolor21
        21
    Macolor21  
       2022-05-08 09:29:54 +08:00
    虽然 Lombok ,但是 JDK 14 不是新增了 Record 了么?从 Scala 上学来了一些
    angrylid
        22
    angrylid  
       2022-05-08 10:06:22 +08:00 via Android
    1 ,是你自己菜;
    2 ,那你为什么不用 xxx 呢;
    3 ,楼下补充。
    ojh
        23
    ojh  
    OP
       2022-05-08 10:13:26 +08:00
    @angrylid
    1 我承认自己菜
    2 建议看下全部而不是标题的加粗
    angrylid
        24
    angrylid  
       2022-05-08 10:29:01 +08:00 via Android
    @ojh 只是自嘲一下,因为我基本认同你的观点。Java 给我感觉就是过度设计过度抽象,有时将一些简单的事情复杂化。
    kett
        25
    kett  
       2022-05-08 10:31:22 +08:00   ❤️ 2
    我觉得就是因为有这么多规范,才保障了项目整体的可控,虽然啰嗦,但是大家都能看懂,比起灵活多样,循规蹈矩的开发方式更适合团队。
    引用一条以前看过的评论:当你回到一个综合性的大型项目中,你会觉得 Java 积累下来的整个技术体系是如此完善,就像一个工业化标准一样。
    lux182
        26
    lux182  
       2022-05-08 10:51:39 +08:00   ❤️ 1
    java 是面向工程的
    brust
        27
    brust  
       2022-05-08 10:54:47 +08:00
    没有垃圾的语言只有垃圾的工程师
    lisongeee
        28
    lisongeee  
       2022-05-08 10:59:38 +08:00
    我看掘金的一篇文章 https://juejin.cn/post/6844904106545381384 这么写:Lombok 会帮我们自动生成很多代码,但这些代码是在编译期生成的,因此在开发和调试阶段这些代码可能是“丢失的”,这就给调试代码带来了很大的不便。

    另外我有点好奇,我看的 java 代码例子里几乎所有字段都需要手动加 setter 和 getter ,但是多数情况下 java class 只有很小一部分字段或者没有字段的 setter 和 getter 会被重写,所有对于其他字段而言,我为什么总是要生成一堆啥也不干的 setter 和 getter 呢?难道只是为了调用的时候统一风格吗?

    现在 jvm 系列的语言我已经转 kotlin 了,虽然我是个写 ts 的前端 :)
    hingbong
        29
    hingbong  
       2022-05-08 11:13:17 +08:00 via Android
    Java14 不是有 record class 吗
    FreeEx
        30
    FreeEx  
       2022-05-08 11:17:19 +08:00   ❤️ 1
    [一个简单的请求处理分了好几层,写得贼难受]

    下图摘自 《整洁架构之道》

    https://tva4.sinaimg.cn/large/a977d012ly1h20trzmyz7j22c03407wk.jpg
    lisongeee
        31
    lisongeee  
       2022-05-08 11:34:21 +08:00
    还有,Lombok 都已经在编译期间修改代码添加 setter 了,为什么不一步到位把外部调用 obj.key = xxx 也修改成 obj.setKey(xxx) 呢,这样就没必要为所有字段添加 setter 了啊,你不加注解正常访问的时候 obj.key = xxx ,然后加了 Lombok 的注解,就在编译期间转换成 obj.setKey(xxx) ,这不就变相实现了 java 没有的语法层级的 setter 了吗?
    statumer
        32
    statumer  
       2022-05-08 11:41:11 +08:00 via iPhone   ❤️ 4
    用 Spring Web 的 Java er 真没资格和 go/c++碰瓷性能差距,人家都工业界大规模用上 epoll 了,Spring 还在整 one request per thread 和同步阻塞 JDBC 呢,先把自己服务 QPS 提高到人家 go 一半再讲吧。
    更搞笑的是 Spring Webflux 优化太垃圾竟然和 Spring Web QPS 五五开,官方在文档里美其名曰 reactor 和 one thread per request 没有性能差距,只是 reactor 负载方差更小。
    用 vertx 这类异步网络库的 Java er 谈性能我没意见,用 Spring 的还是算了。
    liprais
        33
    liprais  
       2022-05-08 11:43:52 +08:00
    @statumer 访问数据库都是同步的,惊喜不
    sheep3
        34
    sheep3  
       2022-05-08 11:46:05 +08:00
    还是 java 库方便,自动注入啥都不用想
    Cu635
        35
    Cu635  
       2022-05-08 11:51:01 +08:00
    @geekvcn
    “第一点内存占用多,你为什么不用 C++写项目?有人逼着你用 Java 写?”
    还真的是有人“逼”得:公司前人选择了 Java 之后,新接手的时候要么用更好的语言重新写,要么就只能继续用 Java ,公司领导不让重新写的话不就是“逼”得么……
    ragnaroks
        36
    ragnaroks  
       2022-05-08 11:51:06 +08:00
    对于 java 的主要战场后端来说,“笨重”并不是问题,后端都是可水平扩展的,只能说性能差会多用服务器
    yolee599
        37
    yolee599  
       2022-05-08 11:54:06 +08:00 via Android
    但是 java 代码的可读性很高啊,标准化生产
    slert
        38
    slert  
       2022-05-08 11:54:49 +08:00
    确实有些是为了规范而规范,如果是个人项目的话,java 并不阻止你摆脱这些人为的规范。
    seakingii
        39
    seakingii  
       2022-05-08 12:07:00 +08:00
    "笨重"是相对的,和 GO 之类的比,肯定是"笨重"的;比如你要实现一个简单的代理服务,放在路由器上用,你会考虑占几百 M 内存的,还是占十几 M 内存的?

    "笨重"并都都是坏事,如果一个项目很复杂,需要 JAVA 这种"笨重"的玩意.

    每种语言有自己的生存土壤,没必要也不可能一种语言打天下.不是说技术上做不到,是成本太高.比如你不可能用汇编语言写你的企业级业务系统,但可能会在某些热点方法上用点汇编来优化.
    teem
        40
    teem  
       2022-05-08 12:08:18 +08:00   ❤️ 1
    #OP 顺便问一句有什么好 Java Web 框架脱离 Servlet 体系又很瘦小的
    ACTFramework : https://github.com/actframework/actframework
    早年的 Play! Framework 1.x 也是不错的选择
    seakingii
        41
    seakingii  
       2022-05-08 12:10:57 +08:00
    另外 Java 的"笨重"还体现在这门语言的语法上,有时为了实现一个功能要写好多的代码.当然现在 Java 本身也在进化,也越来越简洁化.
    az467
        42
    az467  
       2022-05-08 12:17:20 +08:00
    原因在于 java 流行太早而发展太慢,主流版本(8/11)就是这么烂。

    - 内存占用多
    主要两点原因,一是 java 大量使用堆内存和引用对象,而且没有值类型或者结构体,就算 jit 能优化成栈上分配,最少也多一个对象头,性能和内存占用天生就弱,调 c/c++ 库也很麻烦。
    另一个就是 vm 必须要占用的那一部分,实际上使用到的内存没那么多,但是内存就是被占用掉了,这在云时代更是问题,那都是真金白银呐。
    当然啦,相信这些问题将来会被那一大堆 project XXX/GraalVM/aot 优化甚至解决,但是我用 Java8 。
    - JRE 很大
    这个其实还好,真没啥感觉,云环境也有轻量 base image 可以直接用。
    - 打出来的包很大
    在 springboot 一统天下的如今,框架不是你想换就换的。
    上云的可以试一下 Layered Jar ,多少能缓解一点。
    - Servlet 规范
    纯历史遗留问题。
    - Getter 、Setter
    没早点把 Property 抄过来,你看 Kotlin 就很好。
    - xxxService/xxxServiceImpl
    对业务代码来说,99%的情况下没用,知道是怎么回事然后照本宣科就完事了。

    综上,骂了这么多年了,能改的 java 多少快慢都在改进,但是这都跟 java8 用户没有关系。
    xiaofan305
        43
    xiaofan305  
       2022-05-08 12:22:34 +08:00 via Android
    以牺牲硬件资源来换取某新便利或稳定,在计算机领域太常见了 。加一层,再加一层,再加一层…
    ecloud
        44
    ecloud  
       2022-05-08 12:37:45 +08:00
    node.js 以及依附于之上的什么 angular, vue 那才是又臭又大,但是没办法,纯纯解释性语言,JS 天生有弱鸡,结果诞生出这么一群怪胎
    PS:其实早年 Java 想做的其实就是现在 node.js 干得这些事( Applet )
    ecloud
        45
    ecloud  
       2022-05-08 12:43:28 +08:00
    @billlee 天下没有免费的午餐,任何抽象都不是零开销的,C++不是,其他任何编译型的 OO 语言也不是。冯诺伊曼体系本质上就是内存跟 CPU 跳二人转,一个人想清闲那就必须把任务加到另一个人身上,没有白捡的。Java 天生缺陷不是 OO 问题,而是他的虚拟机体系。人家本来天生就不是想用来做大型程序的,OO 特性只是附加的东西。Java 原始设计目的真正的精神续作其实是安卓
    ojh
        46
    ojh  
    OP
       2022-05-08 12:44:06 +08:00
    @statumer Spring Webflux + Spring Data R2DBC 又会如何呢,本人没用过 Spring Data R2DBC ,Java 的响应式编程要写异步代码这块真的不容易 。不过 Java19 已经 preview loom (希望 Value Object 也可以)了,但是这个让主流框架适配不知道猴年马月
    yedra
        47
    yedra  
       2022-05-08 12:54:23 +08:00
    @geekvcn 别人好歹是在求教,你在干什么
    chocotan
        48
    chocotan  
       2022-05-08 13:55:57 +08:00   ❤️ 2
    我本来也打了一堆,最后还是删掉了,感觉国内很多人的认知还是停留在好多年前
    ------
    说说我自己的使用情况吧,我最近在自己搭建一些工具,用了不少其他语言的应用,它们的大小也不小,某些极品应用能直接把服务器内存给干爆( oom killer ),最后我不得不用 java 自己写了个
    Lancer777
        49
    Lancer777  
       2022-05-08 14:14:13 +08:00   ❤️ 1
    其实说难听点就是大部分程序员还是脚本小子,有没有规范,有没有团队协作都是不重要的,自己开心就好。还有吹 Go 生态的,Go 社区现在做的事情不就是把 Java 做的事情重新做一遍吗?有啥区别?如果多看点架构设计、软件工程的书,就能明白 Java 这叫高度工程化,绝对算不上笨重和臃肿,难道建摩天大楼的地基和楼体支撑也叫笨重和臃肿吗?
    chihiro2014
        50
    chihiro2014  
       2022-05-08 14:16:50 +08:00
    模块化可以省掉很多没必要的东西
    fengjianxinghun
        51
    fengjianxinghun  
       2022-05-08 14:20:25 +08:00
    反正一个应用要是 java 写的,我直觉上就会找个其他 c/c++/rust/go 的替代品,除非别无选择
    nl101531
        52
    nl101531  
       2022-05-08 14:23:14 +08:00 via iPhone
    这种算是遗留下来的习惯式规范,不过有了 lombok 也还好了。 自己的项目可以使用充血模型体验不一样的开发乐趣,公司的项目还是按照大家都习惯的方式来,沟通成本小了很多,其实规范多不一定是坏事。
    ojh
        53
    ojh  
    OP
       2022-05-08 14:29:14 +08:00
    @Lancer777 你说的规范、团队协作、工程化有道理,虽然 Java 搞这么多的规范分这么多层看上去很啰嗦,但是可以让能力经验参差不齐的人写的代码都保持一定的统一,利于团队合作和代码维护
    iseki
        54
    iseki  
       2022-05-08 14:35:57 +08:00
    setter & getter 是 Java 没有 property 导致的,<del>就像 Go 一样,写编译器的省事了,程序员就费事了</del>,直接暴露 field 是不合适的。
    zhouzm
        55
    zhouzm  
       2022-05-08 16:39:28 +08:00   ❤️ 3
    唉,现在很多人已经丧失了,认真阅读理解别人的文字,以及好好说话这两种能力。
    msg7086
        56
    msg7086  
       2022-05-08 17:00:55 +08:00   ❤️ 1
    关于 Java 笨重,过度设计,Getter/Setter 这些,我简单说一些。

    Getter/Setter ,有一个原因是向前兼容性。
    没有逻辑在里面,不代表永远没有逻辑在里面。
    如果你暴露一个 public 的字段,那么你暴露的就是一个数据,而操作这个数据的代码,在第三方。换句话说,你的类对你的数据将失去控制能力,任由第三方来读写。数据和操作数据的代码就割裂开来了。
    而 Getter/Setter 则是方法,或者说代码,你对内部的数据有最终操作权,而别人只能调用你提供的方法。如果有朝一日这个数据被改变了,被废弃了,或者业务逻辑被加强了,那么你不需要跑到几十个办公室找几十个团队的人抓着他们跟着你改代码。

    过度设计也是基于这个准则。假设地球上有一万个中型或者大型项目,并且每个项目都有几十个工程师在工作,每个项目都需要不同的组件来互相搭配,如果不做成接口,不解耦组件,那得浪费多少工程师的时间?

    当你用 Java 的时候,你就要把自己摆正到正确的位置上。这是一个更适合大型企业的语言和框架环境,方便几百几千个工程师在一起协作开发,方便让各种能力水平的人都聚到一起工作。有多少语言和框架能做到这样的?不多吧。

    我给公司做团队项目,那肯定是用 Java 的。但是我要是自己写项目,或者和志同道合的人一起写,我肯定选择写 Ruby 。三个人的团队写 Java 会很不舒服,三十人的团队写 Ruby 也会很不舒服。不同的语言有不同的特长。
    lanlanye
        57
    lanlanye  
       2022-05-08 17:36:00 +08:00
    在我这个没写过 Java 项目的外行看来,面向接口编程应该是没什么问题的,准确来说是面向抽象编程,但并不是所有东西都需要抽象,以“考虑未来 /拓展”为理由产生的过度抽象是应该避免的。

    关于 Getter/Setter:同 56 楼,是面向对象保持封装性的一部分,但是我个人认为如果你开发的是一个类似 Spring 这样需要一步步发展完善的大型工程项目,那封装是很重要的,反之如果只是写简单的业务逻辑,以后很可能整个 Model 都推翻重来,也不会有人在你这个项目之上再去拓展(感觉一般的 Web 项目模型都不会再作为其他项目的基础了),那么对于不需要限制修改的属性,完全可以写成 public 的。

    其他内存问题我不了解,不过直觉多一个 JVM ,不管怎么都不可能和直接在对应平台上编译效果一样吧。
    codingadog
        58
    codingadog  
       2022-05-08 18:02:28 +08:00
    世界上只有两种语言:没人用的语言,和被人喷的语言(手动 doge
    DOLLOR
        59
    DOLLOR  
       2022-05-08 18:19:57 +08:00
    我想起之前接手的一个小程序项目,一看就是 java 背景的人写的。因为代码里面出现了大量为了 OO 而强行 OO 的风格。
    比如一个 request 请求,传统的 JS 、TS 开发者会把 wx.request 再套一层 async 函数封装就完事了。而他非要用几个 class 套个里三次外三层,结果是每个页面还要把这几个 class Req 再实例化一遍😂。
    dcsuibian
        60
    dcsuibian  
       2022-05-08 18:33:36 +08:00
    本命 Java 。
    要是写脚本,Java 那肯定是比不上 Nodejs 、Python 这种动态语言的,写起来真的轻松很多。但要是写服务器上正经的应用,那 Java 属实是强的一批。
    1 、就资源占用问题来说,带了 vm 肯定比不上 C 和 C++这种,不适合低性能、低功耗的设备。但 vm 的好处也很大,平台无关性、自动内存管理等等,最主要是省了程序员开发的时间(很值钱的)。(我写过 C 和 C++,内存管理确实不是一件很省心的事)
    以前 Java 的 web 程序是打成 war 包放在 Tomcat 里,现在则是直接和 Tomcat 融合成一个 jar 。近年来还出现了各种容器化、虚拟化技术。大厂在资源占用和开发效率中的选择已经很明显了。同时 jvm 极其优秀,虽然资源占用大了点,但性能也不算差,支持多线程,在带 vm 的语言里就是 top class 。

    我认为 Java 作为一种偏高级的语言其实在资源、性能、开发效率上做到了一种相当好的平衡。

    2 、JRE 很大这个我也觉得很迷惑。搞得好像 js 和 python 不用运行时一样的。.net 倒是好搞,操作系统带了,但非 windows 就比较尴尬。
    dcsuibian
        61
    dcsuibian  
       2022-05-08 19:00:04 +08:00
    3 、xml 配置复杂的问题确实存在,不过已经基本上是过去式了,主要是老项目。真要对比也得比比同时代的,Java xml 满天飞时,其它语言又是怎么做应用的。要不然拿过去比现在属实不公平。

    至于规范来说,我感觉不是什么问题。毕竟软件设计 7 大原则摆在那里,都有章可循。而且现在大家做 web 基本已经形成了一种统一的模板、最佳实践,实际上是好事,减少沟通成本。

    当然能打 Java 的语言也是有的,C#就是。不过成也微软、败也微软
    geekvcn
        62
    geekvcn  
       2022-05-08 19:44:59 +08:00
    我发现很多 Java 培训班的可能连 GraalVM 都不知道,如果他们知道的话他们口中很多 Java 的原罪根本就不成立,比如给朋友发个小工具还要发个运行时过去
    l00t
        63
    l00t  
       2022-05-08 20:21:34 +08:00
    @msg7086 你这个说法是想得很美,但实际并没什么卵用。想象中我改一下内部逻辑,保持接口不变,别人调用者就不用改。但实际上呢?你要是返回数据都不改那约等于没改,你要是返回数据改了,而人家调用者就是基于你的数据来写逻辑的呢? getID(), 开始是返回一个不会重复的 ID ,后来改成返回一个会重复的 ID ,你接口形式是没变哦,但这样的改动不得通知一下所有调用者吗?
    fisherwei
        64
    fisherwei  
       2022-05-08 20:35:38 +08:00
    从运维的视角看,java 最“重”的是 jar 这个东西。

    CI/CD 上,java 的项目哪怕只改变一行代码,maven 出来也是一个发生了变化的 jar 文件,然而这个 jar 几乎占用一个 docker 镜像 90%以上的容量(剩下的是 jre ),导致 jar 项目 registry 总是增长的很快,也占用很多带宽。

    虽然,磁盘和带宽都不缺,也不值钱。只是看起来很不爽。
    thetbw
        65
    thetbw  
       2022-05-08 20:46:43 +08:00
    推荐一个 kotlin 和 ktor 这个 web 框架,基本上脱离了好多 java 这些老旧的东西,不过生产环境应该很少有用的,我机子写着玩玩会用,orm 工具可以使用 ebean
    night98
        66
    night98  
       2022-05-08 21:28:31 +08:00
    @l00t 他的意思是比如你调用方法变更数据,现在是没有逻辑,后面比如对某几个字段需要加一个数据追踪,他直接在方法里面加逻辑就行了,你如果直接调的话就没办法这样子操作了。


    @fisherwei 分层 jar 了解一下,springboot2.3 开始支持,google 的 jib 也有类似的功能,把不可变的分到上层,实际逻辑代码部分在最下层,大部分情况下都能实现秒级推送
    gongquanlin
        67
    gongquanlin  
       2022-05-08 21:32:23 +08:00
    以前写 php 的时候简单逻辑深知直接扔到了 controller 里爽的很;
    后来换了 java ,数据库改个字段,又要改 mapper.java ,又要改 mapper.xml ,又要改 domain ,如果有继承还得改 dto 、vo……麻烦的很
    而且一个增删改查,又得写 service ,又得写 serviceImpl ,恶心的很

    后来公司业务有多个下游请求,用到了策略工厂,用到了责任链,理解为啥一个 service 要写一个 impl ,发现存在就是合理

    只能说 java 轮子又多,各种厂商对 java 的 sdk 支持又好,写业务逻辑速度很快,crud 用代码生成器效率也很高,性能比 php 好一些,部署又方便,小业务确实香

    但是写 go 的时候,除了需要 cgo 的,写完之后直接 linux/windows 编译爽的很

    但是吐槽一把 go 的 err 处理,要是能和 php/java 一样有统一的异常管理就好了,还得一个一个的处理 err
    abcbuzhiming
        68
    abcbuzhiming  
       2022-05-08 21:47:00 +08:00
    @brust 这句话立场就不对,要知道现代编程语言的发展就是为了把很多过去认为能力不够的人拉进来编程,降低编程的门槛,如果说没有垃圾的语言只有垃圾的工程师?那以当年人月神话那会的人看现在的,在座各位都是垃圾工程师——就问有几个人敢说自己能拿打孔纸带编程的?


    @Lancer777 有一说一,JVM 因为历史包袱原因,在内存使用上确实比不上新出的那些语言,否则 Oracle 也不会在那折腾 GraalVM ,现在确实是本地二进制文件的时代,中间字节码是上个时代的东西。当然,比工程化目前 java 生态圈是无敌的,这也是我为啥对转移到 Go 总是有所犹豫,还想继续观望一下 GraalVM 的原因。

    @geekvcn GraalVM 目前还处于试验中,没到大规模应用的程度,其实我也馋这个,本地二进制实在太香了。就怕 Oracle 这个逼将来不愿意把这玩意给 OpenJDK ,搞收费商业化那就。。。
    eason1874
        69
    eason1874  
       2022-05-08 21:49:29 +08:00   ❤️ 2
    Java 开发偏工程化,有特定流程要遵守,所以感觉是重量级编程

    Python 、Javascript 、PHP 这类偏脚本,自由度大,野路子多,一个文件都能跑起来,感觉就比较轻。如果也按工程标准开发,比如用框架开发,这些语言其实也不轻
    wg20080215
        70
    wg20080215  
       2022-05-08 22:16:46 +08:00
    Quarkus 是一种 Java 框架,对比的应该是 SpringBoot 、Vert.x 之类的,拿来和 Java 对比是不太恰当的;另外 AOT 和 JIT 都有自己的应用场景,当下主流的云原生架构在高负载时讲究的是集群弹性,而不是单节点死扛,脱离应用场景,单点能力的对比意义不大哦。

    Quarkus 的优势是和 GraalVM 的集成度很高,如果对 JPA ( Hibernate )习惯的话,用 Quarkus 可以无缝从标准 JVM 切换到 GraalVM 来获取 GraalVM 的优秀特性。

    推荐视频: https://www.bilibili.com/video/BV1Cb4y1X7Rd
    cheng6563
        71
    cheng6563  
       2022-05-08 22:50:35 +08:00
    Java 就是典型的功能我有,但设计的非常脑残。

    不支持字符串内直接引用变量,只能自己实现,导致 log4j2 神奇漏洞。
    泛型拉稀导致反序列化操作非常魔法,日常增加漏洞。
    日期 API 也是一坨,现在我宁愿用 DataUtil 直接操作 Date 也不想用 LocalDateTime
    Future 设计拉稀,Future 甚至没有执行完毕的 Callback 。基本每个异步框架都有自己设计的“Future”,间接导致 Java 的协程难产。
    不支持多行字符串导致一些操作硬是要搞成模板引擎( mybatis )。

    至于为了 OO 而 OO ,这是工程化带来的负面效果。但是 Getter ,Setter 依然很蠢。
    Servlet 和 JDBC 是纯历史遗留问题,但其实也不算啥问题。
    Maven 的版本稳定性秒飞那些直接用 github 当依赖仓库的包管理器。
    lesismal
        72
    lesismal  
       2022-05-08 22:57:16 +08:00
    @abcbuzhiming
    比如农村里上茅草坑习惯了,后来进城里发现有智能马桶,很是高大上。
    GraalVM 就相当于智能马桶。但即便智能马桶,它也还是屎屎相关。

    go 可能像是在餐厅里吃饭,餐厅也是修得晚、软装还没完善,经常让小白们感觉斯是陋室,但这里的东西都是可以下咽的。
    12101111
        73
    12101111  
       2022-05-08 23:21:19 +08:00
    别的不提, 就算在别的变成语言中, 要想实现运行时多态, getter setter 即使没有逻辑也得有这个函数, C++的 virtual class 和 Rust 的 dyn trait 也是没法多态的时候访问字段的, C#可以用语法糖但本质上还是函数. 除非像 Javascript 或者 Python 一样把对象的字段做成字符串为 key 的 map(不过这样性能更差)
    说白了 java 的笨重就体现在滥用运行时多态上, 像 C++ Rust 都是编译时多态, 很多东西都能先实例化再内联然后就优化掉了,Java 再 jit 也没法把类型已经擦除掉类型的对象的函数内联优化掉
    我读过不少 chromium 的代码, 写的跟 java 一样罗嗦,但是调试的时候发现代码几乎都是 inline 的, 带上调试符号, 汇编也很难和代码对的上, jvm 再厉害也不可能做成这样
    不过 v8 的 gc 也不比 jvm 厉害, 所以内存占用也不小, 但是运行速度比 jvm 快多了. chromium 这好几千万行的项目要是 java 写的, 恐怕就没有现在前端那一堆东西了, 浏览器能慢成牛
    FrankHB
        74
    FrankHB  
       2022-05-08 23:25:57 +08:00
    有个这里都没提的:冷启动性能。
    一般人会遇到的竞品里怕是没有一个是能比 Java 的实现更加卡翔的。这直接导致拿 Java 写单进程小工具看起来就是没事找抽,直接自绝于一大坨应用领域。

    @msg7086 @lanlanye 大部分人眼中的 getter/setter 的问题和提到的没多少关系。很多用户吐槽 Java 这里垃圾,是因为他们想要类似 C#的 property 代替,而 Java 愣是不给。不管用不用 property 代替,都不影响你们这里提的东西。
    基于一些深层次的理论问题,我不认为 Java 这里的设计是错的,也不是只有 Java 这样(至少 C++也不给什么劳什子 property 面子)。(具体一点,即便不考虑η-equivalence 这样的异端,这种基于标识符的语法变换缺乏 hygiene 而最终导致语法扩展无法从源码直接推理就够眼烦的了。)不过 Java 这种连 macro 都没的八辈子都别想 call by name 的语言自然就不用纠结这么多,糊 JLS 跟 JEP 的那些大概人也许只是觉得让这种雕虫小技还不如 IDE 帮忙糊代码愉悦罢了。
    至于为什么非得 getter/setter 而不是直接拿字段代替,这很大程度上就是用户之间的内部矛盾。
    dqzcwxb
        75
    dqzcwxb  
       2022-05-08 23:44:08 +08:00
    @eason1874 #69 很多人就是把工程化的毛病硬套给语言,搞的好像别的语言工程化之后就没有这样的毛病一样
    没有理解为什么需要这样做只是单纯的觉得这样做麻烦繁琐老旧,这种不是在创新而是反智
    dqzcwxb
        76
    dqzcwxb  
       2022-05-08 23:59:55 +08:00
    @chocotan #48 通篇看下来,大部人的对 java 的认知还停留在 2013 年的 java8 甚至这里还有一些停留在 java8 以前
    能够了解 java8 有什么更是少之又少 stream lambda optional localdatetime completablefuture 等等更是完全不懂
    后面还有 java11 的 zgc 13 的文本块 14 的 instanceof 等等等等他们更别提能够了解十之一二

    在这里给各位通知一下,最新的 jdk 版本是 2022/03/22 发布的 jdk18,而下一个 jdk19 版本正在开发中目前预告的特性中包含协程,请大家务必跟上新时代不要做旧时代守门人
    Lancer777
        77
    Lancer777  
       2022-05-09 00:29:18 +08:00
    @abcbuzhiming GraalVM 我已经在生产环境上使用了很久了,并没有什么太大问题,主要问题还是在于 Java 生态圈对于这玩意的支持还是太慢了,Quarkus 的上手成本太高,Spring Native 出来的太晚,并且编译速度太慢,还是要等一段时间才能愉快的使用。
    Lancer777
        78
    Lancer777  
       2022-05-09 00:32:29 +08:00
    @cheng6563 Java8 的时间类可是借鉴 JODA Time 的,你说设计的一坨?还有多行字符串在新版的 JDK 已经支持了,get ,set 在 OO 语言里面可不是 Java 独有,.net 也是这么写的。协程马上就来了,还有 4 个月,预计 21 就可以出稳定版啊。
    msg7086
        79
    msg7086  
       2022-05-09 02:21:18 +08:00 via Android
    @dqzcwxb 笑死,我们团队刚刚升级到 JDK8 ,之前一大堆项目都在 7 ,还在龟速移植中。上个月刚接手一个 JDK1.6 上来的项目,连泛型都几乎没有,那叫一个酸爽。不知道等我退休的时候能不能用上 17 。(摊手
    cheng6563
        80
    cheng6563  
       2022-05-09 10:47:50 +08:00
    @FrankHB 冷启动问题就是 jar 包设计的太蠢了,Android 上的 dex 包就没这问题。
    @Lancer777 LocalDateTime 和 Date 的转换蠢到家了,甚至 java.util.Datejava.sql.Date 也不完美兼容。导致每个项目都要写个 DateUtils ,我还不如直接统一用 DateUtils 操作 Date 了。
    abcbuzhiming
        81
    abcbuzhiming  
       2022-05-09 10:58:16 +08:00
    @Lancer777 你看你自己也说了,java 生态圈对这东西的支持力度远远不够,这不就是我说的暂时还没办法大规模的上吗?还有一个问题是,oracle 到底怎么看这个东西的,以后是打算商业收费吗?
    sky857412
        82
    sky857412  
       2022-05-09 12:05:13 +08:00
    1.servlet 是历史问题
    2.使用 get ,set ,你可以在 get set 里面写逻辑呀,只是一般不用,比如类型转换。同时方法调用,可以方便 IDE 进行查找,可以知道在代码哪些地方对属性进行了修改,如果单纯的 public ,你需要进行全局搜索。get 、set 也体现了面向对象的封装性
    3.xxxService/xxxServiceImpl ,在自己的业务逻辑是可用可无的,但是对接第三方系统时是很有用的。假设系统今天对接阿里云的短信,明天对接 XXX 的短信,可以通过不同的实现类去处理。
    sky857412
        83
    sky857412  
       2022-05-09 12:16:15 +08:00
    @l00t 什么叫返回数据不改约等于没改? 2 个实现类,都是给调第三方发短信,都是返回成功。这能叫没改?你无法理解,不要乱误导人。第二个,getID ,明明有很多方法避免,你却非要强调你错误的观念。方法重载,不改 getID ,重新写一个方法,叫一个新的方法名都可以解决歧义。编程是变通的,又不是只有一个正确答案
    AmberMmoe
        84
    AmberMmoe  
       2022-05-09 13:59:10 +08:00
    java 小白,当年学的时候,单是环境就要了我半条命
    yedanten
        85
    yedanten  
       2022-05-09 14:04:36 +08:00 via Android
    工作原因写 java 必定和那些规范扯上关系,是真的被逼着的,即使知道这个项目不太可能有改动,即使知道这个项目可能活不久。大家都按这规范写,过度的抽象怎么了,问就是为了未来那 1%可能性的可拓展性。
    个人项目不用管,怎么开心怎么写,那我还选 java 干嘛。
    fredli
        86
    fredli  
       2022-05-09 14:51:45 +08:00
    学 kotlin 吧,函数式就是方向
    yangxj96
        87
    yangxj96  
       2022-05-09 16:35:51 +08:00
    规范多, 所以培训班出来的人也能快速上手. 简称 CV 大师
    icanbeyrhero
        88
    icanbeyrhero  
       2022-05-10 00:18:54 +08:00 via iPhone
    @fisherwei 考虑使用 alpine jdk 镜像,缩小体积
    drackzy
        89
    drackzy  
       2022-05-10 06:14:03 +08:00
    Rust 、Golang 没有运行时会慢慢侵占一些之前 JAVA 应用的地盘。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5471 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 40ms · UTC 06:53 · PVG 14:53 · LAX 22:53 · JFK 01:53
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.