此文乃「Java开发者AI入门」专栏的第3篇, 在阅读之前请先阅读前两篇, 第1篇是写给Java开发者的AI入门地图, 第2篇是 加上Java, 使得AI能够替你进行劳务工作。

一、为什么学 AI 绕不开 ?

先说一个让很多 Java 开发者不太舒服的事实:

截止到当前这个时候, 人工智能领域超过百分之九十的教程, 以及框架, 还有论文配套代码, 以及开源项目等等, 全都是这样的。

它并非, 相较于Java更为优越——没错, 于这片工程领域之内, 这可是一场永不停歇之口水大战, 不存在所谓标准答案。然而那AI之生态现状实实在在呈现于此态势:

你能够用Java去做AI吗, 毋庸置疑能够, DJL以及AI都处于飞速发展之中, 然而若你期望迅速领会一个AI模型究竟是怎样运行起来的, 能够读懂他人所编写的代码, 并且跟得上社区发展的节奏, 那么它是无法被绕过的工具。

换个角度去思考,并非是要去取代Java, 而是在你的工具箱之中, 增添了一把螺丝刀, 在进行企业后端开发时, 你依旧能够使用Boot, 在需要调整模型参数的时候, 将其打开就可以了。

心态放平:这不是"背叛",是"进化"。

配图1: 有一张那种做成可作左右对比方式呈现的概念图, 而处在左侧的内容呢是和Java开发者相关的所谓“舒适区”, 其中包含Boot以及Maven , 至于右侧部分呈现的则是被视为AI世界的“通行证”的内容, 这里边有pip , 在左侧和右侧之间有一座桥把它们连接起来, 并且桥上写着“7天速成”字样, 其整体风格呈现出简洁扁平化的特点, 在色调方面偏向蓝绿色这种带有科技感的色调。

二、Java vs 核心语法对比

而后的内容, 我会采用“左边 Java, 右边 ”这样的形式来展示。待看完这一节内容, 你便能够对 形成一个全景方面的认知。

2.1 变量与类型

特性

Java

变量声明

name = "张三";

name = "张三"

类型检查

静态类型,编译期检查

动态类型,运行时检查

类型声明

必须声明类型(或用 var 推断)

不需要声明类型

常量

final int MAX = 100;

MAX = 100(约定大写,语言层面无限制)

空值

null

None

多行字符串

"""..."""(Java 15+)或拼接

"""..."""(原生支持)

Java:

int age = 28;
String name = "李四";
boolean isSenior = age >= 30;
final double PI = 3.14159;

age = 28
name = "李四"
is_senior = age >= 30
PI = 3.14159  # 约定常量大写,但不强制

Java开发者的第一感觉是, 这语法也太随意了。没错, 其哲学是约定优于配置。没有了类型声明, 缺了分号, 少了大括号, 代码的确短了不少, 可这也意味着IDE能帮着检查的内容变少了, 这依靠的是开发者自律以及完善的测试。

2.2 控制流

条件判断:

// Java
if (score >= 90) {
    System.out.println("优秀");
} else if (score >= 60) {
    System.out.println("及格");
} else {
    System.out.println("不及格");
}
# Python — 注意冒号和缩进
if score >= 90:
    print("优秀")
elif score >= 60:
    print("及格")
else:
    print("不及格")

循环:

// Java - for 循环
for (int i = 0; i < 10; i++) {
    System.out.println(i);
}
// Java - 增强 for
for (String item : list) {
    System.out.println(item);
}
# Python - for 循环(没有传统三段式)
for i in range(10):
    print(i)
# Python - 迭代
for item in my_list:
    print(item)
# Python - while
while count < 10:
    print(count)
    count += 1

关键区别在于, 不存在那种经典三段式循环, 即没有 for (int i = 0;...) 这样的形式。range() 可是你最好的朋友, range(10) 会进行生成, range(1, 10) 会进行类似效果的生成, range(0, 10, 2) 同样会进行生成。

0, 2, 4, 6, 8

2.3 函数与类

函数:

// Java
public int add(int a, int b) {
    return a + b;
}
// Java - 方法重载
public double add(double a, double b) {
    return a + b;
}
# Python
def add(a, b):
    return a + b
# Python 不需要重载——动态类型天然支持
# add(1, 2) → 3
# add(1.5, 2.5) → 4.0

类:

// Java
public class User {
    private String name;
    private int age;
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getGreeting() {
        return "你好,我是" + name;
    }
}
# Python
class User:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def get_greeting(self):
        return f"你好,我是{name}"

作为对比要点, 其中的 self 等同于 Java 的 this, 然而它必须要十分明确地书写于参数列表当中, 这恰恰就是众多的 Java 开发者最初时期最难以习惯的所在之处。

2.4 数据结构对照表

Java

核心区别

list

list 可以混合类型:

1, "hello", True

dict

词典显得更为简约: , “name”对应的是名为张三, “age”所对应的数值是28。

set

用法几乎一致:{1, 2, 3}

int /

NumPy

AI 场景必用 NumPy,原生 list 性能不够

list / tuple

tuple 是不可变列表,类似于加了 final 的数组

实用操作对比:

// Java - ArrayList 操作
List names = new ArrayList<>();
names.add("张三");
names.add("李四");
names.get(0);           // "张三"
names.size();           // 2
names.remove(0);        // 删除第一个
for (String n : names) { System.out.println(n); }
# Python - list 操作
names = []
names.append("张三")
names.append("李四")
names[0]                 # "张三"
len(names)               # 2
names.pop(0)             # 删除第一个
for n in names: print(n)
# 列表推导式——Python 的杀手级特性
squares = [x**2 for x in range(10)]
# 相当于 Java 的 IntStream.range(0, 10).map(x -> x*x).boxed().collect(Collectors.toList())
# 但写起来只有一行
// Java - HashMap 操作
Map scores = new HashMap<>();
scores.put("张三", 95);
scores.get("张三");       // 95
scores.containsKey("张三"); // true
scores.keySet();
scores.values();
# Python - dict 操作
scores = {}
scores["张三"] = 95
scores["张三"]            # 95
"张三" in scores          # true(Java 是 containsKey,Python 直接用 in)
scores.keys()
scores.values()
# 字典推导式
{k: v for k, v in scores.items() if v > 60}

2.5 包管理:Maven vs pip

Maven

pip

说明

pom.xml

.txt

依赖声明文件

mvn clean

pip -r .txt

安装依赖

~/.m2//

site-/

本地缓存

标签

一行一个包名

声明方式

版本

==1.2.3 / package>=1.0

版本管理

无(全局仓库)

-m venv(虚拟环境)

独有概念

Maven:


    org.apache.commons
    commons-lang3
    3.14.0

pip .txt:

numpy==1.26.4
pandas==2.2.1
scikit-learn==1.4.0

Java开发者学习Python入门_Python与Java在AI领域的对比_Python poetry

最大的区别在于, Java项目具有天然的隔离性, 每个项目使用各自特定的, 其默认情况下是进行全局安装。所以, 你务必使用虚拟环境, 也就是venv, 不然不同项目的依赖版本会产生相互冲突的情况, 这一点在第3节所提到的“坑”中会有详细阐述, 切记, 注意。

三、Java 开发者学 的 5 个"坑"

这部分属于实战方面的经验, 每一处坑都是众多Java领域资深者淌过的饱含痛苦与教训的泪水, 以及挥洒过的汗水所汇聚而成的。

坑 1:缩进即语法——没有了大括号,缩进就是一切

这堪称最大的“特色”, 并且是Java开发者极易踏入的坑。

于Java之中, 那缩进算的仅仅是风格方面的事儿, 编译器可压根就不在意。但, 它们是不一样的, 缩进乃是语法的其中一部分, 要是缩进出现错误, 会直接给出语法错误的提示吖。

def process(data):
    for item in data:
        if item > 0:
            print("正数")
        else:
            print("非正数")
    # ← 这一行和 def 对齐,说明 for 循环结束了
    return len(data)

有这样一个真实踩坑的场景情况: 呢, 我呀曾经把一个从 Stack所复制得到的代码片段粘贴进项目里头, 然而呢结果运行的时候出现报错现象, 然后呢排查花费了20分钟的时间得以发现, 发现那个代码里混合了Tab和空格, 并且呢十分严格地要去禁止混用, 可惜的是Java对于此情况完全没有任何感觉, 是这样的情况。

避坑指南:

坑 2:可变与不可变类型的陷阱

的可变/不可变设计比 Java 更隐蔽:

致命场景:默认参数的可变性

#  错误示范——几乎所有 Python 新手都会踩
def add_item(item, items=[]):
    items.append(item)
    return items
print(add_item("a"))  # ['a']
print(add_item("b"))  # ['a', 'b']  ← 卧槽?!为什么还有 'a'?

原因在于, 其默认参数在函数进行定义这个行为的时候仅仅会计算单次, 所以说items =这种情况之下是一个具备共享性质的可变列表, 每一次对函数展开调用的时候都会朝着同一个列表当中去追加内容。

#  正确写法
def add_item(item, items=None):
    if items is None:
        items = []
    items.append(item)
    return items

在Java里头, List items = new ()每一回创建新对象, 不存在这般问题, 这便是"动态类型 + 默认参数" 组合所带来的隐蔽性隐患。

坑 3:不是构造函数

对于Java开发者而言, 当看到的时候, 其第一反应会是“这就是构造函数”——然而, 这并不全然是。

class User:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def __new__(cls, name, age):
        # 这才是真正的"构造函数"——负责创建对象
        instance = super().__new__(cls)
        return instance

关键区别:

Java 对比:

// Java 的构造函数,同时做了创建和初始化
public User(String name, int age) {
    this.name = name;  // 初始化
    this.age = age;    // 初始化
    // 创建由 JVM 自动完成,你感知不到
}

坑 4:GIL—— 的"多线程枷锁"

Java开发者, 对于new ()、线程池、并发包已然习惯, 然而到了之后, 却发觉:

存在有多线程, 可它受到来自 GIL(也就是全局解释器锁)的限制, 在同一时刻之时, 仅有一个线程处于正在执行字节码的状态。

// Java - 真正的并行
ExecutorService pool = Executors.newFixedThreadPool(4);
pool.submit(() -> heavyComputation());
pool.submit(() -> anotherComputation());
// 两个线程真的在同时跑
# Python - 多线程无法实现真正的并行(CPU 密集型任务)
import threading
t1 = threading.Thread(target=heavy_computation)
t2 = threading.Thread(target=another_computation)
t1.start()
t2.start()
# 由于 GIL,实际还是交替执行,不是真正并行

那怎么办?

有个好消息, 在AI开发期间, 你所主要运用的是NumPy等这类库, 它们的计算事实上是于C/C++层面进行并行的, 因而GIL对你实际产生的影响比分外低得多。

坑 5:虚拟环境(venv)—— 的"项目隔离器"

这是 Java 开发者最缺乏直觉的概念。

Java的范畴内, 各个项目具备自身独有的, Maven/会将一切妥善处理。然而, 默认把全个都封装至全局site-, 这般意味着:

# 项目 A 需要 numpy==1.24
pip install numpy==1.24
# 项目 B 需要 numpy==2.0
pip install numpy==2.0
#  项目 A 炸了——numpy 被覆盖了

解决方案:虚拟环境

# 创建虚拟环境(每个项目一次)
python -m venv myenv
# 激活
source myenv/bin/activate    # macOS/Linux
myenv\Scripts\activate       # Windows
# 现在安装的包都在 myenv 里,不影响全局
pip install numpy==1.24
# 退出虚拟环境
deactivate

类比理解:

避坑指南:

四、7 天学习计划

这份计划是专门给那种, 有着Java经验, 然而AI方面从零开始的开发者所设计的。每天花费2到3个小时 , 7天之后你能够读懂大部分的AI代码 , 并且可以独立地让一个机器学习项目成功运行起来。

这是配图2, 它呈现的是一张时间线图, 横轴所表示的期限为7天内情形, 每一天分别都有主题以及产出内容加以注明。其中, 从Day1至Day2用的是“语法”对应的色块, Day3到Day4采用的是“数据处理”相关的色块, Day5对应的是“建模”这个色块, Day6至Day7则是使用的“实战”这一色块。而且在其底部对每天都进行了预估时间安排, 整体风格类似于甘特图那样, 属于扁平化的设计样式。

第1天至第2天: 基础语法加上数据结构, (每一天的时长为2小时)总共四小时。

目标: 能写出基本的 脚本,不依赖搜索引擎完成日常操作。

Day 1 任务清单:

Day 2 任务清单:

推荐的资源是, 官方教程的第4章到第9章, 对于Java开发者而言, 跳着看就可以, 并非需要, 从“什么是变量”开始进行学习。

第三天至第四天: 网络货币点数增加, (每天时长为两个半小时, 总计五个小时)。

目的在于, 去掌握, AI 数据处理的, 基本工具。这属于, 学习 AI, 最为重要的, 两步。

Day 3:NumPy(科学计算基础)

import numpy as np
# Java 开发者思维:这就像一个 int[][] 但支持向量化运算
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])
c = a @ b  # 矩阵乘法,一行搞定
# Java 里你要写双重循环……

Day 4:(数据分析神器)

import pandas as pd
# 这玩意儿对 Java 开发者来说就像一个超级增强版 HashMap
df = pd.read_csv("employees.csv")
seniors = df[df['age'] >= 30]                    # 筛选
avg_salary = df.groupby('department')['salary'].mean()  # 分组聚合

Java进行对比, 要是你曾于Java当中干过类似的操作, 大约是需要API加上自行去封装统计逻辑的, 其代码量是那般的5至10倍。

Day 5:用 -learn 跑第一个模型(3 小时)

目的是, 从头到尾完整地实现完成一个机器学习项目, 这个过程包括从数据进行加载开始, 最终到对模型展开评估。

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
# 加载数据(相当于读取一个内置的 CSV)
iris = load_iris()
X_train, X_test, y_train, y_test = train_test_split(
    iris.data, iris.target, test_size=0.2
)
# 训练模型(就 3 行代码!)
model = RandomForestClassifier(n_estimators=100)
model.fit(X_train, y_train)
# 评估
predictions = model.predict(X_test)
print(f"准确率: {accuracy_score(y_test, predictions):.2%}")

彼时, 身为Java开发者的人, 心中生出诸多感叹, 在Java这个范畴之内, 若要运行同样一种事物, 所需编写的代码数量竟达到了10倍之多, 究竟为何会这般情形呢? 这并非是Java这门编程语言本身存在着什么问题, 而是在AI所处的整个生态领域, 相较于Java所处境遇, 确实成熟程度高出了许多许。

Day 6:读别人的 AI 代码—— 入门(3 小时)

目标: 能读懂 上用 写的 AI 项目代码。

不用从头学 ,重点是理解代码结构:

import torch
import torch.nn as nn
# 定义模型——类比 Java 里定义一个处理流水线
class SimpleModel(nn.Module):
    def __init__(self):
        super().__init__()
        self.linear = nn.Linear(10, 2)  # 10 个输入,2 个输出
    def forward(self, x):
        return self.linear(x)
model = SimpleModel()
# 看起来很简单对吧?复杂模型也是这个结构,只是层更多

给 Java 开发者的阅读技巧:

Day 7:完成一个小项目(3-4 小时)

目标: 用学到的知识独立完成一个完整项目。

推荐项目三选一:

房价预测, 采用回归模型, 运用波士顿/爱荷华房价数据集之中的, 去训练一个随机森林或线性回归模型, 另有垃圾邮件分类, 属于NLP入门范畴, 要借助TF-IDF加朴素贝叶斯办法对短信予以全垃即垃圾或正常进行分类, 还有手写数字识别, 属于图像分类领域, 需凭借MNIST数据集, 来运作一个简单的神经网络。

产出标准:

五、Java vs 一页纸 Cheat Sheet

我将一份Java速查对照表进行了整理, 它覆盖了日常开发百分之九十的场景, 建议把它打印出来粘贴在显示器旁边, 或者保存成桌面快捷方式。

配图 3: 有一张 A4 横版的速查表, 也就是 Cheat Sheet, 它进行了划分, 分成 6 个区块, 其一为变量与类型, 其二是控制流,其三是函数与类, 其四是数据结构, 其五是常用操作, 其六是包管理。并且每个区块都在左右分栏啦, 左边是有着浅蓝色背景的 Java 代码, 右边是有着浅黄色背景的代码。在底部印着“Java 开发者 AI 入门·专栏出品”这样的水印。其设计风格参照了的代码高亮配色。

核心速查要点(文字版预览):

 Java → Python 速记口诀:
├── 大括号 {} → 冒号 : + 缩进
├── System.out.println() → print()
├── ArrayList → list
├── HashMap → dict
├── null → None
├── this → self
├── pom.xml → requirements.txt
├── equals() → ==
├── for (int i=0; i

六、别试图"精通" ,够用就行

在撰写这篇文章之际, 我回想起自身当初刚开始学习时的那种心态, 那便是急切得仿佛要在一周之内将所有的高级特性都予以掌握, 然而最终呈现出的结果却是, 学习得越多, 内心便愈发焦虑。

而后想清楚了, 并不需要你达到精通, 仅需你能够读懂AI代码, 能够让实验跑通, 继而能够迅速验证想法。

这跟撰写专利是同样的道理, 你并非一定要成为各个技术领域的专家, 然而你得具备充足的理解力, 以此来判定一个方案是否具有可专利性。这便是你于AI领域的“理解力工具”。

务实路线:

7天往后, 你的状况应当是, 获取一段AI代码, 能够看懂百分之七十到百分之八十, 剩余的百分之二十凭借查阅文档便能够解决。如此便足够了。

在后续的专栏当中, 我们将会返回至Java的主要领域。紧接着的下一篇文章是《AI实战: 在Boot里调用大模型企业级AI应用开发指南》, 该文章可以传授给你, 是何如能够于人们都所熟知了解的Java相关的生态内, 十分雅致美观得连通接入到AI的能力的。

敬请期待

专栏目录(持续更新中):

写给 Java 开发者的 AI 入门地图

+ Java,让 AI 替你打工

并非是敌人, Java开发者, 有一本7天速成手册, 而你此刻就在这里。

AI 实战:企业级 AI 应用开发指南(即将发布)

Logo

AtomGit AI 社区提供模型库、数据集、Agent、Token等资源

更多推荐