Grzegorz Rożniecki (@xaerxess)
Java / Perl / JavaScript developer
Software reader / writer
There is more than one way to do it
Tim Toady
"The very fact that it's possible to write messy programs in Perl is also what makes it possible to write programs that are cleaner in Perl than they could ever be in a language that attempts to enforce cleanliness. The potential for greater good goes right along with the potential for greater evil."
There should be one
- and preferably only one -
obvious way to do it
"There are only two kinds of languages: the ones people complain about and the ones nobody uses"
"There are only 10
kinds of languages: the ones people complain about and the ones nobody uses"
for
loop
for (my $i = 0; $i <= 3; ++$i) {
print $i;
}
for
loop
for my $i (0..3) {
print $i;
}
for
loop
for (0..3) {
print $_;
}
for
loop
for (0..3) {
print;
}
for
loop
print for (0..3);
vs
Edward Sapir | Benjamin Whorf |
![]() |
![]() |
linguistics theory | Hopi - time & space |
Perl | Java |
---|---|
created in 1987 | created in 1991 |
Perl 5 released in 1994 | JDK 1.0 released in 1995 |
"get things done" | "write once, run anywhere" |
OO support in Perl 5 | OO support from the beginning |
There’s more than one way to do it
but sometimes consistency is not a bad thing either
package Foo;
sub new {
my $class = shift;
my $self = { }; # or [ ] or any arbitrary scalar value
return bless $self, $class;
}
1;
People like rules and guidelines. They like to agree with them, or to argue with them.
Inconsistency
TIMTOWTDI?
finally...
but...
final class Person {
private final String name;
private final Integer age;
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((age == null) ? 0 : age.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (age == null) {
if (other.age != null)
return false;
} else if (!age.equals(other.age))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
vs
case class Person(name: String, age: Int)
Java 7+: Objects
Java < 7 - Guava: Objects
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public boolean equals(final Object obj) {
if (!(obj instanceof Person))
return false;
final Person other = (Person) obj;
return Objects.equals(this.name, other.name)
&& Objects.equals(this.age, other.age);
}
Better?
Guava 18+: MoreObjects.toStringHelper
Guava < 18: Objects.toStringHelper
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("name", name)
.add("age", age)
.toString();
}
Also better?
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
Lombok: @Value
@Value public class Person {
String name;
Integer age;
}
Lombok: black magic
Google AutoValue: @AutoValue
@AutoValue
abstract class Person {
public static Person create(String name, Integer age) {
return new AutoValue_Person(name, age);
}
public abstract String getName();
public abstract int getAge();
}
Good trade-off?
You should prefer List<Foo>
over Foo[]
whenever possible.
ArrayStoreException
can result at runtime.List<Class<? extends E>>
or List<Optional<T>>
). With an array you get compilation warnings and confusing runtime exceptions.equals
, hashCode
and toString
methods do what users expect; those methods on an array do anything but what you expect -- a common source of bugs.So, why would you ever use object arrays?
Ex. consistent IDE preferences
The "final
" battle
"Closures feel to me like one of these design Black Holes. (...) So, should we just give in to the force of gravity and go the rest of the way? The debate's afoot. It's going to be an entertaining year."
"Java has closures, it's just called 'anonymous inner classes' (...). [They] are the better and more 'java-way' to do closures. Adding an additional syntax for closures will only make the language more complex without solving even one real problem."
...and in 2014 (finally) instead of this:
List<Album> favs = new ArrayList<>();
for (Album a : albums) {
boolean hasFavorite = false;
for (Track t : a.tracks) {
if (t.rating >= 4) {
hasFavorite = true;
break;
}
}
if (hasFavorite) {
favs.add(a);
}
}
Collections.sort(favs, new Comparator<Album>() {
@Override public int compare(Album a1, Album a2) {
return a1.name.compareTo(a2.name);
}});
...you can do this:
List<Album> sortedFavs =
albums.stream()
.filter(a -> a.tracks.anyMatch(t -> (t.rating >= 4)))
.sorted(Comparator.comparing(a -> a.name))
.collect(Collectors.toList());
There is more than one way to do it, finally!
Please send me a feedback:
@xaerxess or xaerxess at
gmail dot
com