Learning Java coming from PHP (1)
Despite my almost 20 years of professional software development, I haven’t learnt a lot of programming languages (see my honest résumé). So far, it’s just been PHP and JavaScript (plus SQL, XSLT, and – back in the day – Object Pascal and Visual Basic).
Now I’m trying to teach myself some Java. This blog post lists differences between PHP and Java, from the perspective of a PHP developer just getting started with Java. (Please let me know if I got something wrong!)
Running “Hello World”
In PHP, you create a hello.php
file:
<?php
echo "Hello World\n";
… and simply run it:
$ php hello.php
In Java, almost everything is an object – even “Hello World” requires defining a class with a main()
method. Here’s a hello.java
file:
class HelloWorld {
public static void main(String args[]) {
System.out.println("Hello World");
}
}
And you need to run it in two steps:
$ javac hello.java && java HelloWorld
Java code must be compiled to bytecode first. That’s what the javac
invocation does, creating a .class
file for each class definition. The java
command runs the main classes’ file. (You should name the .java
file after the class – I didn’t do this to make that point.)
Variables
In PHP, variable names always start with $
, and you don’t declare a type:
$num = 5;
No dollar signs required in Java, but the type is:
int num = 5;
As a side effect, Java variable names can collide with reserved keywords. $default = 1
is fine in PHP, int default = 1
isn’t in Java.
Variable scope: PHP variables are available in the whole function regardless of how deeply nested they were declared:
for ($i = 0; $i < 10; $i++) { }
echo "i is $i\n"; // "i is 10"
Java uses block scope instead, i.e. variables only exist within the block they’re defined in:
for (int i = 0; i < 10; i++) { }
System.out.println("i is " + i); // compile error, i undefined
In PHP, all non-object variables (including arrays) are passed by value into methods, unless you prepend &
:
function changeMe($str, &$i, $ints) {
$str = "bye";
$i = 99;
$ints[0]=99;
}
$str = "hello";
$i = 42;
$ints = [42];
changeMe($str, $i, $ints);
echo $str . "\n"; // hello
echo $i . "\n"; // 99
echo $ints[0] . "\n"; // 42
Java passes all primitive types (int, double, char) and immutable objects (String, Integer, Double) by value. There’s no way to change that. Arrays are passed by reference since they’re objects. Example code:
static void changeMe(String str, Integer i, int[] ints) {
str = "bye";
i = 99;
ints[0]=99;
}
String str = "hello";
Integer i = 42;
int[] ints = {42};
changeMe(str, i, ints);
System.out.println(str); // hello
System.out.println(i); // 42
System.out.println(ints[0]); // 99
Numbers
Java’s numeric type behaviour seems a bit weird initially. This division works as expected in PHP:
$num = 5 / 2; // $num is now 2.5
The result gets truncated in Java because 5 is an int
:
int num = 5 / 2; // num is now 2
That’s why it doesn’t help to try storing the result in a double
:
double num = 5 / 2; // num is now 2.0
Now it works:
double num = 5.0 / 2; // num is now 2.5
At least this code produces a compilation error “possible loss of precision”:
double a = 5, b = 2;
int num = a / b;
There’s object oriented wrappers for primitive types in Java, for example an Integer
class for int
.
Strings
In PHP, you can use either single or double quotes for strings. Only within double quotes, escape sequences (like \n
or \t
) or variables are interpreted. String concatenation in PHP uses the .
(dot) operator:
$str = 'Hello ' . "World 😎\n";
Java has a special primitive (not an object) type char
for a single character, enclosed in single quotes. String
values require double quotes. Concatenation is done with +
(plus):
char space = ' ';
String str = "Hello" + space + "World 😎\n";
While both PHP and the Java String
(but not char
) accept the Unicode emoji, PHP (with its mbstring extension) handles it better:
$len = mb_strlen("😎"); // 1
Java gets the length wrong:
int len = "😎".length(); // 2
PHP has tons of string functions, like strpos()
:
$pos = strpos('hello', 'll');
echo $pos . "\n"; // 2
The Java equivalent is String.indexOf()
:
int pos = "hello".indexOf("ll");
System.out.println(pos); // 2
Operators
In PHP you’ll often use ===
and !==
for exact comparison (to avoid trouble with 0 == ''
and the like):
$isEqual = ($a === $b);
There’s no need for this in (strongly-typed) Java, which simply uses ==
and !=
.
The logical operators for AND and OR in PHP are &&
and ||
. &
and |
exist, but are rarely-used bitwise operators. In Java, both forms are considered logical operators. In both languages, &&
and ||
are “short-circuit” operators evaluating from left to right and stopping when the result is clear:
int i = 0, j = 0;
if ((i > 0) && (++i > 0)) { }
if ((j > 0) & (++j > 0)) { }
// i is now 0, j is now 1
Program control
Java doesn’t have PHP’s elseif
, just use else if
.
Simple break
and continue
statements work the same, but breaking out of nested loops is done by specifying the number of levels in PHP:
while (true) {
while (true) {
break 2; // Break out of both loops
}
}
In Java, you’re using break
(or continue
) with a label instead:
top: { // label
while (true) {
while (true) {
break top; // Break to label
}
}
}
Arrays
PHP arrays are pretty versatile – growing as needed, arbitrary keys, mixed types, easily nested. It’s not really fair to compare Java arrays to them (maybe Java collections would be a better match).
Anyway, here’s a simple array in PHP:
$ages = [];
$ages[0] = 16;
In Java, you must use new
and specify the size of the array:
int[] ages = new int[4];
ages[0] = 16;
You can assign values during declaration in PHP:
$ages = [16, 12, 5, 4];
And in Java:
int[] ages = {16, 12, 5, 4};
Both int[] ages
and int ages[]
are valid syntax.
In PHP, you usually iterate over an array using foreach
:
$ages = [16, 12, 5, 4];
foreach ($ages as $key => $age) {
echo $age . "\n";
}
Java has a special form of for
for this, but it doesn’t support getting the key:
int[] ages = {16, 12, 5, 4};
for (int age: ages) {
System.out.println(age);
}
Classes
PHP class properties require a visibility keyword, methods are defined via function
. Members are accessed using ->
.
class Dog {
private $greeting = "Woof";
function getGreeting() {
return $this->greeting . ' ' . $this->greeting;
}
}
$dog = new Dog();
echo $dog->getGreeting() . "\n"; // Woof Woof
In Java, property visibility is optional. There is no keyword for methods. Members are accessed using the dot. this.
is optional within the class.
class Dog {
String greeting = "Woof";
String getGreeting() {
return greeting + ' ' + this.greeting;
}
}
Dog dog = new Dog();
System.out.println(dog.getGreeting()); // Woof Woof
Constructors are named __construct()
in PHP. Parent constructors are called through parent::__construct()
:
class PoliteGreeter extends Greeter {
protected $title;
public function __construct($title, $who) {
parent::__construct($who);
$this->title = $title;
}
}
In Java, the constructor is named after the class. To call a parent constructor, invoke super()
(which must be the first call in the constructor if present):
class PoliteGreeter extends Greeter {
String title;
PoliteGreeter(String title, String who) {
super(who);
this.title = title;
}
}
PHP methods can have default (optional) parameters:
class Greeter {
function greet($who = 'World') {
echo 'Hello ' . $who . "\n";
}
}
Java doesn’t have default parameters, but method overloading is pretty cool:
class Greeter {
void greet(String who) {
System.out.println("Hello " + who);
}
void greet() {
this.greet("World");
}
}
Nested classes are another Java feature not available in PHP (used here as a workaround for passing primitive variables by reference):
class ByRefExample {
class ByRefParams {
String str;
Integer i;
}
void changeMe(ByRefParams params) {
params.str = "bye";
params.i = 99;
}
public void run() {
ByRefParams params = new ByRefParams();
params.str = "hello";
params.i = 42;
changeMe(params);
System.out.println(params.str); // bye
System.out.println(params.i); // 99
}
}
Class constants are defined via const
in PHP:
class Greeter {
const GREETING = 'Hello';
}
echo Greeter::GREETING . "\n";
In Java, you’re using final
:
class Greeter {
final static String GREETING = "Hello";
}
System.out.println(Greeter.GREETING);
Interfaces and abstract classes work similarly in PHP and Java. PHP has traits, Java has default and static interface methods as of JDK 8.
Namespaces
You use namespace
to declare a PHP file’s namespace:
<?php
namespace example;
class Greeter {
const GREETING = 'Hello';
}
PHP’s namespace delimiter is the backslash \
:
echo \example\Greeter::GREETING . "\n";
Java calls a namespace a package
– and requires you to mark classes as public
to be able to use them from other namespaces:
package example;
public class Greeter {
public final static String GREETING = "Hello";
}
Java assumes your sources are organized in subdirectories by package names. The separator is the dot:
System.out.println(example.Greeter.GREETING);