Everybody else handles dependencies like npm, e.g. installs the latest versions that satisfy constraints. Some package managers have the ability to install from a lock file (e.g. Python's Poetry, Python's Pipenv, Rust's Cargo, npm) but will still grab the latest version when the lockfile doesn't exists (e.g. cloned a project with no lock file, or just added the dependency yourself), and have a command to update which updates every single package to the latest compatible versions.
You can argue that npm's commands are poorly named and guide users towards bad defaults, but saying that it works in a unique way is not true.
I guess my experience is limited. For example, maven dependencies usually specify the exact version required in the pom files. At least, on all the projects I've ever dealt with.
I’ve seen plenty of pom.xml files which are unversioned — not having a standard command to update means less disciplined developers say it’s too much work – but increasingly in other languages (and Gradle IIRC) there’s a distinction between the metadata file listing your direct dependencies and a lock file detailing exactly what was installed. The idea is that (using Node as an example) I’d say “I depend on the AWS SDK” in the main file, which changes infrequently when I add or remove direct dependencies, but my tool would use the lock file (npm-shrinkwrap) to record the exact versions of every package, preferably even by file hash, so you can have a highly repeatable build.
Separating the two is handy both due to frequent churn and to avoid transitive dependencies being kept unnecessarily — I’ve seen projects where libfoo stopped depending on libbar a while back but they were still installing it because someone had copy-pasted that block years before and was just incrementing the version.
You can argue that npm's commands are poorly named and guide users towards bad defaults, but saying that it works in a unique way is not true.