はじめに
「PythonもJavaも勉強しているけど、なんで同じことをするのに書き方がこんなに違うの?」
この疑問、とても本質的です。
書き方が違うのには ちゃんと理由があります。
その理由を知ると、どちらの言語も「なるほど、そういう設計なんだ」と納得できるようになります。
この記事では文法の違いだけでなく、
「なぜそういう設計になっているのか」という仕組みと原理原則まで
図解で丁寧に解説します。
この記事で学べること
PART 1 そもそもプログラミング言語って何?
PART 2 PythonとJavaの「生まれた目的」の違い
PART 3 コードが動く仕組みの違い(コンパイル vs インタープリター)
PART 4 型の違い(静的型付け vs 動的型付け)
PART 5 文法の違いを仕組みから理解する
PART 6 クラスとオブジェクト指向の違い
PART 7 エラーの種類と対処法の違い
PART 8 どちらをどう使うか 選び方の原則
PART 1 そもそもプログラミング言語って何?
コンピューターは「0と1しかわからない」
人間が話す言語
「ねえ、1足す1は何?」
↕ 翻訳が必要
コンピューターが理解できる言語
01001000 01100101 01101100 01101100 01101111
(0と1の組み合わせだけ)
コンピューターは電気のON/OFFしか理解できません。
ON = 1、OFF = 0。これだけです。
プログラミング言語とは、
「人間が読める言葉でコンピューターへの命令を書けるように作られた言語」 です。
プログラミング言語の役割
┌──────────────────────────────────────────────────────────────┐
│ │
│ 人間が書いたコード(英語に近い) │
│ print("Hello") │
│ name = "田中花子" │
│ │
│ │ プログラミング言語が翻訳 │
│ ▼ │
│ │
│ 機械語(コンピューターが理解できる) │
│ 01001000 01100101 01101100 01101100 01101111 │
│ │
│ │ CPUが実行 │
│ ▼ │
│ │
│ 結果が出る │
│ Hello │
│ │
└──────────────────────────────────────────────────────────────┘
PART 2 PythonとJavaの「生まれた目的」の違い
Pythonの生い立ち
┌────────────────────────────────────────────────────────────┐
│ Python の誕生 │
│ │
│ 1991年 グイド・ヴァン・ロッサムが開発 │
│ │
│ 目的:「誰でも読めて・書けて・すぐ動かせる言語」を作りたい │
│ │
│ 設計思想: │
│ ・シンプルで美しいコードを書けること │
│ ・読みやすさを最優先すること │
│ ・「動かすことに集中できる言語」であること │
│ │
│ 名前の由来:モンティ・パイソン(イギリスのコメディグループ) │
└────────────────────────────────────────────────────────────┘
Javaの生い立ち
┌────────────────────────────────────────────────────────────┐
│ Java の誕生 │
│ │
│ 1995年 サン・マイクロシステムズ(現Oracle)が開発 │
│ │
│ 目的:「どのOS・機器でも動く信頼性の高い言語」を作りたい │
│ │
│ 設計思想: │
│ ・"Write Once, Run Anywhere"(一度書けばどこでも動く) │
│ ・大規模システムでも安全に動かせること │
│ ・型を厳密にチェックしてバグを防ぐこと │
│ │
│ 名前の由来:コーヒー(Javaはインドネシアのコーヒー産地) │
└────────────────────────────────────────────────────────────┘
生まれた目的の違いが「文法の違い」を生む
Python Java
目的 書きやすさ・読みやすさ 安全性・大規模開発・移植性
↓ ↓
文法の方向 シンプル・短く書ける 厳密・冗長だが安全
↓ ↓
型の扱い 動的(実行時に決まる) 静的(書くとき決める)
↓ ↓
クラス 必須ではない すべてクラスの中に書く
↓ ↓
向いている データ分析・AI・スクリプト 業務システム・Android・大規模開発
PART 3 コードが動く仕組みの違い
Pythonの動き方:インタープリター方式
【インタープリター方式:その場で通訳しながら進む】
あなたが書いたコード
┌──────────────────────────────────┐
│ name = "田中" │
│ print(name) │
│ age = 25 │
└──────────────────────────────────┘
│
│ python ファイル名.py で実行
▼
インタープリター(通訳者)
┌──────────────────────────────────┐
│ 1行目を読む → 翻訳 → 実行 │
│ 2行目を読む → 翻訳 → 実行 │
│ 3行目を読む → 翻訳 → 実行 │
│ ※ 1行ずつ翻訳しながら進む │
└──────────────────────────────────┘
│
▼
結果が出る
田中
✅ メリット:書いてすぐ動かせる(開発が速い)
❌ デメリット:実行速度はコンパイル型より遅め
Javaの動き方:コンパイル+JVM方式
【コンパイル方式:事前に全部翻訳してから実行する】
あなたが書いたコード(.java ファイル)
┌──────────────────────────────────┐
│ public class Hello { │
│ public static void main │
│ (String[] args) { │
│ System.out.println("Hello");│
│ } │
│ } │
└──────────────────────────────────┘
│
│ javac Hello.java(コンパイル)
▼
バイトコード(.class ファイル)
┌──────────────────────────────────┐
│ cafe babe 0000 003d 001d 0a00 │
│ (機械に近い中間形式。人間には │
│ 読めないが、どのOSでも動く) │
└──────────────────────────────────┘
│
│ java Hello(実行)
▼
JVM(Java仮想マシン)が実行
┌──────────────────────────────────┐
│ Windows の JVM でも動く │
│ Mac の JVM でも動く │
│ Linux の JVM でも動く │
│ ← これが "Write Once Run Anywhere" │
└──────────────────────────────────┘
│
▼
Hello
✅ メリット:速い・OS を問わず動く・事前にエラー検出
❌ デメリット:実行前にコンパイルが必要
2つの方式の比較
Python(インタープリター) Java(コンパイル+JVM)
─────────────────────────────────────────────────────────────
実行前の手順 なし(そのまま実行) コンパイル(javac)が必要
実行速度 比較的遅い 速い
エラー検出 実行してみないとわからない コンパイル時に一部検出できる
開発の速さ 速い(すぐ動かせる) やや手間がかかる
OS 依存 Pythonがインストールされた JVMがあればどこでも動く
環境が必要
PART 4 型の違い:最重要ポイント
「型」とは何か
型(Type)とは、「このデータは何種類のものか」を表すラベルです。
"田中花子" → 文字列型(String型)
25 → 整数型(int型)
198.5 → 小数型(double / float 型)
True / False → 真偽値型(boolean / bool 型)
Pythonは「動的型付け」
【動的型付け:変数に型ラベルを貼らない・実行時に自動判断】
name = "田中花子"
↑
「型を書かなくていい」
Pythonが実行時に「あ、これは文字列だな」と自動で判断する
# 同じ変数にあとから別の型を入れることもできる
x = 10 # 今は整数
x = "hello" # 今度は文字列
x = True # 今度は真偽値
→ 変数の型は実行するたびに変わることがある(柔軟)
→ その反面、予期しない型のデータが入ってもエラーにならないことがある
【型チェックの例】
def add(a, b):
return a + b
add(1, 2) # → 3(整数の足し算)
add("1", "2") # → "12"(文字列の連結!エラーにならない)
add(1, "2") # → エラー(実行してみて初めてわかる)
# 整数と文字列は足し算できないので実行時エラー
Javaは「静的型付け」
【静的型付け:変数に型ラベルを必ず貼る・書くときに決める】
String name = "田中花子";
↑↑↑↑↑↑
「ここに型を書く(必須)」
「このnameは文字列型として使います」と宣言する
int age = 25; // int型(整数)
double price = 198.5; // double型(小数)
// 別の型は入れられない(コンパイル時にエラーになる)
age = "hello"; // ← コンパイルエラー!intにStringは入れられない
【型チェックの例】
public static int add(int a, int b) {
return a + b;
}
add(1, 2); // → 3(OK)
add("1", "2"); // → コンパイルエラー!実行する前にエラー検出
// int型の引数にStringは渡せない
動的型付け vs 静的型付けの違い
┌──────────────────────────────────────────────────────────────┐
│ │
│ 動的型付け(Python) 静的型付け(Java) │
│ ───────────────────────────────────────────────────────── │
│ │
│ 型宣言 不要 必須 │
│ 型チェック 実行時 コンパイル時(実行前) │
│ 柔軟さ 高い 低い │
│ 安全性 低め(実行してみないと 高い(実行前にエラー検出) │
│ わからない) │
│ 書く量 少ない(短く書ける) 多い(型を全部書く) │
│ │
│ 向いている プロトタイプ・スクリプト 大規模システム・チーム開発 │
│ │
└──────────────────────────────────────────────────────────────┘
PART 5 文法の違いを仕組みから理解する
ブロックの表現方法:インデント vs {}
これは見た目の違いだけでなく、設計思想の違いです。
【Python:インデント(字下げ)でブロックを表現】
if score >= 80:
print("合格") ← スペース4つ分の字下げ
print("おめでとう") ← 同じ字下げ = 同じブロック
print("終わり") ← 字下げなし = ifの外
✅ 見た目がきれい・強制的に読みやすいコードになる
❌ スペースの数が違うとエラーになる(インデントに厳しい)
【Java:{ }(中括弧)でブロックを表現】
if (score >= 80) {
System.out.println("合格"); // { } の中 = ブロック内
System.out.println("おめでとう");
}
System.out.println("終わり"); // { } の外 = ブロック外
✅ インデントが揃ってなくてもエラーにはならない
❌ { } の対応が複雑なコードでは追いにくくなる
なぜPythonはインデントにしたのか
設計者ガイドの考え:
「どうせ人間はきれいにインデントするなら、
それをそのままブロックの区切りにしてしまおう。
{ } は見た目がうるさい。」
→ Pythonはインデント自体がプログラムの意味を持つ
→ きれいに書かないと動かない → 自然と読みやすいコードになる
文末のセミコロン
【なぜJavaは文末に ; が必要なのか】
System.out.println("Hello");
↑
この ; は「文の終わり」を表す
Javaは1つの命令が複数行にまたがることができる:
String message =
"とても長い" +
"文字列を" +
"複数行に分けて書く";
↑ ここが文の終わり
→ ; がないと「ここで文が終わった」とわからない
【なぜPythonは ; が不要なのか】
print("Hello") ← 改行が「文の終わり」を意味する
name = "田中"
→ Pythonは改行自体が文の区切り
→ ; は省略可(一行に複数の命令を書くときは ; で区切れるが非推奨)
クラスの必須性の違い
【なぜJavaはすべてクラスの中に書かなければいけないのか】
Java の設計思想:
「すべてのものはオブジェクトとして扱うべきだ」
→ 関数も変数もすべてクラスという入れ物の中に入れる
→ これにより、大規模開発で名前の衝突を防げる
// Java(クラスの外には何も書けない)
public class Main { ← クラスが必須
public static void main(...) {
System.out.println("Hello");
}
}
【なぜPythonはクラスなしで書けるのか】
Python の設計思想:
「シンプルに書ける方がいい。クラスは必要なときに使えばいい」
→ 関数をファイルの直接に書ける
→ スクリプト(小さなプログラム)に向いている
# Python(クラスなしで書ける)
print("Hello") ← これだけで動く
PART 6 クラスとオブジェクト指向の違い
コンストラクタの書き方が違う理由
【Python のコンストラクタ:__init__ という特殊メソッド名】
class Cat:
def __init__(self, name, color):
self.name = name
self.color = color
なぜ __init__ という名前?
→ init = initialize(初期化する)の略
→ __ (アンダースコア2つ)= Pythonが特別扱いするメソッドの印
→ Pythonはこの名前のメソッドをコンストラクタとして認識する
なぜ self が第一引数?
→ self = このオブジェクト自身を指す変数
→ Pythonは「メソッドを呼んだオブジェクト」を自動でselfに渡す
→ 書かないとエラーになる(省略不可)
【Java のコンストラクタ:クラスと同じ名前のメソッド】
public class Cat {
String name;
String color;
public Cat(String name, String color) { ← クラス名と同じ名前
this.name = name;
this.color = color;
}
}
なぜクラスと同じ名前?
→ Javaは「クラスと同じ名前のメソッドはコンストラクタ」というルール
→ 戻り値の型を書かない点が通常のメソッドと違う
なぜ this.name = name; と書くのか?
→ this = このオブジェクト自身(Pythonのselfと同じ意味)
→ this.name = フィールドのname
→ 右辺の name = 引数のname
→ 名前が同じなのでthisで区別する必要がある
selfとthisの違い
Python(self) Java(this)
─────────────────────────────────────────────────────────
意味 このオブジェクト自身 このオブジェクト自身
書き方 メソッドの第一引数に必須 省略可(自動)
なくていい 書かないとエラー 書かなくても動く(省略可)
呼び出し例 self.name this.name(またはname)
どちらも「自分自身のオブジェクトを指す」という意味は同じ。
書き方のルールが違うだけ。
privateとカプセル化の違い
【Java:private で強制的にアクセスを制限】
public class Cat {
private String name; ← privateは「このクラスの中だけ」
外からcat.nameとは書けない(コンパイルエラー)
public String getName() { ← getter:読む窓口
return name;
}
}
Cat cat = new Cat();
cat.name = "みけ"; // ← コンパイルエラー!privateなので触れない
cat.getName(); // ← OK。getterを通じてだけアクセスできる
【Python:慣習でアクセスを制限(強制力はない)】
class Cat:
def __init__(self, name):
self._name = name # _ 1つ:「外から直接触わないで」の慣習
# 技術的には触れてしまう(Pythonに完全なprivateはない)
cat = Cat("たま")
print(cat._name) # これは動く(慣習違反だが動く)
# __ 2つはより強い制限(名前修飾)
self.__name = name # __ 2つ:外から cat.__name では直接アクセスできない
【まとめ】
Javaは「制限してアクセスを禁止」という強制ルール
Pythonは「触わらないでという暗黙のサイン」という慣習ルール
PART 7 エラーの種類と対処法
エラーの種類
┌──────────────────────────────────────────────────────────────┐
│ エラーの3種類 │
├──────────────────────────────────────────────────────────────┤
│ │
│ ① 構文エラー(Syntax Error) │
│ コードの書き方が間違っている │
│ 例:: を忘れた / { } が対応していない │
│ → コードを実行する前に検出される │
│ │
│ ② 実行時エラー(Runtime Error / Exception) │
│ 書き方は正しいが実行中に問題が起きた │
│ 例:0で割った / Noneにアクセスした │
│ → コードを実行してみて初めてわかる │
│ │
│ ③ 論理エラー(Logic Error) │
│ エラーは出ないが結果が間違っている │
│ 例:>=を>にしてしまった / ループが1回多い │
│ → コンピューターはエラーと気づいてくれない(一番やっかい)│
│ │
└──────────────────────────────────────────────────────────────┘
PythonとJavaの主なエラーの違い
Python Java
─────────────────────────────────────────────────────────────
型エラー 実行時に発生 コンパイル時に検出(実行前)
TypeError コンパイルエラー
null/None AttributeError: NullPointerException
アクセス 'NoneType' has no (実行時)
attribute 'xxx'
配列範囲外 IndexError: ArrayIndexOutOfBoundsException
list index out of range (実行時)
0除算 ZeroDivisionError: ArithmeticException:
division by zero / by zero
(実行時) (実行時)
不正引数 ValueError IllegalArgumentException
(実行時) (実行時・コンパイル時)
ファイルなし FileNotFoundError FileNotFoundException
(実行時) (実行時)
エラーメッセージの読み方
【Python のエラーメッセージ】
Traceback (most recent call last): ← エラーの発生経緯
File "main.py", line 8, in calc ← main.pyの8行目
File "main.py", line 3, in add ← main.pyの3行目
ZeroDivisionError: division by zero ← エラーの種類:説明
読み方:
1. 最後の行「エラーの種類: 説明」を先に読む
2. 「File ~ line ~」でエラーが起きた場所を確認する
3. 一番下から上に向かって読む(最後に呼ばれた場所が一番下)
【Java のエラーメッセージ】
Exception in thread "main" ← どのスレッドで発生したか
java.lang.NullPointerException ← エラーの種類(完全修飾名)
at Cat.cry(Cat.java:12) ← Cat.javaの12行目
at Main.main(Main.java:5) ← Main.javaの5行目
読み方:Python と基本的に同じ。
at が続く部分(スタックトレース)を上から読む。
一番上が実際にエラーが起きた場所。
PART 8 どちらをどう使うか
向いている用途の違い
┌──────────────────────────────────────────────────────────────┐
│ Python が向いている用途 │
│ │
│ ✅ データ分析・機械学習・AI │
│ pandas・numpy・scikit-learn など強力なライブラリが豊富 │
│ │
│ ✅ スクリプト・自動化 │
│ ファイル操作・Web スクレイピング・定期実行など │
│ │
│ ✅ プロトタイプ(試作品) │
│ 書いてすぐ動かせる → アイデアを素早く試せる │
│ │
│ ✅ Web バックエンド(Django・Flask・FastAPI) │
│ │
│ ✅ プログラミング入門 │
│ シンプルな文法で学習コストが低い │
└──────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────┐
│ Java が向いている用途 │
│ │
│ ✅ 大規模業務システム │
│ 銀行・保険・ERPなど信頼性が求められるシステム │
│ │
│ ✅ Android アプリ開発 │
│ 長らく Android の公式言語(現在は Kotlin も主流) │
│ │
│ ✅ エンタープライズ Web バックエンド(Spring Framework) │
│ │
│ ✅ 長期保守が必要なシステム │
│ 型が厳密 → リファクタリング・チーム開発に強い │
│ │
│ ✅ 高パフォーマンスが必要なシステム │
│ JIT コンパイル(実行時最適化)で高速動作 │
└──────────────────────────────────────────────────────────────┘
選び方の原則
Q:新人エンジニアはどちらから学ぶべき?
A:目的による。
データ分析・AI に進みたい → Python から
業務システム開発に進みたい → Java から
どちらかわからない → Python から(学習コストが低い)
どちらを先に学んでも、
「概念(変数・条件分岐・ループ・クラス)」は同じ。
書き方が違うだけ。
1つをしっかり理解すると、もう1つは早く習得できる。
まとめ:違いの本質
┌──────────────────────────────────────────────────────────────┐
│ │
│ 仕組みの違い │
│ Python:インタープリター(その場で翻訳しながら実行) │
│ Java :コンパイル+JVM(事前翻訳→どこでも動く) │
│ │
│ 型の違い │
│ Python:動的型付け(実行時に自動判断・型宣言不要) │
│ Java :静的型付け(書くとき宣言・コンパイル時にチェック) │
│ │
│ 文法の違い │
│ Python:インデントでブロック / 文末;不要 / クラス任意 │
│ Java :{}でブロック / 文末;必須 / すべてクラスの中 │
│ │
│ 設計思想の違い │
│ Python:シンプル・読みやすさ優先・すぐ動かせる │
│ Java :安全性・大規模開発・どこでも動く │
│ │
│ これらの違いはすべて「生まれた目的の違い」から来ている。 │
│ どちらが優れているのではなく、向いている用途が違う。 │
│ │
└──────────────────────────────────────────────────────────────┘
| 項目 | Python | Java |
|---|---|---|
| 誕生 | 1991年 | 1995年 |
| 実行方式 | インタープリター | コンパイル+JVM |
| 型 | 動的型付け | 静的型付け |
| 型宣言 | 不要 | 必須 |
| ブロック | インデント | { } |
| 文末 | 不要 | ; 必須 |
| クラス | 任意 | 必須 |
| self/this | self(必須) | this(省略可) |
| コンストラクタ名 | __init__ |
クラス名と同じ |
| private | 慣習(_ または __) | 言語機能として強制 |
| 向いている用途 | データ分析・AI・自動化 | 業務システム・Android |
公式ドキュメント・参考リソース
Python 公式
- Python 公式サイト
- Python 公式ドキュメント(日本語)
- Python チュートリアル(日本語)
- PEP 8 ── Python コードスタイルガイド
- PEP 20 ── Python の設計思想(The Zen of Python)
Java 公式
学習リソース
- CS50(Harvard 大学・無料・日本語字幕あり)
- paiza ラーニング(日本語・Python/Java 対応)
- Teach Yourself CS(学習ロードマップ)
- roadmap.sh(Python / Java ロードマップ)
「なぜそう書くのか」がわかると、暗記ではなく理解でコードが書けるようになれるはず🌸