Files
Android-pyApi/android_pyapi/java/util.py
T
shuiyu1123 8c3bd3c415 feat: 大幅增强原生行为 — 修复P0 Bug + 补全核心API
P0 Bug 修复:
- Canvas.drawBitmap 重复定义导致重载丢失 → 合并为*args重载
- String.hashCode() 不可达的第二return → 修复为单return
- File.compareTo() 调用不存在的__cmp__ → 改为显式比较
- HashMap.remove() 逻辑错误 → 区分单参(返回旧值)/双参(返回boolean)

P1 核心行为增强:
- Handler: sendMessage/sendMessageDelayed 现在真正入队异步执行
- Looper: loop() 实现真正的消息循环(按when时间取出到期消息)
- AsyncTask: execute() 在后台线程池执行,完成后主线程回调
- Bundle: 新增12个数组类型put/get方法
- Math.round: 改为Java语义(floor(a+0.5))而非Python银行家舍入
- Thread: currentThread()缓存对象, 新增join/getState/getId/getPriority
- String: 新增strip/repeat/isBlank/lines/subSequence/getChars/chars/formatted/translateEscapes

P2 缺失API补全:
- 新增21个Java标准Exception类 (NullPointerException等)
- View: 新增39个事件处理/监听器/位置尺寸方法
- Activity: 新增33个生命周期/权限/UI方法
- Context: 新增22个文件流/权限/资源/主题方法
- Canvas: 支持 Canvas(Bitmap) 构造函数重载
- __init__.py: __all__ 补全Exception体系和Activity类
2026-06-24 15:04:17 +00:00

3700 lines
107 KiB
Python

"""
Java java.util standard library APIs implemented in Python.
Android-pyApi: desktop Python translation of Android Java APIs.
"""
from .._core import Stub
from .lang import RuntimeException
import heapq as _heapq
import bisect as _bisect
import datetime as _datetime
import uuid as _uuid
import random as _py_random
import math as _py_math
import copy as _copy
import re as _re
import io as _io
import threading as _threading
import time as _time
from typing import Any, Dict, List, Callable, Tuple, Iterable as _IterableType
import typing as _typing
from collections.abc import Iterable as _IterableABC
__all__ = [
"ArrayList", "LinkedList", "HashMap", "LinkedHashMap", "TreeMap",
"HashSet", "TreeSet", "LinkedHashSet",
"Collections", "Arrays", "Date", "Calendar", "GregorianCalendar",
"UUID", "StringTokenizer", "Optional", "Random",
"Properties", "EnumSet", "EnumMap",
"Iterator", "ListIterator", "Enumeration",
"Objects", "Locale", "BitSet", "PriorityQueue",
"Vector", "Stack",
"ConcurrentModificationException", "NoSuchElementException",
"EmptyStackException", "TooManyListenersException",
"MissingResourceException", "IllegalFormatException",
"DuplicateFormatFlagsException", "FormatFlagsConversionMismatchException",
"FormatterClosedException",
]
# ============================================================
# Exceptions
# ============================================================
# Define exception classes in correct dependency order.
# IllegalArgumentException comes before IllegalFormatException.
IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
ConcurrentModificationException = type(
"ConcurrentModificationException", (RuntimeException,), {}
)
NoSuchElementException = type("NoSuchElementException", (RuntimeException,), {})
EmptyStackException = type("EmptyStackException", (RuntimeException,), {})
TooManyListenersException = type("TooManyListenersException", (Exception,), {})
MissingResourceException = type("MissingResourceException", (RuntimeException,), {})
IllegalFormatException = type("IllegalFormatException", (IllegalArgumentException,), {})
DuplicateFormatFlagsException = type(
"DuplicateFormatFlagsException", (IllegalFormatException,), {}
)
FormatFlagsConversionMismatchException = type(
"FormatFlagsConversionMismatchException", (IllegalFormatException,), {}
)
# We need IllegalStateException for FormatterClosedException
from .lang import RuntimeException as _RuntimeException
IllegalStateException = type("IllegalStateException", (_RuntimeException,), {})
FormatterClosedException = type("FormatterClosedException", (IllegalStateException,), {})
UnsupportedOperationException = type("UnsupportedOperationException", (RuntimeException,), {})
# ============================================================
# Iterator / ListIterator / Enumeration
# ============================================================
class Iterator(Stub):
"""java.util.Iterator"""
def __init__(self, data):
super().__init__()
self._data = list(data)
self._index = 0
self._mod_count = 0
def hasNext(self) -> bool:
return self._index < len(self._data)
def next(self):
if not self.hasNext():
raise NoSuchElementException()
val = self._data[self._index]
self._index += 1
return val
def remove(self):
raise UnsupportedOperationException("remove")
def forEachRemaining(self, action):
while self.hasNext():
action(self.next())
class ListIterator(Iterator):
"""java.util.ListIterator"""
def __init__(self, data):
super().__init__(data)
def hasPrevious(self) -> bool:
return self._index > 0
def previous(self):
if not self.hasPrevious():
raise NoSuchElementException()
self._index -= 1
return self._data[self._index]
def nextIndex(self) -> int:
return self._index
def previousIndex(self) -> int:
return self._index - 1
def set(self, obj):
self._data[self._index - 1] = obj
def add(self, obj):
self._data.insert(self._index, obj)
self._index += 1
class Enumeration(Stub):
"""java.util.Enumeration"""
def __init__(self, data):
super().__init__()
self._it = iter(data)
def hasMoreElements(self) -> bool:
try:
self._next = next(self._it)
return True
except StopIteration:
return False
def nextElement(self):
if hasattr(self, '_next'):
val = self._next
del self._next
return val
return next(self._it)
def asIterator(self) -> Iterator:
return Iterator(self._it)
# ============================================================
# ArrayList
# ============================================================
class ArrayList(Stub):
"""java.util.ArrayList — backed by Python list"""
def __init__(self, initial_capacity: Any = None):
super().__init__()
if initial_capacity is None:
self._data = []
elif isinstance(initial_capacity, int):
self._data = []
elif isinstance(initial_capacity, _IterableABC):
self._data = list(initial_capacity)
else:
self._data = []
def add(self, obj) -> bool:
self._data.append(obj)
return True
def addAt(self, index: int, obj) -> None:
self._data.insert(index, obj)
def addAll(self, c) -> bool:
if isinstance(c, ArrayList):
self._data.extend(c._data)
else:
self._data.extend(c)
return True
def addAllAt(self, index: int, c) -> bool:
if isinstance(c, ArrayList):
self._data[index:index] = c._data
else:
self._data[index:index] = list(c)
return True
def clear(self) -> None:
self._data.clear()
def clone(self) -> 'ArrayList':
return ArrayList(self._data)
def contains(self, obj) -> bool:
return obj in self._data
def containsAll(self, c) -> bool:
if isinstance(c, ArrayList):
return all(x in self._data for x in c._data)
return all(x in self._data for x in c)
def ensureCapacity(self, min_capacity: int) -> None:
pass # Python list handles resizing automatically
def get(self, index: int):
return self._data[index]
def indexOf(self, obj) -> int:
try:
return self._data.index(obj)
except ValueError:
return -1
def isEmpty(self) -> bool:
return len(self._data) == 0
def iterator(self) -> Iterator:
return Iterator(self._data)
def listIterator(self) -> ListIterator:
return ListIterator(self._data)
def lastIndexOf(self, obj) -> int:
try:
return len(self._data) - 1 - self._data[::-1].index(obj)
except ValueError:
return -1
def remove(self, obj) -> bool:
if obj in self._data:
self._data.remove(obj)
return True
return False
def removeAt(self, index: int):
return self._data.pop(index)
def removeAll(self, c) -> bool:
if isinstance(c, ArrayList):
items = c._data
else:
items = list(c)
old_len = len(self._data)
self._data = [x for x in self._data if x not in items]
return len(self._data) != old_len
def retainAll(self, c) -> bool:
if isinstance(c, ArrayList):
items = set(c._data)
else:
items = set(c)
old_len = len(self._data)
self._data = [x for x in self._data if x in items]
return len(self._data) != old_len
def set(self, index: int, obj):
old = self._data[index]
self._data[index] = obj
return old
def size(self) -> int:
return len(self._data)
def sort(self, key=None, reverse: bool = False) -> None:
self._data.sort(key=key, reverse=reverse)
def subList(self, from_index: int, to_index: int) -> 'ArrayList':
return ArrayList(self._data[from_index:to_index])
def toArray(self, a=None):
if a is None:
return list(self._data)
if len(a) < len(self._data):
return list(self._data)
for i, v in enumerate(self._data):
a[i] = v
if len(self._data) < len(a):
a[len(self._data)] = None
return a
def trimToSize(self) -> None:
pass
def forEach(self, action) -> None:
for item in self._data:
action(item)
def removeIf(self, predicate) -> bool:
old_len = len(self._data)
self._data = [x for x in self._data if not predicate(x)]
return len(self._data) != old_len
def replaceAll(self, operator) -> None:
self._data = [operator(x) for x in self._data]
def equals(self, other) -> bool:
if isinstance(other, ArrayList):
return self._data == other._data
return False
def hashCode(self) -> int:
h = 1
for v in self._data:
h = (31 * h + hash(v)) & 0x7FFFFFFF
return h
def toString(self) -> str:
items = ", ".join(str(x) for x in self._data)
return f"[{items}]"
def __len__(self):
return len(self._data)
def __getitem__(self, idx):
return self._data[idx]
def __setitem__(self, idx, val):
self._data[idx] = val
def __delitem__(self, idx):
del self._data[idx]
def __iter__(self):
return iter(self._data)
def __repr__(self):
return self.toString()
def __contains__(self, obj):
return obj in self._data
def __add__(self, other):
if isinstance(other, ArrayList):
result = ArrayList(self._data)
result._data.extend(other._data)
return result
return NotImplemented
def __eq__(self, other):
return self.equals(other)
# ============================================================
# LinkedList
# ============================================================
class LinkedList(Stub):
"""java.util.LinkedList — backed by Python list"""
def __init__(self, c=None):
super().__init__()
if c is None:
self._data = []
elif isinstance(c, _IterableABC):
self._data = list(c)
else:
self._data = []
def add(self, obj) -> bool:
self._data.append(obj)
return True
def addFirst(self, obj) -> None:
self._data.insert(0, obj)
def addLast(self, obj) -> None:
self._data.append(obj)
def addAt(self, index: int, obj) -> None:
self._data.insert(index, obj)
def addAll(self, c) -> bool:
if isinstance(c, LinkedList):
self._data.extend(c._data)
else:
self._data.extend(c)
return True
def clear(self) -> None:
self._data.clear()
def clone(self) -> 'LinkedList':
return LinkedList(self._data)
def contains(self, obj) -> bool:
return obj in self._data
def descendingIterator(self) -> Iterator:
return Iterator(reversed(self._data))
def element(self):
if not self._data:
raise NoSuchElementException()
return self._data[0]
def get(self, index: int):
return self._data[index]
def getFirst(self):
if not self._data:
raise NoSuchElementException()
return self._data[0]
def getLast(self):
if not self._data:
raise NoSuchElementException()
return self._data[-1]
def indexOf(self, obj) -> int:
try:
return self._data.index(obj)
except ValueError:
return -1
def isEmpty(self) -> bool:
return len(self._data) == 0
def iterator(self) -> Iterator:
return Iterator(self._data)
def lastIndexOf(self, obj) -> int:
try:
return len(self._data) - 1 - self._data[::-1].index(obj)
except ValueError:
return -1
def listIterator(self, index: int = 0) -> ListIterator:
li = ListIterator(self._data)
li._index = index
return li
def offer(self, obj) -> bool:
self._data.append(obj)
return True
def offerFirst(self, obj) -> bool:
self._data.insert(0, obj)
return True
def offerLast(self, obj) -> bool:
self._data.append(obj)
return True
def peek(self):
return self._data[0] if self._data else None
def peekFirst(self):
return self._data[0] if self._data else None
def peekLast(self):
return self._data[-1] if self._data else None
def poll(self):
return self._data.pop(0) if self._data else None
def pollFirst(self):
return self._data.pop(0) if self._data else None
def pollLast(self):
return self._data.pop() if self._data else None
def pop(self):
if not self._data:
raise NoSuchElementException()
return self._data.pop()
def push(self, obj) -> None:
self._data.insert(0, obj)
def remove(self, obj) -> bool:
if obj in self._data:
self._data.remove(obj)
return True
return False
def removeAt(self, index: int):
return self._data.pop(index)
def removeFirst(self):
if not self._data:
raise NoSuchElementException()
return self._data.pop(0)
def removeFirstOccurrence(self, obj) -> bool:
try:
idx = self._data.index(obj)
self._data.pop(idx)
return True
except ValueError:
return False
def removeLast(self):
if not self._data:
raise NoSuchElementException()
return self._data.pop()
def removeLastOccurrence(self, obj) -> bool:
try:
idx = len(self._data) - 1 - self._data[::-1].index(obj)
self._data.pop(idx)
return True
except ValueError:
return False
def set(self, index: int, obj):
old = self._data[index]
self._data[index] = obj
return old
def size(self) -> int:
return len(self._data)
def toArray(self, a=None):
if a is None:
return list(self._data)
if len(a) < len(self._data):
return list(self._data)
for i, v in enumerate(self._data):
a[i] = v
if len(self._data) < len(a):
a[len(self._data)] = None
return a
def forEach(self, action) -> None:
for item in self._data:
action(item)
def equals(self, other) -> bool:
if isinstance(other, LinkedList):
return self._data == other._data
return False
def hashCode(self) -> int:
h = 1
for v in self._data:
h = (31 * h + hash(v)) & 0x7FFFFFFF
return h
def toString(self) -> str:
items = ", ".join(str(x) for x in self._data)
return f"[{items}]"
def __len__(self):
return len(self._data)
def __getitem__(self, idx):
return self._data[idx]
def __iter__(self):
return iter(self._data)
def __repr__(self):
return self.toString()
def __eq__(self, other):
return self.equals(other)
# ============================================================
# HashMap
# ============================================================
class HashMap(Stub):
"""java.util.HashMap — backed by Python dict"""
def __init__(self, initial_capacity: Any = None, load_factor: float = 0.75):
super().__init__()
self._data: Dict = {}
if initial_capacity is not None and not isinstance(initial_capacity, (int, float)):
if isinstance(initial_capacity, HashMap):
self._data.update(initial_capacity._data)
elif isinstance(initial_capacity, dict):
self._data.update(initial_capacity)
elif isinstance(initial_capacity, _IterableABC):
for item in initial_capacity:
if hasattr(item, 'getKey') and hasattr(item, 'getValue'):
k, v = item.getKey(), item.getValue()
elif isinstance(item, tuple) and len(item) >= 2:
k, v = item[0], item[1]
else:
continue
self._data[k] = v
def clear(self) -> None:
self._data.clear()
def clone(self) -> 'HashMap':
return HashMap(self._data)
def compute(self, key, remapping_function):
old = self._data.get(key)
new_val = remapping_function(key, old)
if new_val is not None:
self._data[key] = new_val
return new_val
self._data.pop(key, None)
return None
def computeIfAbsent(self, key, mapping_function):
if key not in self._data:
new_val = mapping_function(key)
if new_val is not None:
self._data[key] = new_val
return new_val
return self._data.get(key)
def computeIfPresent(self, key, remapping_function):
if key in self._data:
new_val = remapping_function(key, self._data[key])
if new_val is not None:
self._data[key] = new_val
return new_val
self._data.pop(key, None)
return None
def containsKey(self, key) -> bool:
return key in self._data
def containsValue(self, value) -> bool:
return value in self._data.values()
def entrySet(self) -> set:
return self._data.items()
def forEach(self, action) -> None:
for k, v in self._data.items():
action(k, v)
def get(self, key):
return self._data.get(key)
def getOrDefault(self, key, default):
return self._data.get(key, default)
def isEmpty(self) -> bool:
return len(self._data) == 0
def keySet(self) -> set:
return set(self._data.keys())
def merge(self, key, value, remapping_function):
old = self._data.get(key)
if old is None:
self._data[key] = value
return value
new_val = remapping_function(old, value)
if new_val is not None:
self._data[key] = new_val
return new_val
self._data.pop(key, None)
return None
def put(self, key, value):
old = self._data.get(key)
self._data[key] = value
return old
def putAll(self, m) -> None:
if isinstance(m, HashMap):
self._data.update(m._data)
else:
self._data.update(m)
def putIfAbsent(self, key, value):
if key not in self._data:
self._data[key] = value
return None
return self._data[key]
def remove(self, key, value=None):
if value is not None:
# remove(key, value) — 返回 boolean
if key in self._data and self._data[key] == value:
del self._data[key]
return True
return False
else:
# remove(key) — 返回被删除的 value(与 Java 语义一致)
if key in self._data:
old = self._data[key]
del self._data[key]
return old
return None
def replace(self, key, old_value=None, new_value=None):
if old_value is None and new_value is None:
return None
if new_value is None:
# replace(key, value) form
if key in self._data:
old = self._data[key]
self._data[key] = old_value # old_value is actually new value here
return old
return None
# replace(key, oldValue, newValue) form
if key in self._data and self._data[key] == old_value:
self._data[key] = new_value
return True
return False
def replaceAll(self, function) -> None:
for k in list(self._data.keys()):
self._data[k] = function(k, self._data[k])
def size(self) -> int:
return len(self._data)
def values(self):
return list(self._data.values())
def equals(self, other) -> bool:
if isinstance(other, HashMap):
return self._data == other._data
return False
def hashCode(self) -> int:
h = 0
for k, v in self._data.items():
h = (h + (hash(k) ^ hash(v))) & 0x7FFFFFFF
return h
def toString(self) -> str:
items = ", ".join(f"{k}={v}" for k, v in self._data.items())
return f"{{{items}}}"
def __len__(self):
return len(self._data)
def __getitem__(self, key):
return self._data[key]
def __setitem__(self, key, value):
self._data[key] = value
def __delitem__(self, key):
del self._data[key]
def __iter__(self):
return iter(self._data)
def __contains__(self, key):
return key in self._data
def __repr__(self):
return self.toString()
def __eq__(self, other):
return self.equals(other)
# ============================================================
# LinkedHashMap
# ============================================================
class LinkedHashMap(HashMap):
"""java.util.LinkedHashMap — backed by dict (preserves order in Python 3.7+)"""
def __init__(self, initial_capacity: Any = None, load_factor: float = 0.75,
access_order: bool = False):
super().__init__(initial_capacity, load_factor)
self._access_order = access_order
def get(self, key):
val = self._data.get(key)
if val is not None and self._access_order:
# Move to end (most recently accessed) by delete/reinsert
del self._data[key]
self._data[key] = val
return val
def getOrDefault(self, key, default):
val = self._data.get(key, default)
if key in self._data and self._access_order:
del self._data[key]
self._data[key] = val
return val
def put(self, key, value):
old = self._data.get(key)
if key in self._data:
del self._data[key]
self._data[key] = value
return old
def removeEldestEntry(self, eldest) -> bool:
return False
def eldest(self):
if not self._data:
return None
key = next(iter(self._data))
return (key, self._data[key])
# ============================================================
# TreeMap
# ============================================================
class TreeMap(Stub):
"""java.util.TreeMap — sorted map using Python's sorted()"""
def __init__(self, comparator=None, m=None):
super().__init__()
self._data: Dict = {}
self._comparator = comparator
if m is not None:
if isinstance(m, TreeMap):
self._data.update(m._data)
elif isinstance(m, dict):
self._data.update(m)
elif isinstance(m, _IterableABC):
for item in m:
if isinstance(item, tuple) and len(item) >= 2:
self._data[item[0]] = item[1]
def _sorted_keys(self):
key_fn = self._comparator if self._comparator else None
return sorted(self._data.keys(), key=key_fn)
def _get_entry_by_key(self, key):
if key in self._data:
return (key, self._data[key])
return None
def clear(self) -> None:
self._data.clear()
def clone(self) -> 'TreeMap':
return TreeMap(self._comparator, self._data)
def comparator(self):
return self._comparator
def containsKey(self, key) -> bool:
return key in self._data
def containsValue(self, value) -> bool:
return value in self._data.values()
def ceilingKey(self, key):
keys = self._sorted_keys()
for k in keys:
if (self._comparator(k, key) >= 0 if self._comparator else k >= key):
return k
return None
def ceilingEntry(self, key):
k = self.ceilingKey(key)
return (k, self._data[k]) if k is not None else None
def floorKey(self, key):
keys = self._sorted_keys()
for k in reversed(keys):
if (self._comparator(k, key) <= 0 if self._comparator else k <= key):
return k
return None
def floorEntry(self, key):
k = self.floorKey(key)
return (k, self._data[k]) if k is not None else None
def higherKey(self, key):
keys = self._sorted_keys()
for k in keys:
if (self._comparator(k, key) > 0 if self._comparator else k > key):
return k
return None
def higherEntry(self, key):
k = self.higherKey(key)
return (k, self._data[k]) if k is not None else None
def lowerKey(self, key):
keys = self._sorted_keys()
for k in reversed(keys):
if (self._comparator(k, key) < 0 if self._comparator else k < key):
return k
return None
def lowerEntry(self, key):
k = self.lowerKey(key)
return (k, self._data[k]) if k is not None else None
def firstKey(self):
if not self._data:
raise NoSuchElementException()
return self._sorted_keys()[0]
def firstEntry(self):
k = self.firstKey()
return (k, self._data[k])
def lastKey(self):
if not self._data:
raise NoSuchElementException()
return self._sorted_keys()[-1]
def lastEntry(self):
k = self.lastKey()
return (k, self._data[k])
def pollFirstEntry(self):
if not self._data:
return None
k = self.firstKey()
v = self._data.pop(k)
return (k, v)
def pollLastEntry(self):
if not self._data:
return None
k = self.lastKey()
v = self._data.pop(k)
return (k, v)
def entrySet(self):
return [(k, self._data[k]) for k in self._sorted_keys()]
def forEach(self, action) -> None:
for k in self._sorted_keys():
action(k, self._data[k])
def get(self, key):
return self._data.get(key)
def getOrDefault(self, key, default):
return self._data.get(key, default)
def headMap(self, to_key, inclusive: bool = False) -> 'TreeMap':
result = TreeMap(self._comparator)
for k in self._sorted_keys():
cmp = self._comparator(k, to_key) if self._comparator else (k < to_key)
if cmp or (inclusive and (self._comparator(k, to_key) == 0 if self._comparator else k == to_key)):
result._data[k] = self._data[k]
elif not inclusive and (self._comparator(k, to_key) < 0 if self._comparator else k < to_key):
result._data[k] = self._data[k]
else:
break
return result
def tailMap(self, from_key, inclusive: bool = True) -> 'TreeMap':
result = TreeMap(self._comparator)
started = False
for k in self._sorted_keys():
cmp = self._comparator(k, from_key) if self._comparator else (k >= from_key)
if cmp or (inclusive and (self._comparator(k, from_key) == 0 if self._comparator else k == from_key)):
started = True
if started:
result._data[k] = self._data[k]
return result
def subMap(self, from_key, to_key, from_inclusive: bool = True, to_inclusive: bool = False) -> 'TreeMap':
result = TreeMap(self._comparator)
for k in self._sorted_keys():
cmp_from = self._comparator(k, from_key) if self._comparator else (k >= from_key if from_inclusive else k > from_key)
cmp_to = self._comparator(k, to_key) if self._comparator else (k <= to_key if to_inclusive else k < to_key)
if cmp_from and cmp_to:
result._data[k] = self._data[k]
return result
def isEmpty(self) -> bool:
return len(self._data) == 0
def keySet(self):
return self._sorted_keys()
def put(self, key, value):
old = self._data.get(key)
self._data[key] = value
return old
def putAll(self, m) -> None:
if isinstance(m, TreeMap):
self._data.update(m._data)
else:
self._data.update(m)
def putIfAbsent(self, key, value):
if key not in self._data:
self._data[key] = value
return None
return self._data[key]
def remove(self, key):
return self._data.pop(key, None)
def replace(self, key, old_value=None, new_value=None):
if new_value is None:
if key in self._data:
old = self._data[key]
self._data[key] = old_value
return old
return None
if key in self._data and self._data[key] == old_value:
self._data[key] = new_value
return True
return False
def size(self) -> int:
return len(self._data)
def values(self):
return [self._data[k] for k in self._sorted_keys()]
def navigableKeySet(self):
return self._sorted_keys()
def descendingKeySet(self):
return list(reversed(self._sorted_keys()))
def descendingMap(self) -> 'TreeMap':
result = TreeMap(self._comparator)
for k in reversed(self._sorted_keys()):
result._data[k] = self._data[k]
return result
def equals(self, other) -> bool:
if isinstance(other, TreeMap):
return self._data == other._data
return False
def hashCode(self) -> int:
h = 0
for k, v in self._data.items():
h = (h + (hash(k) ^ hash(v))) & 0x7FFFFFFF
return h
def toString(self) -> str:
items = ", ".join(f"{k}={v}" for k in self._data.items())
return f"{{{items}}}"
def __len__(self):
return len(self._data)
def __getitem__(self, key):
return self._data[key]
def __setitem__(self, key, value):
self._data[key] = value
def __delitem__(self, key):
del self._data[key]
def __iter__(self):
return iter(self._sorted_keys())
def __repr__(self):
return self.toString()
def __eq__(self, other):
return self.equals(other)
# ============================================================
# HashSet
# ============================================================
class HashSet(Stub):
"""java.util.HashSet — backed by Python set"""
def __init__(self, c=None):
super().__init__()
if c is None:
self._data: set = set()
elif isinstance(c, _IterableABC):
self._data = set(c)
else:
self._data = set()
def add(self, obj) -> bool:
if obj in self._data:
return False
self._data.add(obj)
return True
def addAll(self, c) -> bool:
old_size = len(self._data)
if isinstance(c, HashSet):
self._data.update(c._data)
elif isinstance(c, set):
self._data.update(c)
else:
self._data.update(c)
return len(self._data) != old_size
def clear(self) -> None:
self._data.clear()
def clone(self) -> 'HashSet':
return HashSet(self._data)
def contains(self, obj) -> bool:
return obj in self._data
def containsAll(self, c) -> bool:
if isinstance(c, HashSet):
return all(x in self._data for x in c._data)
return all(x in self._data for x in c)
def isEmpty(self) -> bool:
return len(self._data) == 0
def iterator(self) -> Iterator:
return Iterator(list(self._data))
def remove(self, obj) -> bool:
if obj in self._data:
self._data.remove(obj)
return True
return False
def removeAll(self, c) -> bool:
old_size = len(self._data)
if isinstance(c, HashSet):
self._data.difference_update(c._data)
else:
self._data.difference_update(c)
return len(self._data) != old_size
def retainAll(self, c) -> bool:
old_size = len(self._data)
if isinstance(c, HashSet):
self._data.intersection_update(c._data)
else:
self._data.intersection_update(c)
return len(self._data) != old_size
def size(self) -> int:
return len(self._data)
def toArray(self, a=None):
items = list(self._data)
if a is None:
return items
if len(a) < len(items):
return items
for i, v in enumerate(items):
a[i] = v
if len(items) < len(a):
a[len(items)] = None
return a
def forEach(self, action) -> None:
for item in list(self._data):
action(item)
def equals(self, other) -> bool:
if isinstance(other, HashSet):
return self._data == other._data
return False
def hashCode(self) -> int:
h = 0
for v in self._data:
h = (h + hash(v)) & 0x7FFFFFFF
return h
def toString(self) -> str:
items = ", ".join(str(x) for x in self._data)
return f"[{items}]"
def __len__(self):
return len(self._data)
def __iter__(self):
return iter(self._data)
def __contains__(self, obj):
return obj in self._data
def __repr__(self):
return self.toString()
def __eq__(self, other):
return self.equals(other)
# ============================================================
# LinkedHashSet
# ============================================================
class LinkedHashSet(HashSet):
"""java.util.LinkedHashSet — ordered set (preserves insertion order)"""
def __init__(self, c=None):
# dict keys preserve insertion order in Python 3.7+
self._order: Dict[Any, None] = {}
if c is not None:
if isinstance(c, _IterableABC):
for item in c:
self._order[item] = None
self._data = set(self._order.keys())
def add(self, obj) -> bool:
if obj in self._order:
return False
self._order[obj] = None
self._data.add(obj)
return True
def remove(self, obj) -> bool:
if obj in self._order:
del self._order[obj]
self._data.discard(obj)
return True
return False
def clear(self) -> None:
self._order.clear()
self._data.clear()
def iterator(self) -> Iterator:
return Iterator(list(self._order.keys()))
def toArray(self, a=None):
items = list(self._order.keys())
if a is None:
return items
if len(a) < len(items):
return items
for i, v in enumerate(items):
a[i] = v
if len(items) < len(a):
a[len(items)] = None
return a
def forEach(self, action) -> None:
for item in list(self._order.keys()):
action(item)
def __iter__(self):
return iter(self._order.keys())
# ============================================================
# TreeSet
# ============================================================
class TreeSet(Stub):
"""java.util.TreeSet — sorted set"""
def __init__(self, comparator=None, c=None):
super().__init__()
self._data: set = set()
self._comparator = comparator
if c is not None:
if isinstance(c, _IterableABC):
self._data = set(c)
def _sorted(self):
key_fn = self._comparator if self._comparator else None
return sorted(self._data, key=key_fn)
def add(self, obj) -> bool:
if obj in self._data:
return False
self._data.add(obj)
return True
def addAll(self, c) -> bool:
old_size = len(self._data)
if isinstance(c, TreeSet):
self._data.update(c._data)
else:
self._data.update(c)
return len(self._data) != old_size
def ceiling(self, obj):
sorted_items = self._sorted()
for item in sorted_items:
if (self._comparator(item, obj) >= 0 if self._comparator else item >= obj):
return item
return None
def floor(self, obj):
sorted_items = self._sorted()
for item in reversed(sorted_items):
if (self._comparator(item, obj) <= 0 if self._comparator else item <= obj):
return item
return None
def higher(self, obj):
sorted_items = self._sorted()
for item in sorted_items:
if (self._comparator(item, obj) > 0 if self._comparator else item > obj):
return item
return None
def lower(self, obj):
sorted_items = self._sorted()
for item in reversed(sorted_items):
if (self._comparator(item, obj) < 0 if self._comparator else item < obj):
return item
return None
def clear(self) -> None:
self._data.clear()
def clone(self) -> 'TreeSet':
return TreeSet(self._comparator, self._data)
def comparator(self):
return self._comparator
def contains(self, obj) -> bool:
return obj in self._data
def containsAll(self, c) -> bool:
if isinstance(c, TreeSet):
return all(x in self._data for x in c._data)
return all(x in self._data for x in c)
def first(self):
if not self._data:
raise NoSuchElementException()
return self._sorted()[0]
def last(self):
if not self._data:
raise NoSuchElementException()
return self._sorted()[-1]
def pollFirst(self):
if not self._data:
return None
val = self._sorted()[0]
self._data.discard(val)
return val
def pollLast(self):
if not self._data:
return None
val = self._sorted()[-1]
self._data.discard(val)
return val
def headSet(self, to_element, inclusive: bool = False) -> 'TreeSet':
result = TreeSet(self._comparator)
for item in self._data:
cmp = self._comparator(item, to_element) if self._comparator else (item < to_element)
if cmp or (inclusive and item == to_element):
result._data.add(item)
return result
def tailSet(self, from_element, inclusive: bool = True) -> 'TreeSet':
result = TreeSet(self._comparator)
for item in self._data:
cmp = self._comparator(item, from_element) if self._comparator else (item > from_element)
if cmp or (inclusive and item == from_element):
result._data.add(item)
return result
def subSet(self, from_element, to_element,
from_inclusive: bool = True, to_inclusive: bool = False) -> 'TreeSet':
result = TreeSet(self._comparator)
for item in self._data:
cmp_from = self._comparator(item, from_element) if self._comparator else (
item >= from_element if from_inclusive else item > from_element)
cmp_to = self._comparator(item, to_element) if self._comparator else (
item <= to_element if to_inclusive else item < to_element)
if cmp_from and cmp_to:
result._data.add(item)
return result
def descendingIterator(self) -> Iterator:
return Iterator(reversed(self._sorted()))
def descendingSet(self) -> 'TreeSet':
result = TreeSet(self._comparator)
result._data = set(self._data)
return result
def isEmpty(self) -> bool:
return len(self._data) == 0
def iterator(self) -> Iterator:
return Iterator(self._sorted())
def remove(self, obj) -> bool:
if obj in self._data:
self._data.discard(obj)
return True
return False
def removeAll(self, c) -> bool:
old_size = len(self._data)
if isinstance(c, TreeSet):
self._data.difference_update(c._data)
else:
self._data.difference_update(c)
return len(self._data) != old_size
def retainAll(self, c) -> bool:
old_size = len(self._data)
if isinstance(c, TreeSet):
self._data.intersection_update(c._data)
else:
self._data.intersection_update(c)
return len(self._data) != old_size
def size(self) -> int:
return len(self._data)
def toArray(self, a=None):
items = self._sorted()
if a is None:
return items
if len(a) < len(items):
return items
for i, v in enumerate(items):
a[i] = v
if len(items) < len(a):
a[len(items)] = None
return a
def forEach(self, action) -> None:
for item in self._sorted():
action(item)
def equals(self, other) -> bool:
if isinstance(other, TreeSet):
return self._data == other._data
return False
def hashCode(self) -> int:
h = 0
for v in self._data:
h = (h + hash(v)) & 0x7FFFFFFF
return h
def toString(self) -> str:
items = ", ".join(str(x) for x in self._sorted())
return f"[{items}]"
def __len__(self):
return len(self._data)
def __iter__(self):
return iter(self._sorted())
def __contains__(self, obj):
return obj in self._data
def __repr__(self):
return self.toString()
def __eq__(self, other):
return self.equals(other)
# ============================================================
# Collections
# ============================================================
class Collections:
"""java.util.Collections — static utility methods"""
EMPTY_LIST = []
EMPTY_SET = set()
EMPTY_MAP = {}
@staticmethod
def sort(data, key=None, reverse: bool = False) -> None:
if key is not None:
if isinstance(data, ArrayList):
data._data.sort(key=key, reverse=reverse)
elif isinstance(data, Vector):
data._data.sort(key=key, reverse=reverse)
else:
data.sort(key=key, reverse=reverse)
else:
data.sort(reverse=reverse)
@staticmethod
def reverse(data) -> None:
if isinstance(data, ArrayList):
data._data.reverse()
elif isinstance(data, Vector):
data._data.reverse()
else:
data.reverse()
@staticmethod
def shuffle(data, rnd: _typing.Optional['Random'] = None) -> None:
if isinstance(data, ArrayList):
lst = data._data
elif isinstance(data, Vector):
lst = data._data
else:
lst = data
if rnd:
_py_random.shuffle(lst)
else:
_py_random.shuffle(lst)
@staticmethod
def swap(data, i: int, j: int) -> None:
if isinstance(data, ArrayList):
data._data[i], data._data[j] = data._data[j], data._data[i]
elif isinstance(data, Vector):
data._data[i], data._data[j] = data._data[j], data._data[i]
else:
data[i], data[j] = data[j], data[i]
@staticmethod
def fill(data, obj) -> None:
if isinstance(data, ArrayList):
for i in range(len(data._data)):
data._data[i] = obj
elif isinstance(data, Vector):
for i in range(len(data._data)):
data._data[i] = obj
else:
for i in range(len(data)):
data[i] = obj
@staticmethod
def copy(dest, src) -> None:
if isinstance(dest, ArrayList) and isinstance(src, ArrayList):
dest._data[:len(src._data)] = src._data[:]
elif isinstance(dest, Vector) and isinstance(src, Vector):
dest._data[:len(src._data)] = src._data[:]
else:
dest[:len(src)] = src[:]
@staticmethod
def min(coll, comp=None):
if comp:
return min(coll, key=comp)
return min(coll)
@staticmethod
def max(coll, comp=None):
if comp:
return max(coll, key=comp)
return max(coll)
@staticmethod
def rotate(data, distance: int) -> None:
if isinstance(data, ArrayList):
lst = data._data
elif isinstance(data, Vector):
lst = data._data
else:
lst = data
n = len(lst)
if n == 0:
return
d = distance % n
lst[:] = lst[-d:] + lst[:-d]
@staticmethod
def indexOfSubList(source, target) -> int:
if isinstance(source, ArrayList):
src = source._data
else:
src = list(source)
if isinstance(target, ArrayList):
tgt = target._data
else:
tgt = list(target)
for i in range(len(src) - len(tgt) + 1):
if src[i:i + len(tgt)] == tgt:
return i
return -1
@staticmethod
def lastIndexOfSubList(source, target) -> int:
if isinstance(source, ArrayList):
src = source._data
else:
src = list(source)
if isinstance(target, ArrayList):
tgt = target._data
else:
tgt = list(target)
for i in range(len(src) - len(tgt), -1, -1):
if src[i:i + len(tgt)] == tgt:
return i
return -1
@staticmethod
def replaceAll(data, old_val, new_val) -> bool:
if isinstance(data, ArrayList):
lst = data._data
elif isinstance(data, Vector):
lst = data._data
else:
lst = data
found = False
for i, v in enumerate(lst):
if v == old_val:
lst[i] = new_val
found = True
return found
@staticmethod
def binarySearch(data, key):
if isinstance(data, ArrayList):
lst = data._data
else:
lst = list(data)
idx = _bisect.bisect_left(lst, key)
if idx < len(lst) and lst[idx] == key:
return idx
return -1
@staticmethod
def disjoint(c1, c2) -> bool:
set1 = set(c1)
set2 = set(c2)
return set1.isdisjoint(set2)
@staticmethod
def frequency(c, obj) -> int:
count = 0
for item in c:
if item == obj:
count += 1
return count
@staticmethod
def nCopies(n: int, obj) -> list:
return [obj] * n
@staticmethod
def singleton(obj) -> set:
return {obj}
@staticmethod
def singletonList(obj) -> list:
return [obj]
@staticmethod
def singletonMap(key, value) -> dict:
return {key: value}
@staticmethod
def unmodifiableList(data) -> list:
if isinstance(data, ArrayList):
return tuple(data._data)
return tuple(data)
@staticmethod
def unmodifiableSet(data) -> frozenset:
if isinstance(data, HashSet):
return frozenset(data._data)
return frozenset(data)
@staticmethod
def unmodifiableMap(data) -> dict:
if isinstance(data, HashMap):
return dict(data._data)
return dict(data)
@staticmethod
def synchronizedList(data):
lock = _threading.Lock()
class _SyncList:
def __init__(self, lst):
self._lock = lock
self._lst = lst
def __getattr__(self, name):
with self._lock:
return getattr(self._lst, name)
def add(self, obj):
with self._lock:
return self._lst.add(obj)
def get(self, idx):
with self._lock:
return self._lst[idx]
def set(self, idx, val):
with self._lock:
old = self._lst[idx]
self._lst[idx] = val
return old
def remove(self, obj):
with self._lock:
return self._lst.remove(obj)
def size(self):
with self._lock:
return len(self._lst)
def __len__(self):
with self._lock:
return len(self._lst)
def __getitem__(self, idx):
with self._lock:
return self._lst[idx]
def __setitem__(self, idx, val):
with self._lock:
self._lst[idx] = val
def __iter__(self):
with self._lock:
return iter(list(self._lst))
return _SyncList(data)
@staticmethod
def synchronizedSet(data):
lock = _threading.Lock()
class _SyncSet:
def __init__(self, s):
self._lock = lock
self._s = s
def add(self, obj):
with self._lock:
return self._s.add(obj)
def remove(self, obj):
with self._lock:
return self._s.remove(obj)
def __contains__(self, obj):
with self._lock:
return obj in self._s
def __iter__(self):
with self._lock:
return iter(list(self._s))
def __len__(self):
with self._lock:
return len(self._s)
return _SyncSet(data)
@staticmethod
def synchronizedMap(data):
lock = _threading.Lock()
class _SyncMap:
def __init__(self, m):
self._lock = lock
self._m = m
def put(self, k, v):
with self._lock:
return self._m.put(k, v)
def get(self, k):
with self._lock:
return self._m.get(k)
def remove(self, k):
with self._lock:
return self._m.remove(k)
def __getitem__(self, k):
with self._lock:
return self._m[k]
def __setitem__(self, k, v):
with self._lock:
self._m[k] = v
def __contains__(self, k):
with self._lock:
return k in self._m
def __len__(self):
with self._lock:
return len(self._m)
def keys(self):
with self._lock:
return list(self._m.keys())
return _SyncMap(data)
@staticmethod
def enumaration(c) -> Enumeration:
return Enumeration(c)
@staticmethod
def list(enum: Enumeration) -> ArrayList:
items = []
while enum.hasMoreElements():
items.append(enum.nextElement())
return ArrayList(items)
@staticmethod
def newSetFromMap(m) -> HashSet:
class _SetFromMap(HashSet):
def __init__(self, backing_map):
super().__init__()
self._backing = backing_map
def add(self, obj):
return self._backing.put(obj, True) is None
def iterator(self):
return Iterator(self._backing.keySet())
def size(self):
return self._backing.size()
def remove(self, obj):
return self._backing.remove(obj) is not None
def contains(self, obj):
return self._backing.containsKey(obj)
def clear(self):
self._backing.clear()
return _SetFromMap(m)
@staticmethod
def asLifoQueue(deque) -> 'Collections._LifoQueue':
class _LifoQueue:
def __init__(self, dq):
self._dq = dq
def add(self, e):
self._dq.addFirst(e)
return True
def offer(self, e):
return self.add(e)
def remove(self):
if len(self._dq) == 0:
raise NoSuchElementException()
return self._dq.removeFirst()
def poll(self):
return self._dq.pollFirst()
def element(self):
if len(self._dq) == 0:
raise NoSuchElementException()
return self._dq.getFirst()
def peek(self):
return self._dq.peekFirst()
def size(self):
return self._dq.size()
def isEmpty(self):
return self._dq.isEmpty()
return _LifoQueue(deque)
# ============================================================
# Arrays
# ============================================================
class Arrays:
"""java.util.Arrays — static utility methods"""
@staticmethod
def asList(*args) -> ArrayList:
if len(args) == 1 and isinstance(args[0], (list, tuple)):
return ArrayList(args[0])
return ArrayList(list(args))
@staticmethod
def sort(a, from_index: int = 0, to_index: int = None) -> None:
if to_index is None:
a.sort()
else:
a[from_index:to_index] = sorted(a[from_index:to_index])
@staticmethod
def parallelSort(a, from_index: int = 0, to_index: int = None) -> None:
Arrays.sort(a, from_index, to_index)
@staticmethod
def binarySearch(a, key, from_index: int = 0, to_index: int = None) -> int:
if to_index is None:
lst = a
else:
lst = a[from_index:to_index]
idx = _bisect.bisect_left(lst, key)
if idx < len(lst) and lst[idx] == key:
return idx + from_index
return -(idx + from_index + 1)
@staticmethod
def fill(a, val, from_index: int = 0, to_index: int = None) -> None:
if to_index is None:
for i in range(len(a)):
a[i] = val
else:
for i in range(from_index, to_index):
a[i] = val
@staticmethod
def copyOf(original, new_length: int) -> list:
return list(original[:new_length]) + [None] * max(0, new_length - len(original))
@staticmethod
def copyOfRange(original, from_index: int, to_index: int) -> list:
return list(original[from_index:to_index])
@staticmethod
def equals(a, b) -> bool:
if len(a) != len(b):
return False
return all(x == y for x, y in zip(a, b))
@staticmethod
def deepEquals(a, b) -> bool:
if len(a) != len(b):
return False
return all(_deep_eq(x, y) for x, y in zip(a, b))
@staticmethod
def hashCode(a) -> int:
if a is None:
return 0
h = 1
for v in a:
h = (31 * h + hash(v)) & 0x7FFFFFFF
return h
@staticmethod
def deepHashCode(a) -> int:
if a is None:
return 0
h = 1
for v in a:
if isinstance(v, (list, tuple)):
h = (31 * h + Arrays.deepHashCode(v)) & 0x7FFFFFFF
else:
h = (31 * h + hash(v)) & 0x7FFFFFFF
return h
@staticmethod
def toString(a) -> str:
if a is None:
return "null"
return "[" + ", ".join(str(x) for x in a) + "]"
@staticmethod
def deepToString(a) -> str:
if a is None:
return "null"
return "[" + ", ".join(_deep_str(x) for x in a) + "]"
@staticmethod
def stream(a) -> 'Arrays._ArrayStream':
class _ArrayStream:
def __init__(self, arr):
self._arr = arr
self._idx = 0
def filter(self, pred):
return _ArrayStream([x for x in self._arr if pred(x)])
def map(self, func):
return _ArrayStream([func(x) for x in self._arr])
def forEach(self, action):
for x in self._arr:
action(x)
def toArray(self):
return list(self._arr)
def count(self):
return len(self._arr)
return _ArrayStream(a)
@staticmethod
def setAll(a, generator) -> None:
for i in range(len(a)):
a[i] = generator(i)
@staticmethod
def parallelSetAll(a, generator) -> None:
Arrays.setAll(a, generator)
@staticmethod
def spliterator(a) -> Iterator:
return Iterator(a)
def _deep_eq(x, y) -> bool:
if isinstance(x, (list, tuple)) and isinstance(y, (list, tuple)):
return Arrays.deepEquals(x, y)
return x == y
def _deep_str(x) -> str:
if isinstance(x, (list, tuple)):
return Arrays.deepToString(x)
return str(x)
# ============================================================
# Date
# ============================================================
class Date(Stub):
"""java.util.Date — wraps Python datetime"""
def __init__(self, *args):
super().__init__()
if len(args) == 0:
self._dt = _datetime.datetime.now()
elif len(args) == 1:
if isinstance(args[0], (int, float)):
self._dt = _datetime.datetime.fromtimestamp(args[0] / 1000.0)
elif isinstance(args[0], str):
self._dt = _datetime.datetime.fromisoformat(args[0])
elif isinstance(args[0], _datetime.datetime):
self._dt = args[0]
elif isinstance(args[0], Date):
self._dt = args[0]._dt
else:
self._dt = _datetime.datetime.now()
elif len(args) >= 6:
year = args[0] - 1900
month = args[1]
day = args[2]
hour = args[3] if len(args) > 3 else 0
minute = args[4] if len(args) > 4 else 0
second = args[5] if len(args) > 5 else 0
self._dt = _datetime.datetime(year + 1900, month + 1, day, hour, minute, second)
else:
self._dt = _datetime.datetime.now()
def getTime(self) -> int:
return int(self._dt.timestamp() * 1000)
def setTime(self, time_millis: int) -> None:
self._dt = _datetime.datetime.fromtimestamp(time_millis / 1000.0)
def before(self, when: 'Date') -> bool:
return self._dt < when._dt
def after(self, when: 'Date') -> bool:
return self._dt > when._dt
def compareTo(self, another: 'Date') -> int:
return (self._dt > another._dt) - (self._dt < another._dt)
def equals(self, other) -> bool:
if isinstance(other, Date):
return self._dt == other._dt
return False
def hashCode(self) -> int:
return hash(self._dt) & 0x7FFFFFFF
def toString(self) -> str:
return self._dt.strftime("%a %b %d %H:%M:%S %z %Y")
def clone(self) -> 'Date':
return Date(self._dt)
def getYear(self) -> int:
return self._dt.year - 1900
def getMonth(self) -> int:
return self._dt.month - 1
def getDay(self) -> int:
return self._dt.weekday()
def getHours(self) -> int:
return self._dt.hour
def getMinutes(self) -> int:
return self._dt.minute
def getSeconds(self) -> int:
return self._dt.second
def getDate(self) -> int:
return self._dt.day
def setYear(self, year: int) -> None:
self._dt = self._dt.replace(year=year + 1900)
def setMonth(self, month: int) -> None:
self._dt = self._dt.replace(month=month + 1)
def setDate(self, date: int) -> None:
self._dt = self._dt.replace(day=date)
def setHours(self, hours: int) -> None:
self._dt = self._dt.replace(hour=hours)
def setMinutes(self, minutes: int) -> None:
self._dt = self._dt.replace(minute=minutes)
def setSeconds(self, seconds: int) -> None:
self._dt = self._dt.replace(second=seconds)
def toGMTString(self) -> str:
return self._dt.strftime("%d %b %Y %H:%M:%S GMT")
def toLocaleString(self) -> str:
return self._dt.strftime("%Y-%m-%d %H:%M:%S")
@staticmethod
def parse(s: str) -> 'Date':
try:
return Date(_datetime.datetime.fromisoformat(s))
except ValueError:
return Date()
@staticmethod
def fromInstant(instant) -> 'Date':
return Date(instant.toEpochMilli())
def toInstant(self):
return self._dt
def __str__(self):
return self.toString()
def __repr__(self):
return f"Date({self.getTime()})"
# ============================================================
# Calendar / GregorianCalendar
# ============================================================
class Calendar(Stub):
"""java.util.Calendar — wraps Python datetime with Java field system"""
# Field constants
YEAR = 1
MONTH = 2
DAY_OF_MONTH = 5
DAY_OF_YEAR = 6
DAY_OF_WEEK = 7
DAY_OF_WEEK_IN_MONTH = 8
AM_PM = 9
HOUR = 10
HOUR_OF_DAY = 11
MINUTE = 12
SECOND = 13
MILLISECOND = 14
WEEK_OF_MONTH = 15
WEEK_OF_YEAR = 16
ERA = 17
ZONE_OFFSET = 18
DST_OFFSET = 19
FIELD_COUNT = 20
# Day of week constants
SUNDAY = 1
MONDAY = 2
TUESDAY = 3
WEDNESDAY = 4
THURSDAY = 5
FRIDAY = 6
SATURDAY = 7
# Month constants
JANUARY = 0
FEBRUARY = 1
MARCH = 2
APRIL = 3
MAY = 4
JUNE = 5
JULY = 6
AUGUST = 7
SEPTEMBER = 8
OCTOBER = 9
NOVEMBER = 10
DECEMBER = 11
UNDECIMBER = 12
# AM/PM
AM = 0
PM = 1
def __init__(self):
super().__init__()
self._dt = _datetime.datetime.now()
self._fields: Dict[int, int] = {}
self._is_set: Dict[int, bool] = {}
self._lenient = True
self._first_day_of_week = Calendar.SUNDAY
self._minimal_days_in_first_week = 1
self._timezone = _datetime.timezone.utc
self._set_fields_from_dt()
def _set_fields_from_dt(self) -> None:
self._fields[Calendar.YEAR] = self._dt.year
self._fields[Calendar.MONTH] = self._dt.month - 1
self._fields[Calendar.DAY_OF_MONTH] = self._dt.day
self._fields[Calendar.DAY_OF_YEAR] = self._dt.timetuple().tm_yday
self._fields[Calendar.DAY_OF_WEEK] = self._dt.isoweekday() % 7 + 1
self._fields[Calendar.HOUR] = self._dt.hour % 12
self._fields[Calendar.HOUR_OF_DAY] = self._dt.hour
self._fields[Calendar.MINUTE] = self._dt.minute
self._fields[Calendar.SECOND] = self._dt.second
self._fields[Calendar.MILLISECOND] = self._dt.microsecond // 1000
self._fields[Calendar.AM_PM] = Calendar.AM if self._dt.hour < 12 else Calendar.PM
self._fields[Calendar.WEEK_OF_YEAR] = self._dt.isocalendar()[1]
self._fields[Calendar.ERA] = 1 # AD = 1
def get(self, field: int) -> int:
return self._fields.get(field, 0)
def set(self, field: int, value: int) -> None:
self._fields[field] = value
self._is_set[field] = True
def setTime(self, date: 'Date') -> None:
self._dt = date._dt
self._set_fields_from_dt()
def getTime(self) -> Date:
return Date(self._dt)
def getTimeInMillis(self) -> int:
return int(self._dt.timestamp() * 1000)
def setTimeInMillis(self, millis: int) -> None:
self._dt = _datetime.datetime.fromtimestamp(millis / 1000.0)
self._set_fields_from_dt()
def add(self, field: int, amount: int) -> None:
if field == Calendar.YEAR:
self._dt = self._dt.replace(year=self._dt.year + amount)
elif field == Calendar.MONTH:
new_month = self._dt.month - 1 + amount
new_year = self._dt.year + new_month // 12
new_month = new_month % 12
try:
self._dt = self._dt.replace(year=new_year, month=new_month + 1)
except ValueError:
self._dt = self._dt.replace(year=new_year, month=new_month + 1, day=28)
elif field == Calendar.DAY_OF_MONTH:
self._dt += _datetime.timedelta(days=amount)
elif field == Calendar.HOUR_OF_DAY or field == Calendar.HOUR:
self._dt += _datetime.timedelta(hours=amount)
elif field == Calendar.MINUTE:
self._dt += _datetime.timedelta(minutes=amount)
elif field == Calendar.SECOND:
self._dt += _datetime.timedelta(seconds=amount)
elif field == Calendar.MILLISECOND:
self._dt += _datetime.timedelta(milliseconds=amount)
elif field == Calendar.WEEK_OF_YEAR or field == Calendar.WEEK_OF_MONTH:
self._dt += _datetime.timedelta(weeks=amount)
self._set_fields_from_dt()
def roll(self, field: int, amount: int) -> None:
if field == Calendar.MONTH:
old_month = self._dt.month
new_month = ((old_month - 1 + amount) % 12) + 1
try:
self._dt = self._dt.replace(month=new_month)
except ValueError:
self._dt = self._dt.replace(month=new_month, day=28)
elif field == Calendar.DAY_OF_MONTH:
import calendar as _cal
max_day = _cal.monthrange(self._dt.year, self._dt.month)[1]
new_day = ((self._dt.day - 1 + amount) % max_day) + 1
self._dt = self._dt.replace(day=new_day)
else:
self.add(field, amount)
self._set_fields_from_dt()
def before(self, when: 'Calendar') -> bool:
return self._dt < when._dt
def after(self, when: 'Calendar') -> bool:
return self._dt > when._dt
def compareTo(self, another: 'Calendar') -> int:
return (self._dt > another._dt) - (self._dt < another._dt)
def equals(self, other) -> bool:
if isinstance(other, Calendar):
return self._dt == other._dt
return False
def hashCode(self) -> int:
return hash(self._dt) & 0x7FFFFFFF
def toString(self) -> str:
return str(self._dt)
def isLenient(self) -> bool:
return self._lenient
def setLenient(self, lenient: bool) -> None:
self._lenient = lenient
def getFirstDayOfWeek(self) -> int:
return self._first_day_of_week
def setFirstDayOfWeek(self, value: int) -> None:
self._first_day_of_week = value
def getMinimalDaysInFirstWeek(self) -> int:
return self._minimal_days_in_first_week
def setMinimalDaysInFirstWeek(self, value: int) -> None:
self._minimal_days_in_first_week = value
def getActualMaximum(self, field: int) -> int:
import calendar as _cal
if field == Calendar.DAY_OF_MONTH:
return _cal.monthrange(self._dt.year, self._dt.month)[1]
if field == Calendar.DAY_OF_YEAR:
return 366 if self._dt.year % 4 == 0 and (self._dt.year % 100 != 0 or self._dt.year % 400 == 0) else 365
if field == Calendar.MONTH:
return 11
if field == Calendar.HOUR:
return 11
if field == Calendar.HOUR_OF_DAY:
return 23
if field == Calendar.MINUTE:
return 59
if field == Calendar.SECOND:
return 59
if field == Calendar.MILLISECOND:
return 999
return 0
def getActualMinimum(self, field: int) -> int:
return 0
def getDisplayName(self, field: int, style: int, locale: 'Locale') -> str:
return str(self.get(field))
@staticmethod
def getInstance() -> 'GregorianCalendar':
return GregorianCalendar()
class GregorianCalendar(Calendar):
"""java.util.GregorianCalendar"""
BC = 0
AD = 1
def __init__(self, *args):
super().__init__()
if len(args) == 0:
self._dt = _datetime.datetime.now()
elif len(args) == 3:
year, month, day = args
self._dt = _datetime.datetime(year, month + 1, day)
elif len(args) >= 5:
year, month, day, hour, minute = args[:5]
second = args[5] if len(args) > 5 else 0
self._dt = _datetime.datetime(year, month + 1, day, hour, minute, second)
else:
self._dt = _datetime.datetime.now()
self._set_fields_from_dt()
def isLeapYear(self, year: int) -> bool:
return (year % 4 == 0 and year % 100 != 0) or year % 400 == 0
def getGreatestMinimum(self, field: int) -> int:
return self.getActualMinimum(field)
def getLeastMaximum(self, field: int) -> int:
return self.getActualMaximum(field)
def getMaximum(self, field: int) -> int:
if field == Calendar.DAY_OF_MONTH:
return 31
if field == Calendar.DAY_OF_YEAR:
return 366
if field == Calendar.MONTH:
return 11
return self.getActualMaximum(field)
def getMinimum(self, field: int) -> int:
return 0
# ============================================================
# UUID
# ============================================================
class UUID(Stub):
"""java.util.UUID — wraps Python uuid module"""
def __init__(self, most_sig_bits: int, least_sig_bits: int):
super().__init__()
self._most_sig_bits = most_sig_bits & 0xFFFFFFFFFFFFFFFF
self._least_sig_bits = least_sig_bits & 0xFFFFFFFFFFFFFFFF
# Rebuild a Python UUID from the bits for string representation
hex_str = f"{self._most_sig_bits:016x}{self._least_sig_bits:016x}"
self._uuid = _uuid.UUID(hex_str)
@staticmethod
def randomUUID() -> 'UUID':
u = _uuid.uuid4()
most = u.int >> 64
least = u.int & 0xFFFFFFFFFFFFFFFF
return UUID(most, least)
@staticmethod
def nameUUIDFromBytes(name: bytes) -> 'UUID':
u = _uuid.uuid3(_uuid.NAMESPACE_DNS, name.decode('utf-8', errors='replace'))
most = u.int >> 64
least = u.int & 0xFFFFFFFFFFFFFFFF
return UUID(most, least)
@staticmethod
def fromString(name: str) -> 'UUID':
u = _uuid.UUID(name)
most = u.int >> 64
least = u.int & 0xFFFFFFFFFFFFFFFF
return UUID(most, least)
def getMostSignificantBits(self) -> int:
return self._most_sig_bits
def getLeastSignificantBits(self) -> int:
return self._least_sig_bits
def version(self) -> int:
return self._uuid.version
def variant(self) -> int:
return self._uuid.variant
def timestamp(self) -> int:
if self.version() != 1:
raise UnsupportedOperationException("Not a time-based UUID")
return self._uuid.time
def clockSequence(self) -> int:
if self.version() != 1:
raise UnsupportedOperationException("Not a time-based UUID")
return self._uuid.clock_seq
def node(self) -> int:
if self.version() != 1:
raise UnsupportedOperationException("Not a time-based UUID")
return self._uuid.node
def compareTo(self, other: 'UUID') -> int:
return (self._uuid.int > other._uuid.int) - (self._uuid.int < other._uuid.int)
def equals(self, other) -> bool:
if isinstance(other, UUID):
return self._uuid == other._uuid
return False
def hashCode(self) -> int:
return hash(self._uuid) & 0x7FFFFFFF
def toString(self) -> str:
return str(self._uuid)
def __str__(self):
return str(self._uuid)
def __repr__(self):
return f"UUID({str(self._uuid)})"
# ============================================================
# StringTokenizer
# ============================================================
class StringTokenizer(Stub):
"""java.util.StringTokenizer — simple tokenizer"""
def __init__(self, s: str, delim: str = " \t\n\r\f", return_delims: bool = False):
super().__init__()
self._str = str(s)
self._delim = delim
self._return_delims = return_delims
self._tokens = self._tokenize()
self._index = 0
def _tokenize(self):
if self._return_delims:
tokens = []
buf = ""
for ch in self._str:
if ch in self._delim:
if buf:
tokens.append(buf)
buf = ""
tokens.append(ch)
else:
buf += ch
if buf:
tokens.append(buf)
return tokens
import re as _re
pattern = f"[{_re.escape(self._delim)}]+"
return [t for t in _re.split(pattern, self._str) if t]
def countTokens(self) -> int:
return len(self._tokens)
def hasMoreTokens(self) -> bool:
return self._index < len(self._tokens)
def nextToken(self, delim: str = None) -> str:
if delim is not None:
self._delim = delim
remaining = self._str[self._index:]
st = StringTokenizer(remaining, delim, self._return_delims)
self._tokens = st._tokens
self._index = 0
if not self.hasMoreTokens():
raise NoSuchElementException()
tok = self._tokens[self._index]
self._index += 1
return tok
def hasMoreElements(self) -> bool:
return self.hasMoreTokens()
def nextElement(self):
return self.nextToken()
def __iter__(self):
return self
def __next__(self):
if not self.hasMoreTokens():
raise StopIteration
return self.nextToken()
# ============================================================
# Optional
# ============================================================
class Optional(Stub):
"""java.util.Optional — wraps value or None"""
def __init__(self, value=None):
super().__init__()
self._value = value
@staticmethod
def empty() -> 'Optional':
return Optional(None)
@staticmethod
def of(value) -> 'Optional':
if value is None:
raise TypeError("value is null")
return Optional(value)
@staticmethod
def ofNullable(value) -> 'Optional':
return Optional(value)
def get(self):
if self._value is None:
raise NoSuchElementException("No value present")
return self._value
def isPresent(self) -> bool:
return self._value is not None
def isEmpty(self) -> bool:
return self._value is None
def ifPresent(self, consumer) -> None:
if self._value is not None:
consumer(self._value)
def ifPresentOrElse(self, action, empty_action) -> None:
if self._value is not None:
action(self._value)
else:
empty_action()
def filter(self, predicate) -> 'Optional':
if self._value is None:
return self
return Optional.ofNullable(self._value) if predicate(self._value) else Optional.empty()
def map(self, mapper) -> 'Optional':
if self._value is None:
return Optional.empty()
return Optional.ofNullable(mapper(self._value))
def flatMap(self, mapper) -> 'Optional':
if self._value is None:
return Optional.empty()
return mapper(self._value)
def orElse(self, other):
return self._value if self._value is not None else other
def orElseGet(self, supplier):
if self._value is not None:
return self._value
return supplier()
def orElseThrow(self, exception_supplier=None):
if self._value is not None:
return self._value
if exception_supplier:
raise exception_supplier()
raise NoSuchElementException("No value present")
def stream(self):
if self._value is not None:
return [self._value]
return []
def equals(self, other) -> bool:
if isinstance(other, Optional):
return self._value == other._value
return False
def hashCode(self) -> int:
return hash(self._value) & 0x7FFFFFFF if self._value is not None else 0
def toString(self) -> str:
if self._value is None:
return "Optional.empty"
return f"Optional[{self._value}]"
def __str__(self):
return self.toString()
def __repr__(self):
return self.toString()
def __bool__(self):
return self._value is not None
# ============================================================
# Random
# ============================================================
class Random(Stub):
"""java.util.Random — wraps Python random module"""
def __init__(self, seed: _typing.Optional[int] = None):
super().__init__()
self._rng = _py_random.Random(seed)
def setSeed(self, seed: int) -> None:
self._rng.seed(seed)
def nextInt(self, bound: _typing.Optional[int] = None) -> int:
if bound is None:
return self._rng.randint(-2147483648, 2147483647)
if bound <= 0:
raise IllegalArgumentException("bound must be positive")
return self._rng.randrange(0, bound)
def nextLong(self) -> int:
return (self._rng.randint(-2147483648, 2147483647) << 32) | self._rng.randint(0, 0xFFFFFFFF)
def nextBoolean(self) -> bool:
return self._rng.random() < 0.5
def nextFloat(self) -> float:
return self._rng.random()
def nextDouble(self) -> float:
return self._rng.random()
def nextGaussian(self) -> float:
return self._rng.gauss(0.0, 1.0)
def nextBytes(self, bytes_arr: bytearray) -> None:
for i in range(len(bytes_arr)):
bytes_arr[i] = self._rng.randint(0, 255)
def next(self, bits: int) -> int:
return self._rng.getrandbits(bits) & ((1 << bits) - 1)
@staticmethod
def create() -> 'Random':
return Random()
# ============================================================
# Properties
# ============================================================
class Properties(HashMap):
"""java.util.Properties — extends Hashtable-like dict with load/store"""
def __init__(self, defaults: 'Properties' = None):
super().__init__()
self._defaults = defaults
def setProperty(self, key: str, value: str) -> None:
self.put(str(key), str(value))
def getProperty(self, key: str, default_value: str = None) -> _typing.Optional[str]:
val = self._data.get(str(key))
if val is not None:
return str(val)
if self._defaults is not None:
return self._defaults.getProperty(key, default_value)
return default_value
def load(self, in_stream) -> None:
if isinstance(in_stream, (str, bytes)):
lines = in_stream.splitlines() if isinstance(in_stream, str) else in_stream.decode('utf-8').splitlines()
else:
lines = in_stream.read().splitlines() if hasattr(in_stream, 'read') else in_stream.splitlines()
for line in lines:
line = line.strip()
if not line or line.startswith('#') or line.startswith('!'):
continue
if '=' in line:
key, val = line.split('=', 1)
elif ':' in line:
key, val = line.split(':', 1)
else:
key = line
val = ""
key = key.strip()
val = val.strip()
self._data[key] = val
def store(self, out_stream, comments: str = None) -> None:
lines = []
if comments:
lines.append(f"#{comments}")
lines.append(f"# {_datetime.datetime.now().isoformat()}")
for k, v in self._data.items():
escaped_val = str(v).replace("\\", "\\\\").replace(" ", "\\ ")
lines.append(f"{k}={escaped_val}")
content = "\n".join(lines) + "\n"
if isinstance(out_stream, _io.IOBase):
out_stream.write(content)
else:
out_stream.write(content) # type: ignore
def list(self, out_stream) -> None:
for k, v in self._data.items():
out_stream.write(f"{k}={v}\n")
def propertyNames(self):
return Iterator(self._data.keys())
def stringPropertyNames(self) -> set:
names = set()
for k in self._data.keys():
if isinstance(k, str):
names.add(k)
if self._defaults:
names.update(self._defaults.stringPropertyNames())
return names
def loadFromXML(self, in_stream) -> None:
import xml.etree.ElementTree as _ET
tree = _ET.parse(in_stream)
root = tree.getroot()
for entry in root.findall('entry'):
key = entry.get('key', '')
self._data[key] = entry.text or ''
def storeToXML(self, out_stream, comment: str = None) -> None:
import xml.etree.ElementTree as _ET
root = _ET.Element('properties')
if comment:
c = _ET.SubElement(root, 'comment')
c.text = comment
for k, v in self._data.items():
entry = _ET.SubElement(root, 'entry')
entry.set('key', str(k))
entry.text = str(v)
tree = _ET.ElementTree(root)
tree.write(out_stream, xml_declaration=True, encoding='UTF-8')
def get(self, key):
val = self._data.get(key)
if val is not None:
return val
return self._defaults.get(key) if self._defaults else None
def put(self, key, value):
return super().put(str(key), str(value))
def toString(self) -> str:
items = ", ".join(f"{k}={v}" for k, v in self._data.items())
return f"{{{items}}}"
# ============================================================
# EnumSet
# ============================================================
class EnumSet(HashSet):
"""java.util.EnumSet — simple implementation using set"""
def __init__(self, c=None):
super().__init__()
self._element_type = None
if c is not None:
if isinstance(c, EnumSet):
self._data = set(c._data)
self._element_type = c._element_type
elif isinstance(c, type):
self._element_type = c
elif isinstance(c, _IterableABC):
for item in c:
self._data.add(item)
if self._element_type is None:
self._element_type = item.__class__
@staticmethod
def allOf(element_type) -> 'EnumSet':
es = EnumSet()
es._element_type = element_type
if hasattr(element_type, '_values'):
for v in element_type._values():
es._data.add(v)
elif hasattr(element_type, '__members__'):
for name, member in element_type.__members__.items():
es._data.add(member)
return es
@staticmethod
def noneOf(element_type) -> 'EnumSet':
es = EnumSet()
es._element_type = element_type
return es
@staticmethod
def range(element_type, from_val, to_val) -> 'EnumSet':
es = EnumSet()
es._element_type = element_type
started = False
if hasattr(element_type, '_values'):
for v in element_type._values():
if v == from_val:
started = True
if started:
es._data.add(v)
if v == to_val:
break
elif hasattr(element_type, '__members__'):
for name, member in element_type.__members__.items():
if member == from_val:
started = True
if started:
es._data.add(member)
if member == to_val:
break
return es
@staticmethod
def copyOf(es) -> 'EnumSet':
return EnumSet(es)
def complementOf(self, other: 'EnumSet') -> 'EnumSet':
result = EnumSet.noneOf(self._element_type)
if self._element_type and hasattr(self._element_type, '_values'):
for v in self._element_type._values():
if v not in other._data:
result._data.add(v)
return result
# ============================================================
# EnumMap
# ============================================================
class EnumMap(HashMap):
"""java.util.EnumMap — simple implementation using dict"""
def __init__(self, key_type=None, m=None):
super().__init__()
self._key_type = key_type
if m is not None:
if isinstance(m, EnumMap):
self._data.update(m._data)
self._key_type = m._key_type
elif isinstance(m, dict):
self._data.update(m)
else:
for k, v in m.items():
self._data[k] = v
def put(self, key, value):
if self._key_type is None:
self._key_type = key.__class__
return super().put(key, value)
def keySet(self):
return set(self._data.keys())
# ============================================================
# Objects
# ============================================================
class Objects:
"""java.util.Objects — static helper methods"""
@staticmethod
def equals(a, b) -> bool:
return a == b
@staticmethod
def deepEquals(a, b) -> bool:
return _deep_eq(a, b)
@staticmethod
def hashCode(o) -> int:
return 0 if o is None else (hash(o) & 0x7FFFFFFF)
@staticmethod
def hash(*values) -> int:
return Arrays.hashCode(values)
@staticmethod
def toString(o, null_default: str = "null") -> str:
if o is None:
return null_default
return str(o)
@staticmethod
def compare(a, b, cmp) -> int:
if cmp:
return cmp(a, b)
return (a > b) - (a < b)
@staticmethod
def requireNonNull(obj, message: Any = None):
if obj is None:
if message is None:
raise TypeError("null")
raise TypeError(str(message) if not callable(message) else message.get())
return obj
@staticmethod
def nonNull(obj) -> bool:
return obj is not None
@staticmethod
def isNull(obj) -> bool:
return obj is None
@staticmethod
def requireNonNullElse(obj, default):
return obj if obj is not None else default
@staticmethod
def requireNonNullElseGet(obj, supplier):
return obj if obj is not None else supplier()
@staticmethod
def checkIndex(index: int, length: int) -> int:
if index < 0 or index >= length:
raise IndexError(f"Index {index} out of bounds [0, {length})")
return index
@staticmethod
def checkFromToIndex(from_index: int, to_index: int, length: int) -> int:
if from_index < 0 or from_index > to_index or to_index > length:
raise IndexError(f"Range [{from_index}, {to_index}) out of bounds [0, {length})")
return from_index
@staticmethod
def checkFromIndexSize(from_index: int, size: int, length: int) -> int:
if from_index < 0 or size < 0 or from_index + size > length:
raise IndexError(f"Range [{from_index}, {from_index + size}) out of bounds [0, {length})")
return from_index
# ============================================================
# Locale
# ============================================================
class Locale(Stub):
"""java.util.Locale — basic locale representation"""
ENGLISH = None
FRENCH = None
GERMAN = None
ITALIAN = None
JAPANESE = None
KOREAN = None
CHINESE = None
SIMPLIFIED_CHINESE = None
TRADITIONAL_CHINESE = None
FRANCE = None
GERMANY = None
ITALY = None
JAPAN = None
KOREA = None
CHINA = None
UK = None
US = None
CANADA = None
CANADA_FRENCH = None
ROOT = None
def __init__(self, language: str = "", country: str = "", variant: str = ""):
super().__init__()
self._language = language
self._country = country
self._variant = variant
@staticmethod
def getDefault() -> 'Locale':
return Locale("en", "US")
@staticmethod
def setDefault(locale: 'Locale') -> None:
pass
def getLanguage(self) -> str:
return self._language
def getCountry(self) -> str:
return self._country
def getVariant(self) -> str:
return self._variant
def getDisplayLanguage(self, locale: 'Locale' = None) -> str:
return self._language
def getDisplayCountry(self, locale: 'Locale' = None) -> str:
return self._country
def getDisplayName(self, locale: 'Locale' = None) -> str:
parts = [self._language]
if self._country:
parts.append(self._country)
if self._variant:
parts.append(self._variant)
return "_".join(parts)
def toString(self) -> str:
return self.getDisplayName()
def toLanguageTag(self) -> str:
tag = self._language
if self._country:
tag += "-" + self._country
if self._variant:
tag += "-" + self._variant
return tag
@staticmethod
def forLanguageTag(tag: str) -> 'Locale':
parts = tag.replace("-", "_").split("_")
lang = parts[0] if len(parts) > 0 else ""
country = parts[1] if len(parts) > 1 else ""
variant = parts[2] if len(parts) > 2 else ""
return Locale(lang, country, variant)
def equals(self, other) -> bool:
if isinstance(other, Locale):
return (self._language == other._language and
self._country == other._country and
self._variant == other._variant)
return False
def hashCode(self) -> int:
return hash((self._language, self._country, self._variant)) & 0x7FFFFFFF
# Initialize Locale constants
Locale.ENGLISH = Locale("en")
Locale.FRENCH = Locale("fr")
Locale.GERMAN = Locale("de")
Locale.ITALIAN = Locale("it")
Locale.JAPANESE = Locale("ja")
Locale.KOREAN = Locale("ko")
Locale.CHINESE = Locale("zh")
Locale.SIMPLIFIED_CHINESE = Locale("zh", "CN")
Locale.TRADITIONAL_CHINESE = Locale("zh", "TW")
Locale.FRANCE = Locale("fr", "FR")
Locale.GERMANY = Locale("de", "DE")
Locale.ITALY = Locale("it", "IT")
Locale.JAPAN = Locale("ja", "JP")
Locale.KOREA = Locale("ko", "KR")
Locale.CHINA = Locale("zh", "CN")
Locale.UK = Locale("en", "GB")
Locale.US = Locale("en", "US")
Locale.CANADA = Locale("en", "CA")
Locale.CANADA_FRENCH = Locale("fr", "CA")
Locale.ROOT = Locale("", "")
# ============================================================
# BitSet
# ============================================================
class BitSet(Stub):
"""java.util.BitSet — bit manipulation"""
def __init__(self, nbits: int = 0):
super().__init__()
if isinstance(nbits, int):
self._bits = 0
elif isinstance(nbits, BitSet):
self._bits = nbits._bits
else:
self._bits = 0
def _check(self, bit_index: int) -> None:
if bit_index < 0:
raise IndexError(f"bitIndex < 0: {bit_index}")
def get(self, bit_index: int) -> bool:
self._check(bit_index)
return bool((self._bits >> bit_index) & 1)
def getRange(self, from_index: int, to_index: int) -> 'BitSet':
self._check(from_index)
mask = ((1 << (to_index - from_index)) - 1) << from_index
result = BitSet()
result._bits = (self._bits & mask) >> from_index
return result
def set(self, bit_index: int, value: bool = True) -> None:
self._check(bit_index)
if value:
self._bits |= (1 << bit_index)
else:
self._bits &= ~(1 << bit_index)
def setRange(self, from_index: int, to_index: int, value: bool = True) -> None:
self._check(from_index)
mask = ((1 << (to_index - from_index)) - 1) << from_index
if value:
self._bits |= mask
else:
self._bits &= ~mask
def clear(self, bit_index: int = None) -> None:
if bit_index is None:
self._bits = 0
else:
self._check(bit_index)
self._bits &= ~(1 << bit_index)
def clearRange(self, from_index: int, to_index: int) -> None:
self.setRange(from_index, to_index, False)
def flip(self, bit_index: int) -> None:
self._check(bit_index)
self._bits ^= (1 << bit_index)
def flipRange(self, from_index: int, to_index: int) -> None:
self._check(from_index)
mask = ((1 << (to_index - from_index)) - 1) << from_index
self._bits ^= mask
def cardinality(self) -> int:
return self._bits.bit_count()
def intersects(self, bs: 'BitSet') -> bool:
return (self._bits & bs._bits) != 0
def and_(self, bs: 'BitSet') -> None:
self._bits &= bs._bits
def or_(self, bs: 'BitSet') -> None:
self._bits |= bs._bits
def xor(self, bs: 'BitSet') -> None:
self._bits ^= bs._bits
def andNot(self, bs: 'BitSet') -> None:
self._bits &= ~bs._bits
def size(self) -> int:
return self._bits.bit_length() + (8 - (self._bits.bit_length() % 8)) % 8
def length(self) -> int:
return self._bits.bit_length()
def isEmpty(self) -> bool:
return self._bits == 0
def nextSetBit(self, from_index: int) -> int:
self._check(from_index)
bits = self._bits >> from_index
if bits == 0:
return -1
return (bits & -bits).bit_length() - 1 + from_index
def nextClearBit(self, from_index: int) -> int:
self._check(from_index)
bits = ~(self._bits >> from_index)
if bits == 0:
return -1
return (bits & -bits).bit_length() - 1 + from_index
def previousSetBit(self, from_index: int) -> int:
if from_index < 0:
return -1
mask = (1 << (from_index + 1)) - 1
bits = self._bits & mask
if bits == 0:
return -1
return bits.bit_length() - 1
def previousClearBit(self, from_index: int) -> int:
if from_index < 0:
return -1
mask = (1 << (from_index + 1)) - 1
bits = (~self._bits) & mask
if bits == 0:
return -1
return bits.bit_length() - 1
def toByteArray(self) -> bytearray:
if self._bits == 0:
return bytearray()
n_bytes = (self._bits.bit_length() + 7) // 8
return bytearray(self._bits.to_bytes(n_bytes, 'little'))
def toLongArray(self) -> list:
if self._bits == 0:
return []
n_longs = (self._bits.bit_length() + 63) // 64
result = []
for i in range(n_longs):
result.append((self._bits >> (i * 64)) & 0xFFFFFFFFFFFFFFFF)
return result
@staticmethod
def valueOf(bytes_or_longs) -> 'BitSet':
bs = BitSet()
if isinstance(bytes_or_longs, (bytes, bytearray)):
bs._bits = int.from_bytes(bytes_or_longs, 'little')
elif isinstance(bytes_or_longs, list):
for i, v in enumerate(bytes_or_longs):
bs._bits |= (v & 0xFFFFFFFFFFFFFFFF) << (i * 64)
return bs
def stream(self):
bits = []
i = 0
while True:
idx = self.nextSetBit(i)
if idx < 0:
break
bits.append(idx)
i = idx + 1
return bits
def equals(self, other) -> bool:
if isinstance(other, BitSet):
return self._bits == other._bits
return False
def hashCode(self) -> int:
return hash(self._bits) & 0x7FFFFFFF
def toString(self) -> str:
bits = []
i = 0
while True:
idx = self.nextSetBit(i)
if idx < 0:
break
bits.append(str(idx))
i = idx + 1
return "{" + ", ".join(bits) + "}"
def clone(self) -> 'BitSet':
return BitSet(self)
def __repr__(self):
return self.toString()
def __eq__(self, other):
return self.equals(other)
# ============================================================
# PriorityQueue
# ============================================================
class PriorityQueue(Stub):
"""java.util.PriorityQueue — using heapq"""
def __init__(self, initial_capacity: Any = None, comparator=None):
super().__init__()
self._heap: list = []
self._comparator = comparator
if initial_capacity is not None and not isinstance(initial_capacity, (int, float)):
if isinstance(initial_capacity, _IterableABC):
for item in initial_capacity:
self._heap.append(item)
if comparator:
self._heap.sort(key=comparator)
else:
self._heap.sort()
def _wrap_key(self, obj):
if self._comparator:
return (self._comparator(obj), obj)
return obj
def add(self, obj) -> bool:
_heapq.heappush(self._heap, self._wrap_key(obj))
return True
def offer(self, obj) -> bool:
return self.add(obj)
def peek(self):
return self._heap[0][1] if self._heap and self._comparator else (self._heap[0] if self._heap else None)
def element(self):
val = self.peek()
if val is None:
raise NoSuchElementException()
return val
def poll(self):
if not self._heap:
return None
val = _heapq.heappop(self._heap)
return val[1] if self._comparator else val
def remove(self, obj) -> bool:
if self._comparator:
wrapped = self._wrap_key(obj)
for i, v in enumerate(self._heap):
if v == wrapped:
self._heap[i] = self._heap[-1]
self._heap.pop()
_heapq.heapify(self._heap)
return True
else:
for i, v in enumerate(self._heap):
if v == obj:
self._heap[i] = self._heap[-1]
self._heap.pop()
_heapq.heapify(self._heap)
return True
return False
def size(self) -> int:
return len(self._heap)
def isEmpty(self) -> bool:
return len(self._heap) == 0
def clear(self) -> None:
self._heap.clear()
def comparator(self):
return self._comparator
def iterator(self) -> Iterator:
return Iterator(list(self._heap))
def toArray(self, a=None):
if self._comparator:
items = sorted([v[1] for v in self._heap], key=self._comparator)
else:
items = sorted(self._heap)
if a is None:
return items
return items[:len(a)]
def forEach(self, action) -> None:
for item in list(self._heap):
action(item)
def toString(self) -> str:
items = ", ".join(str(x) for x in self._heap)
return f"[{items}]"
def __len__(self):
return len(self._heap)
def __repr__(self):
return self.toString()
# ============================================================
# Vector
# ============================================================
class Vector(Stub):
"""java.util.Vector — synchronized list"""
def __init__(self, initial_capacity: Any = None, capacity_increment: int = 0):
super().__init__()
if initial_capacity is None:
self._data = []
elif isinstance(initial_capacity, int):
self._data = []
elif isinstance(initial_capacity, _IterableABC):
self._data = list(initial_capacity)
else:
self._data = []
self._capacity_increment = capacity_increment
self._lock = _threading.Lock()
def _synchronized(self, func, *args, **kwargs):
with self._lock:
return func(*args, **kwargs)
def add(self, obj) -> bool:
with self._lock:
self._data.append(obj)
return True
def addAt(self, index: int, obj) -> None:
with self._lock:
self._data.insert(index, obj)
def addAll(self, c) -> bool:
with self._lock:
if isinstance(c, Vector):
self._data.extend(c._data)
else:
self._data.extend(c)
return True
def addAllAt(self, index: int, c) -> bool:
with self._lock:
if isinstance(c, Vector):
self._data[index:index] = c._data
else:
self._data[index:index] = list(c)
return True
def addElement(self, obj) -> None:
self.add(obj)
def capacity(self) -> int:
with self._lock:
return len(self._data)
def clear(self) -> None:
with self._lock:
self._data.clear()
def clone(self) -> 'Vector':
with self._lock:
return Vector(self._data)
def contains(self, obj) -> bool:
with self._lock:
return obj in self._data
def containsAll(self, c) -> bool:
with self._lock:
if isinstance(c, Vector):
return all(x in self._data for x in c._data)
return all(x in self._data for x in c)
def copyInto(self, an_array: list) -> None:
with self._lock:
for i, v in enumerate(self._data):
an_array[i] = v
def elementAt(self, index: int):
with self._lock:
return self._data[index]
def elements(self) -> Enumeration:
with self._lock:
return Enumeration(list(self._data))
def ensureCapacity(self, min_capacity: int) -> None:
pass
def firstElement(self):
with self._lock:
if not self._data:
raise NoSuchElementException()
return self._data[0]
def forEach(self, action) -> None:
with self._lock:
for item in list(self._data):
action(item)
def get(self, index: int):
with self._lock:
return self._data[index]
def indexOf(self, obj, index: int = 0) -> int:
with self._lock:
try:
return self._data.index(obj, index)
except ValueError:
return -1
def insertElementAt(self, obj, index: int) -> None:
with self._lock:
self._data.insert(index, obj)
def isEmpty(self) -> bool:
with self._lock:
return len(self._data) == 0
def iterator(self) -> Iterator:
with self._lock:
return Iterator(list(self._data))
def lastElement(self):
with self._lock:
if not self._data:
raise NoSuchElementException()
return self._data[-1]
def lastIndexOf(self, obj, index: int = None) -> int:
with self._lock:
if index is None:
index = len(self._data) - 1
for i in range(index, -1, -1):
if self._data[i] == obj:
return i
return -1
def listIterator(self, index: int = 0) -> ListIterator:
with self._lock:
li = ListIterator(list(self._data))
li._index = index
return li
def remove(self, obj) -> bool:
with self._lock:
if obj in self._data:
self._data.remove(obj)
return True
return False
def removeAt(self, index: int):
with self._lock:
return self._data.pop(index)
def removeAll(self, c) -> bool:
with self._lock:
if isinstance(c, Vector):
items = c._data
else:
items = list(c)
old_len = len(self._data)
self._data = [x for x in self._data if x not in items]
return len(self._data) != old_len
def removeAllElements(self) -> None:
with self._lock:
self._data.clear()
def removeElement(self, obj) -> bool:
return self.remove(obj)
def removeElementAt(self, index: int) -> None:
with self._lock:
self._data.pop(index)
def removeIf(self, predicate) -> bool:
with self._lock:
old_len = len(self._data)
self._data = [x for x in self._data if not predicate(x)]
return len(self._data) != old_len
def replaceAll(self, operator) -> None:
with self._lock:
self._data = [operator(x) for x in self._data]
def retainAll(self, c) -> bool:
with self._lock:
if isinstance(c, Vector):
items = set(c._data)
else:
items = set(c)
old_len = len(self._data)
self._data = [x for x in self._data if x in items]
return len(self._data) != old_len
def set(self, index: int, obj):
with self._lock:
old = self._data[index]
self._data[index] = obj
return old
def setElementAt(self, obj, index: int) -> None:
with self._lock:
self._data[index] = obj
def setSize(self, new_size: int) -> None:
with self._lock:
while len(self._data) < new_size:
self._data.append(None)
while len(self._data) > new_size:
self._data.pop()
def size(self) -> int:
with self._lock:
return len(self._data)
def sort(self, key=None, reverse: bool = False) -> None:
with self._lock:
self._data.sort(key=key, reverse=reverse)
def subList(self, from_index: int, to_index: int) -> 'Vector':
with self._lock:
return Vector(self._data[from_index:to_index])
def toArray(self, a=None):
with self._lock:
if a is None:
return list(self._data)
if len(a) < len(self._data):
return list(self._data)
for i, v in enumerate(self._data):
a[i] = v
if len(self._data) < len(a):
a[len(self._data)] = None
return a
def toString(self) -> str:
with self._lock:
items = ", ".join(str(x) for x in self._data)
return f"[{items}]"
def trimToSize(self) -> None:
pass
def __len__(self):
with self._lock:
return len(self._data)
def __getitem__(self, idx):
with self._lock:
return self._data[idx]
def __setitem__(self, idx, val):
with self._lock:
self._data[idx] = val
def __delitem__(self, idx):
with self._lock:
del self._data[idx]
def __iter__(self):
with self._lock:
return iter(list(self._data))
def __repr__(self):
return self.toString()
def __contains__(self, obj):
with self._lock:
return obj in self._data
def __eq__(self, other):
if isinstance(other, Vector):
with self._lock:
return self._data == other._data
return False
# ============================================================
# Stack
# ============================================================
class Stack(Vector):
"""java.util.Stack — extends Vector"""
def __init__(self):
super().__init__()
def push(self, item):
with self._lock:
self._data.append(item)
return item
def pop(self):
with self._lock:
if not self._data:
raise EmptyStackException()
return self._data.pop()
def peek(self):
with self._lock:
if not self._data:
raise EmptyStackException()
return self._data[-1]
def empty(self) -> bool:
with self._lock:
return len(self._data) == 0
def search(self, obj) -> int:
with self._lock:
try:
idx = len(self._data) - 1 - self._data[::-1].index(obj)
return len(self._data) - idx
except ValueError:
return -1
def add(self, obj) -> bool:
self.push(obj)
return True
def remove(self, obj) -> bool:
with self._lock:
if obj in self._data:
self._data.remove(obj)
return True
return False