跳转至

第 9 章 · 标准库对照速查

资深 Java 工程师上手干活最大的空白往往是:"我熟悉 java.util / java.time / java.nio.file / java.util.regex,Python 里对应啥?" 本章是一张高频标准库地图,每节给出 Java 对应 + Pythonic 用法。不深入,只给"日常能干活"的对照。


9.1 collectionsjava.util

Python Java 对应 用途
Counter (手动 Map<K,Integer> 计数
defaultdict computeIfAbsent 缺 key 自动建默认值
deque ArrayDeque 双端队列
namedtuple record(轻量) 位置 + 命名访问的不可变元组
OrderedDict LinkedHashMap 保序字典(3.7+ 普通 dict 已保序,多数场景不再需要)
from collections import Counter, defaultdict, deque

Counter("abracadabra").most_common(2)   # [('a', 5), ('b', 2)]
dd = defaultdict(list)
dd["k"].append(1)                       # 不用先判 key
dq = deque([1, 2, 3])
dq.appendleft(0); dq.popleft()          # O(1) 头部操作

9.2 itertools ↔ Stream API

Python 的 itertools 是 Stream 的"前辈",提供惰性迭代工具:

Python Java 对应 作用
chain(a, b) Stream.concat 拼接
islice(it, n) stream.limit(n) 取前 n 个
groupby(it, key) Collectors.groupingBy 分组(注意:需先排序,按连续 key 分组)
product(A, B) 嵌套循环 / 笛卡尔积 笛卡尔积
combinations/pemutations (手写) 组合 / 排列
accumulate stream reduce 前缀 前缀和等
from itertools import chain, groupby, product

list(chain([1, 2], [3, 4]))                 # [1,2,3,4]
list(product("AB", "12"))                   # [('A','1'),('A','2'),('B','1'),('B','2')]

# groupby 必须先按 key 排序,它只分"连续相同"的段
data = sorted([("a",1),("b",2),("a",3)], key=lambda x: x[0])
for k, group in groupby(data, key=lambda x: x[0]):
    print(k, list(group))                   # a [('a',1),('a',3)] ; b [('b',2)]

⚠️ Java 程序员的陷阱

itertools.groupby 和 Java 的 groupingBy 行为不同:它只把相邻且 key 相同的元素分组,所以必须先按 key 排序。想完全等同 groupingBy,更省心的做法是用 defaultdict(list) 手动收集。


9.3 pathlibjava.nio.file

Python 处理路径的现代方式pathlib(比老的 os.path 拼字符串优雅得多):

Python Java
Path("a") / "b.txt" Path.of("a","b.txt")
p.read_text(encoding="utf-8") Files.readString(p)
p.write_text(s) Files.writeString(p, s)
p.exists() / p.is_file() Files.exists / isRegularFile
p.parent / p.name / p.suffix p.getParent / getFileName
Path(".").glob("*.py") Files.list + 过滤
from pathlib import Path

docs = Path("docs")
for md in docs.rglob("*.md"):          # 递归 glob
    print(md, md.stat().st_size)

(docs / "notes.txt").write_text("hi", encoding="utf-8")

Pythonic 写法

拼路径用 / 运算符(Path("a") / "b"),永远不要用字符串 + 拼(跨平台分隔符问题)。


9.4 datetimejava.time

Python Java
date(2026, 6, 16) LocalDate
datetime.now() LocalDateTime.now()
datetime.now(timezone.utc) Instant.now()
timedelta(days=1) Duration / Period
dt.strftime("%Y-%m-%d") DateTimeFormatter
datetime.fromisoformat(s) parse
from datetime import datetime, date, timedelta, timezone

now = datetime.now()                       # naive(无时区,慎用)
utc = datetime.now(timezone.utc)           # aware(带时区,推荐)
tomorrow = date.today() + timedelta(days=1)
formatted = now.strftime("%Y-%m-%d %H:%M")
parsed = datetime.fromisoformat("2026-06-16T10:00:00")

⚠️ Java 程序员的陷阱

Python 的 datetime.now() 默认是 naive(无时区信息),存/传时容易踩夏令时坑。推荐带时区datetime.now(timezone.utc),或用第三方 zoneinfo(标准库,3.9+)指定时区。


9.5 rejava.util.regex

import re

re.findall(r"\d+", "a1b22c333")          # ['1', '22', '333']
re.sub(r"\s+", "-", "a  b   c")          # 'a-b-c'
m = re.search(r"(\w+)@(\w+)", "mail: x@y.com")
m.group(1), m.group(2)                    # ('x', 'y')

# 预编译(循环里用,提升性能)
pattern = re.compile(r"\d{4}")
pattern.findall("2026 and 1999")
Python Java
re.match Pattern.matcher + matches(从头匹配)
re.search find(任意位置)
re.findall 循环 find + group
re.sub replaceAll
r"raw string" Pattern.compile

Pythonic 写法

正则字符串前加 r(raw string),避免反斜杠转义地狱:r"\d+\s" 而不是 "\\d+\\s"


9.6 json ↔ Jackson / Gson

import json

data = {"name": "小明", "age": 30}
text = json.dumps(data, ensure_ascii=False, indent=2)   # 序列化
obj = json.loads(text)                                    # 反序列化
Python Java
json.dumps(obj) objectMapper.writeValueAsString
json.loads(s) objectMapper.readValue
ensure_ascii=False (默认就是 UTF-8)

要点

  • 默认 dumps 会把非 ASCII 转义:"小明""小明"。中文项目务必 ensure_ascii=False
  • 复杂对象模型(嵌套、校验)用第三方 pydantic(FastAPI 底层),相当于 Jackson + Bean Validation。

9.7 csv ↔ Apache Commons CSV

import csv

with open("data.csv", newline="", encoding="utf-8") as f:
    reader = csv.DictReader(f)            # 每行是 dict
    for row in reader:
        print(row["name"], row["age"])

9.8 subprocess ↔ ProcessBuilder

import subprocess

result = subprocess.run(
    ["git", "status"],
    capture_output=True, text=True, check=True
)
print(result.stdout)
# check=True 时非零退出码抛 CalledProcessError

⚠️ Java 程序员的陷阱

别再用老式的 os.system()subprocess.run(..., shell=True) 拼 shell 字符串——有命令注入风险。用列表形式 ["git", "status", path] 传参,让系统正确转义。


9.9 logging ↔ slf4j / log4j

import logging

logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
log = logging.getLogger(__name__)         # 按模块命名 logger

log.info("user %s logged in", user_id)    # 用 %s 占位,延迟格式化(别用 f-string)
Python Java
logging.getLogger(__name__) LoggerFactory.getLogger(Class)
log.info / warning / error log.info / warn / error
basicConfig logback.xml 配置

Pythonic 写法

日志消息用 log.info("user %s done", uid) 而非 log.info(f"user {uid} done")——前者只在真的输出时才格式化,且级别不够时不做无用拼接。


9.10 其他高频工具速查

领域 Python Java
数学 math, statistics, random Math, Random
函数工具 functoolslru_cache, partial, reduce), operator Function, Collectors.reducing
操作系统 os, sys, shutil System, Files
临时文件 tempfile Files.createTempFile
类型/反射 typing, inspect, dataclasses java.lang.reflect
并发(第 11 章) threading, multiprocessing, concurrent.futures, asyncio java.util.concurrent

本章练习

练习 9.1

pathlib 写:统计 docs/ 目录下所有 .md 文件的总行数。

参考答案
from pathlib import Path
total = sum(
    len(p.read_text(encoding="utf-8").splitlines())
    for p in Path("docs").rglob("*.md")
)
练习 9.2

Counter 统计一段英文里每个单词的出现次数(忽略大小写、去标点),取前 3。

参考答案
from collections import Counter
import re
text = "To be or not to be, that is the question."
words = re.findall(r"[a-z]+", text.lower())
print(Counter(words).most_common(3))
# [('to', 2), ('be', 2), ('or', 1)]  (前三可能并列)
练习 9.3

subprocess 安全地运行 ping 某主机 3 次,捕获输出;非零退出时打印错误。

参考答案
import subprocess
try:
    r = subprocess.run(
        ["ping", "-n", "3", "example.com"],   # Windows 用 -n
        capture_output=True, text=True, check=True
    )
    print(r.stdout)
except subprocess.CalledProcessError as e:
    print(f"failed (exit {e.returncode}):", e.stderr)

上一章:第 8 章 · 类型提示 | 下一章:第 10 章 · 工程化基础