Suppose that we have a Squirrel class and assume that the species name will never be null. We could write a constructor to enforce that if we wanted to:
public class Squirrel {
private int weight;
private String species;
public Squirrel(String theSpecies) {
if (theSpecies == null)
throw new IllegalArgumentException();
species = theSpecies;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public String getSpecies() {
return species;
}
}
We want to write a Comparator to sort by species name. If two squirrels are of the species, we want to sort the one that weighs the least first.
With the introduction of static and default methods on interfaces within Java 8, there are now some new helper methods on Comparator. The code could be written as this:
import java.util.Comparator;
public class ChainingComparator implements Comparator<Squirrel> {
@Override
public int compare(Squirrel s1, Squirrel s2) {
Comparator<Squirrel> c = Comparator.comparing(s -> s.getSpecies());
c = c.thenComparingInt(s -> s.getWeight());
return c.compare(s1, s2);
}
}
Labels
- OCPJP
- OCPJP 8
- Path
- Comparator
- Eclipse
- Archetypes
- Arrays
- BufferedReader
- BufferedWriter
- Comparable
- DataInputStream
- DataOutputStream
- DateTimeFormatter
- FileInputStream
- FileOutputStream
- FileReader
- FileWriter
- Files
- Logger
- Maven
- Paths
- Singleton
- StandardCopyOption
- Static nested class
- Threading
- ZonedDateTime
- enum
Wednesday, August 31, 2016
Tuesday, August 30, 2016
Design patterns: Singleton, Immutable object, Builder and Factory
A design pattern is an established general solution to a commonly occurring software development problem. The purpose of a design pattern is to leverage the wealth of knowledge of developers who have come before you in order to solve old problems that you might encounter easily. It also gives developers a common vocabulary in which they could discuss common problems and solutions. For example, if you say that you wrote getters/ setters or implemented the singleton pattern, most developers will understand the structure of your code without having to get into the low‐level details.
The following VisitorTicketTracker class represents an example of an implementation of the Singleton Pattern:
// Lazy instantiation
public class VisitorTicketTracker {
private static volatile VisitorTicketTracker instance;
private VisitorTicketTracker() {
}
public static VisitorTicketTracker getInstance() {
if (instance == null) {
synchronized (VisitorTicketTracker.class) {
if (instance == null) {
instance = new VisitorTicketTracker();
}
}
}
return instance;
}
// Data access methods
}
The following Animal class represents an example of an implementation of immutable object pattern:
import java.util.ArrayList;
import java.util.List;
public final class Animal {
private final String species;
private final int age;
private final List<String> favoriteFoods;
public Animal(String species, int age, List<String> favoriteFoods) {
this.species = species;
this.age = age;
if (favoriteFoods == null) {
throw new RuntimeException("favorite Foods is required");
}
this.favoriteFoods = new ArrayList<String>(favoriteFoods);
}
public String getSpecies() {
return species;
}
public int getAge() {
return age;
}
public int getFavoriteFoodsCount() {
return favoriteFoods.size();
}
public String getFavoriteFood(int index) {
return favoriteFoods.get(index);
}
}
The following AnimalBuilder class goes along with our previous class Animal and represents an example of an implementation of the builder pattern:
import java.util.List;
public class AnimalBuilder {
private String species;
private int age;
private List<String> favoriteFoods;
public AnimalBuilder setAge(int age) {
this.age = age;
return this;
}
public AnimalBuilder setSpecies(String species) {
this.species = species;
return this;
}
public AnimalBuilder setFavoriteFoods(List<String> favoriteFoods) {
this.favoriteFoods = favoriteFoods;
return this;
}
public Animal build() {
return new Animal(species, age, favoriteFoods);
}
}
Less talk, here is an example:
abstract class Food {
private int quantity;
public Food(int quantity) {
this.quantity = quantity;
}
public int getQuantity() {
return quantity;
}
public abstract void consumed();
}
class Hay extends Food {
public Hay(int quantity) {
super(quantity);
}
@Override
public void consumed() {
System.out.println("Hay eaten: " + getQuantity());
}
}
class Pellets extends Food {
public Pellets(int quantity) {
super(quantity);
}
@Override
public void consumed() {
System.out.println("Pellets eaten: " + getQuantity());
}
}
public class FoodFactory {
public static Food getFood(String animalName) {
switch (animalName) {
case "zebra":
return new Hay(100);
case "rabbit":
return new Pellets(5);
case "goat":
return new Pellets(30);
}
// Good practice to throw an exception if no matching subclass could be
// found
throw new UnsupportedOperationException("Unsupported animal: " + animalName);
}
}
Singleton Pattern
The singleton pattern is a creational pattern focused on creating only one instance of an object in memory within an application, sharable by all classes and threads within the application. The globally available object created by the singleton pattern is referred to as a singleton. Singletons might also improve performance by loading reusable data that would otherwise be time-consuming to store and reload each time it is needed.The following VisitorTicketTracker class represents an example of an implementation of the Singleton Pattern:
// Lazy instantiation
public class VisitorTicketTracker {
private static volatile VisitorTicketTracker instance;
private VisitorTicketTracker() {
}
public static VisitorTicketTracker getInstance() {
if (instance == null) {
synchronized (VisitorTicketTracker.class) {
if (instance == null) {
instance = new VisitorTicketTracker();
}
}
}
return instance;
}
// Data access methods
}
Immutable Objects
The immutable object pattern is a creational pattern based on the idea of creating objects whose state does not change after they are created and could be easily shared across multiple classes. Immutable objects go hand and hand with encapsulation, except that no setter methods exist that modify the object. Since the state of an immutable object never changes, they are inherently thread‐safe.The following Animal class represents an example of an implementation of immutable object pattern:
import java.util.ArrayList;
import java.util.List;
public final class Animal {
private final String species;
private final int age;
private final List<String> favoriteFoods;
public Animal(String species, int age, List<String> favoriteFoods) {
this.species = species;
this.age = age;
if (favoriteFoods == null) {
throw new RuntimeException("favorite Foods is required");
}
this.favoriteFoods = new ArrayList<String>(favoriteFoods);
}
public String getSpecies() {
return species;
}
public int getAge() {
return age;
}
public int getFavoriteFoodsCount() {
return favoriteFoods.size();
}
public String getFavoriteFood(int index) {
return favoriteFoods.get(index);
}
}
Builder Pattern
The builder pattern is a creational pattern in which parameters are passed to a builder object, often through method chaining, and an object is generated with a final build call. It is often used with immutable objects, since immutable objects do not have setter methods and must be created with all of their parameters set, although it could be used with mutable objects as well.The following AnimalBuilder class goes along with our previous class Animal and represents an example of an implementation of the builder pattern:
import java.util.List;
public class AnimalBuilder {
private String species;
private int age;
private List<String> favoriteFoods;
public AnimalBuilder setAge(int age) {
this.age = age;
return this;
}
public AnimalBuilder setSpecies(String species) {
this.species = species;
return this;
}
public AnimalBuilder setFavoriteFoods(List<String> favoriteFoods) {
this.favoriteFoods = favoriteFoods;
return this;
}
public Animal build() {
return new Animal(species, age, favoriteFoods);
}
}
Factory Pattern
The factory pattern sometimes referred to as the factory method pattern, is a creational pattern based on the idea of using a factory class to produce instances of objects based on a set of input parameters. It is similar to the builder pattern, although it is focused on supporting class polymorphism.Less talk, here is an example:
abstract class Food {
private int quantity;
public Food(int quantity) {
this.quantity = quantity;
}
public int getQuantity() {
return quantity;
}
public abstract void consumed();
}
class Hay extends Food {
public Hay(int quantity) {
super(quantity);
}
@Override
public void consumed() {
System.out.println("Hay eaten: " + getQuantity());
}
}
class Pellets extends Food {
public Pellets(int quantity) {
super(quantity);
}
@Override
public void consumed() {
System.out.println("Pellets eaten: " + getQuantity());
}
}
public class FoodFactory {
public static Food getFood(String animalName) {
switch (animalName) {
case "zebra":
return new Hay(100);
case "rabbit":
return new Pellets(5);
case "goat":
return new Pellets(30);
}
// Good practice to throw an exception if no matching subclass could be
// found
throw new UnsupportedOperationException("Unsupported animal: " + animalName);
}
}
Common Functional Interfaces
The table below gathers the mostly used functional interfaces within Java 8:
P, Q is Int, Long, Double
Functional Interface | Parameter Types | Return Type | Abstract Method Name | Description | Other Methods |
---|---|---|---|---|---|
Runnable | none | void | run | Runs an action without arguments or return value | |
Supplier |
none | T | get | Supplies a value of type T | |
Consumer |
T | void | accept | Consumes a value of type T | chain |
BiConsumer |
T, U | void | accept | Consumes values of types T and U | chain |
Function |
T | R | apply | A function with argument of type T | compose, andThen, identity |
BiFunction |
T, U | R | apply | A function with arguments of types T and U | andThen |
UnaryOperator |
T | T | apply | A unary operator on the type T | compose, andThen, identity |
BinaryOperator |
T, T | T | apply | A binary operator on the type T | andThen |
Predicate |
T | boolean | test | A Boolean-valued function | and, or, negate, isEqual |
BiPredicate |
T, U | boolean | test | A Boolean-valued function with two arguments | and, or, negate |
Functional Interfaces for Primitive Types:
p, q is int, long, double;P, Q is Int, Long, Double
Functional Interface | Parameter Types | Return Type | Abstract Method Name |
---|---|---|---|
BooleanSupplier | none | boolean | getAsBoolean |
PSupplier | none | p | getAsP |
PConsumer | p | void | accept |
ObjPConsumer |
T, p | void | accept |
PFunction |
p | T | apply |
PToQFunction | p | q | applyAsQ |
ToPFunction |
T | p | applyAsP |
ToPBiFunction |
T, U | p | applyAsP |
PUnaryOperator | p | p | applyAsP |
PBinaryOperator | p, p | p | applyAsP |
PPredicate | p | boolean | test |
Thursday, August 25, 2016
The most common Stream operations
Streams represent one of the major revolutionary features of Java 8. In this article, you will see the most used operations grouped by type in brief.
String contents = new String(Files.readAllBytes(path), StandardCharsets.UTF_8);
Stream<String> words = Stream.of(contents.split("[\\P{L}]+"));
Or
Stream<String> wordsAnotherWay = Pattern.compile("[\\P{L}]+").splitAsStream(contents);
Stream<String> java.util.regex.Pattern.splitAsStream(CharSequence arg0)
Or
silence = Stream.<String>empty(); // Explicit type specification
try (Stream<String> lines = Files.lines(path, StandardCharsets.UTF_8)) {
}
As you could see here the generation of the stream is made within a try with resources block. Since Stream class implements AutoCloseable interface, the stream and the underlying resource (path in this case) will be closed automatically at the end of the try block.
Stream<String> noVowelsWords = words.map(s -> s.replaceAll("[aeiouAEIOU]", ""));
List<Character> result = new ArrayList<>();
for (char c : s.toCharArray())
result.add(c);
return result.stream();
}
Stream<Character> combined = Stream.concat(characterStream("Hello"), characterStream("World"));
List<String> firstElements = stream.limit(SIZE).collect(Collectors.toList());
if (last.isPresent())
System.out.println("last: " + last.get());
optionalValue.ifPresent(s -> System.out.println(s + " contains red"));
Or
System.out.print(optionalValue.orElse("No word") + " contains red");
Or
optionalValue.orElseGet(() -> System.getProperty("user.dir"));
Or
try {
String result = optionalValue.orElseThrow(NoSuchElementException::new);
System.out.println("result: " + result);
} catch (Throwable t) {
t.printStackTrace();
}
Or
Integer sum2 = values.reduce(0, (x, y) -> x + y);
Integer java.util.stream.Stream.reduce(Integer identity, BinaryOperator<Integer> accumulator)
while (iter.hasNext())
System.out.println(iter.next());
Set<String> wordsSet = words.collect(Collectors.toSet());
TreeSet<String> wordsTreeSet = words.collect(Collectors.toCollection(TreeSet::new));
<Set<String>, ?> Set<String> java.util.stream.Stream.collect(Collector<? super String, ?, Set<String>> collector)
<TreeSet<String>, ?> TreeSet<String> java.util.stream.Stream.collect(Collector<? super String, ?, TreeSet<String>> collector)
double averageWordLength = summary.getAverage();
double maxWordLength = summary.getMax();
.collect(Collectors.toMap(Person::getId, Function.identity(), (existingValue, newValue) -> {
throw new IllegalStateException();
}, TreeMap::new));
Map<String, String> languageNames = locales.collect(Collectors.toMap(Locale::getDisplayLanguage,
Locale::getDisplayLanguage, (existingValue, newValue) -> existingValue));
Map<String, Set<String>> countryLanguageSets = locales.collect(Collectors.toMap(Locale::getDisplayCountry,
l -> Collections.singleton(l.getDisplayLanguage()), (a, b) -> { // union of a and b
Set<String> r = new HashSet<>(a);
r.addAll(b);
return r;
}));
1- Generating streams (Source):
Example:
Path path = Paths.get("file.txt");String contents = new String(Files.readAllBytes(path), StandardCharsets.UTF_8);
Stream<String> words = Stream.of(contents.split("[\\P{L}]+"));
Or
Stream<String> wordsAnotherWay = Pattern.compile("[\\P{L}]+").splitAsStream(contents);
Description:
Generate a stream of String containing the existing words within the file "file.txt".Method's signature:
<String> Stream<String> java.util.stream.Stream.of(String... values)Stream<String> java.util.regex.Pattern.splitAsStream(CharSequence arg0)
Example:
Stream<String> song = Stream.of("gently", "down", "the", "stream");Description:
Generates stream of String containing the words passed as var-args argument.Example:
Stream<String> silence = Stream.empty();Or
silence = Stream.<String>empty(); // Explicit type specification
Description:
Generate an empty stream of String.Method's signature:
<Object> Stream<Object> java.util.stream.Stream.empty()Example:
Stream<String> echos = Stream.generate(() -> "Echo");Description:
Generates an infinite stream of String containing the "Echo" values.Method's signature:
<String> Stream<String> java.util.stream.Stream.generate(Supplier<String> s)Example:
Stream<Double> randoms = Stream.generate(Math::random);Description:
Generates an infinite stream of Double containing random values.Method's signature:
<Double> Stream<Double> java.util.stream.Stream.generate(Supplier<Double> s)Example:
Stream<BigInteger> integers = Stream.iterate(BigInteger.ONE, n -> n.add(BigInteger.ONE));Description:
Generates an infinite stream of BigInteger containing values 1,2,3...Method's signature:
<BigInteger> Stream<BigInteger> java.util.stream.Stream.iterate(BigInteger seed, UnaryOperator<BigInteger> f)Example:
Path path = Paths.get("file.txt");try (Stream<String> lines = Files.lines(path, StandardCharsets.UTF_8)) {
}
Description:
Generates a stream of String containing lines within the file "file.txt".As you could see here the generation of the stream is made within a try with resources block. Since Stream class implements AutoCloseable interface, the stream and the underlying resource (path in this case) will be closed automatically at the end of the try block.
Method's signature:
Stream<String> java.nio.file.Files.lines(Path path, Charset cs) throws IOExceptionExample:
Stream<String> words = wordList.stream();Description:
Generates stream of String from worldList listMethod's signature:
Stream<String> java.util.Collection.stream()Example:
Optional<String> optionalString = Optional.empty();Description:
Genarates an empty optional.Method's signature:
<Object> Optional<Object> java.util.Optional.empty()Example:
Optional.of(Math.sqrt(x));Description:
Generates an Optional<Double> containing the square root of x (x is a double value).Method's signature:
<Double> Optional<Double> java.util.Optional.of(Double value)2- Intermediate operations:
Example:
Stream<String> longWords = words.filter(w -> w.length() > 10);Description:
Filters worlds having more than 10 characters.Method's signature:
Stream<String> java.util.stream.Stream.filter(Predicate<? super String> predicate)Example:
Stream<String> lowercaseWords = words.map(String::toLowerCase);Stream<String> noVowelsWords = words.map(s -> s.replaceAll("[aeiouAEIOU]", ""));
Description:
The first statement applies toLowerCase() method on each string within the stream words and returns a new stream stored into lowercaseWords stream. Whereas, the second statement replaces all vowels with an ampty string.Method's signature:
<String> Stream<String> java.util.stream.Stream.map(Function<? super String, ? extends String> mapper)Example:
Stream<Integer> notTheFirst = integers.skip(1);Description:
This one does the opposite of limit(int) method; it excludes the first element of the Integer's stream integers.Method's signature:
Stream<Integer> java.util.stream.Stream.skip(long n)Example:
public static Stream<Character> characterStream(String s) {List<Character> result = new ArrayList<>();
for (char c : s.toCharArray())
result.add(c);
return result.stream();
}
Stream<Character> combined = Stream.concat(characterStream("Hello"), characterStream("World"));
Description:
Concatenate two streams of Character. Note that concat() method available only for Character type.Method's signature:
<Character> Stream<Character> java.util.stream.Stream.concat(Stream<? extends Character> a, Stream<? extends Character> b)Example:
Stream<String> uniqueWords = Stream.of("merrily", "merrily", "merrily", "gently").distinct();Description:
Generates a new stream of only distinct words.Method's signature:
Stream<String> java.util.stream.Stream.distinct()Example:
Stream<String> sorted = words.sorted();Description:
Generates a new stream of sorted strings.Method's signature:
Stream<String> java.util.stream.Stream.sorted()Example:
Stream<String> longestFirst = words.sorted(Comparator.comparing(String::length).reversed());Description:
Generates a stream of words sorted by length in descending order.Method's signature:
Stream<String> java.util.stream.Stream.sorted(Comparator<? super String> comparator)3- Terminal operations:
Example:
final int SIZE = 10;List<String> firstElements = stream.limit(SIZE).collect(Collectors.toList());
Description:
Collect the first 10 elements of stream into firstElements list.Method's signature:
<List<String>, ?> List<String> java.util.stream.Stream.collect(Collector<? super String, ?, List<String>> collector)Example:
Object[] powers = Stream.iterate(1.0, p -> p * 2).peek(e -> System.out.println("Fetching " + e)).limit(20).toArray();Description:
Generates a stream of Integer, picks the first 20 values as streams are evaluated lazily i.e. until the call of the terminal operation, print the selected values out, then, results in an array of objects stored into power variable.Method's signature:
Object[] java.util.stream.Stream.toArray()Example:
Optional<String> last = words.max(String::compareToIgnoreCase);if (last.isPresent())
System.out.println("last: " + last.get());
Description:
Output an Optional of type String containing the last world lexicographically contained within the stream of strings words.Method's signature:
Optional<String> java.util.stream.Stream.max(Comparator<? super String> comparator)Example:
boolean aWordStartsWithQ = words.anyMatch(s -> s.startsWith("Q"));Description:
Returns a boolean value representing wether there is or there is not any value starting with the letter "Q" within the stream words.Method's signature:
boolean java.util.stream.Stream.anyMatch(Predicate<? super String> predicate)Example:
Optional<String> startsWithQ = words.parallel().filter(s -> s.startsWith("Q")).findAny();Description:
Returns an optional string containg any word starting with "Q" regardless of the values' order within the original stream.Method's signature:
Optional<String> java.util.stream.Stream.findAny()Example:
Optional<String> optionalValue = wordList.stream().filter(s -> s.contains("red")).findFirst();optionalValue.ifPresent(s -> System.out.println(s + " contains red"));
Or
System.out.print(optionalValue.orElse("No word") + " contains red");
Or
optionalValue.orElseGet(() -> System.getProperty("user.dir"));
Or
try {
String result = optionalValue.orElseThrow(NoSuchElementException::new);
System.out.println("result: " + result);
} catch (Throwable t) {
t.printStackTrace();
}
Description:
Print out an optional string representing the first value within the original stream containing "red".Method's signature:
Optional<String> java.util.stream.Stream.findFirst()Example:
Optional<Integer> sum = values.reduce((x, y) -> x + y);Or
Integer sum2 = values.reduce(0, (x, y) -> x + y);
Description:
Returns the sum of values contained within the stream of integers.Method's signature:
Optional<Integer> java.util.stream.Stream.reduce(BinaryOperator<Integer> accumulator)Integer java.util.stream.Stream.reduce(Integer identity, BinaryOperator<Integer> accumulator)
Example:
int result = words.reduce(0, (s, w) -> s + w.length(), (s1, s2) -> s1 + s2);Description:
Counts the number of letters contained within the stream of words.Method's signature:
<Integer> Integer java.util.stream.Stream.reduce(Integer identity, BiFunction<Integer, ? super String, Integer> accumulator, BinaryOperator<Integer> combiner)Example:
System.out.println("[" + set.stream().limit(10).map(Object::toString).collect(Collectors.joining(", ")) + "]");Description:
Prints out the first 10 element of the set separated by comma.Method's signature:
<String, ?> String java.util.stream.Stream.collect(Collector<? super String, ?, String> collector)Example:
Iterator<Integer> iter = Stream.iterate(0, n -> n + 1).limit(10).iterator();while (iter.hasNext())
System.out.println(iter.next());
Description:
Result in an iterator containing the first ten iterarions of the original stram.Method's signature:
Iterator<Integer> java.util.stream.BaseStream.iterator()Example:
Integer[] numbers = Stream.iterate(0, n -> n + 1).limit(10).toArray(Integer[]::new);Description:
Results in array of integers consisting of the first ten iterations of the original array.Method's signature:
<Integer> Integer[] java.util.stream.Stream.toArray(IntFunction<Integer[]> generator)Example:
HashSet<String> wordsHashSet = words.collect(HashSet::new, HashSet::add, HashSet::addAll);Set<String> wordsSet = words.collect(Collectors.toSet());
TreeSet<String> wordsTreeSet = words.collect(Collectors.toCollection(TreeSet::new));
Description:
The previous statements represent three different ways to collect streams into sets.Method's signature:
<HashSet<String>> HashSet<String> java.util.stream.Stream.collect(Supplier<HashSet<String>> supplier, BiConsumer<HashSet<String>, ? super String> accumulator, BiConsumer<HashSet<String>, HashSet<String>> combiner)<Set<String>, ?> Set<String> java.util.stream.Stream.collect(Collector<? super String, ?, Set<String>> collector)
<TreeSet<String>, ?> TreeSet<String> java.util.stream.Stream.collect(Collector<? super String, ?, TreeSet<String>> collector)
Example:
IntSummaryStatistics summary = words.collect(Collectors.summarizingInt(String::length));double averageWordLength = summary.getAverage();
double maxWordLength = summary.getMax();
Description:
Terminate the pipeline getting statistics about words' length.Method's signature:
<IntSummaryStatistics, ?> IntSummaryStatistics java.util.stream.Stream.collect(Collector<? super String, ?, IntSummaryStatistics> collector)Example:
Map<Integer, Person> idToPerson = people.collect(Collectors.toMap(Person::getId, Function.identity()));Method's signature:
<Map<Integer, Person>, ?> Map<Integer, Person> java.util.stream.Stream.collect(Collector<? super Person, ?, Map<Integer, Person>> collector)Example:
idToPerson = people.collect(Collectors.toMap(Person::getId, Function.identity(), (existingValue, newValue) -> {
throw new IllegalStateException();
}, TreeMap::new));
Method's signature:
<TreeMap<Integer, Person>, ?> TreeMap<Integer, Person> java.util.stream.Stream.collect(Collector<? super Person, ?, TreeMap<Integer, Person>> collector)Example:
Stream<Locale> locales = Stream.of(Locale.getAvailableLocales());Map<String, String> languageNames = locales.collect(Collectors.toMap(Locale::getDisplayLanguage,
Locale::getDisplayLanguage, (existingValue, newValue) -> existingValue));
Map<String, Set<String>> countryLanguageSets = locales.collect(Collectors.toMap(Locale::getDisplayCountry,
l -> Collections.singleton(l.getDisplayLanguage()), (a, b) -> { // union of a and b
Set<String> r = new HashSet<>(a);
r.addAll(b);
return r;
}));
Method's signature:
<Map<String, Set<String>>, ?> Map<String, Set<String>> java.util.stream.Stream.collect(Collector<? super Locale, ?, Map<String, Set<String>>> collector)Wednesday, August 24, 2016
The Easy Way to Write toString(), equals() and hashCode() Methods
Once you’ve written a toString() method, it starts to get boring to write more especially if you want to include a lot of instance variables. Luckily, there is an open source library that takes care of it for you. Apache Commons Lang provides some methods that you might wish were in core Java.
This is all you have to write to have Apache Commons return all of the instance variables in a String:
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
You might be wondering what this reflection thing is that is mentioned in the method name. Reflection is a technique used in Java to look at information about the class at runtime. This lets the ToString Builder class determine what are all of the instance variables and to construct a String with each.
When testing your code, there is a benefit to not having information in toString() that isn’t useful to your caller. Apache Commons accounts for this as well.
You could write
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}
There are a few other styles that support letting you choose to omit the class names or the instance variable names.
Like toString(), you could use Apache Commons Lang to do a lot of the work for you. If you want all of the instance variables to be checked, your equals() method could be one line:
@Override
public boolean equals(Object obj) {
return EqualsBuilder.reflectionEquals(this, obj);
}
This is nice. However, for equals(), it is common to look at just one or two instance variables rather than all of them.
@Override
public boolean equals(Object obj) {
if (!(obj instanceof LionEqualsBuilder))
return false;
Lion other = (Lion) obj;
return new EqualsBuilder().appendSuper(super.equals(obj)).append(idNumber, other.idNumber)
.append(name, other.name).isEquals();
}
Not quite as elegant, right? You have to remember to handle the null and instanceof guard conditions first. It is still better than having to code the whole thing by hand, though. Comparing the idNumber is easy because you could call ==. Comparing the name means checking that either both names are null or the names are the same. If either name is null, you need to return false. This logic is a bit messy if you write it out by hand.
You probably thought that this was going to be about the Apache Commons Lang class for hash code. There is one, but it isn’t the easiest way to write hash code.
It is easier to code your own. Just pick the key fields that identify your object (and don’t change during the program) and combine them:
@Override
public int hashCode() {
return keyField + 7 * otherKeyField.hashCode();
}
It is common to multiply by a prime number when combining multiple fields in the hash code. This makes the hash code more unique, which helps when distributing objects into buckets.
This is all you have to write to have Apache Commons return all of the instance variables in a String:
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
You might be wondering what this reflection thing is that is mentioned in the method name. Reflection is a technique used in Java to look at information about the class at runtime. This lets the ToString Builder class determine what are all of the instance variables and to construct a String with each.
When testing your code, there is a benefit to not having information in toString() that isn’t useful to your caller. Apache Commons accounts for this as well.
You could write
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}
There are a few other styles that support letting you choose to omit the class names or the instance variable names.
Like toString(), you could use Apache Commons Lang to do a lot of the work for you. If you want all of the instance variables to be checked, your equals() method could be one line:
@Override
public boolean equals(Object obj) {
return EqualsBuilder.reflectionEquals(this, obj);
}
This is nice. However, for equals(), it is common to look at just one or two instance variables rather than all of them.
@Override
public boolean equals(Object obj) {
if (!(obj instanceof LionEqualsBuilder))
return false;
Lion other = (Lion) obj;
return new EqualsBuilder().appendSuper(super.equals(obj)).append(idNumber, other.idNumber)
.append(name, other.name).isEquals();
}
Not quite as elegant, right? You have to remember to handle the null and instanceof guard conditions first. It is still better than having to code the whole thing by hand, though. Comparing the idNumber is easy because you could call ==. Comparing the name means checking that either both names are null or the names are the same. If either name is null, you need to return false. This logic is a bit messy if you write it out by hand.
You probably thought that this was going to be about the Apache Commons Lang class for hash code. There is one, but it isn’t the easiest way to write hash code.
It is easier to code your own. Just pick the key fields that identify your object (and don’t change during the program) and combine them:
@Override
public int hashCode() {
return keyField + 7 * otherKeyField.hashCode();
}
It is common to multiply by a prime number when combining multiple fields in the hash code. This makes the hash code more unique, which helps when distributing objects into buckets.
Labels:
Apache Commons Lang,
Concise,
Java 8,
OCPJP,
OCPJP 8
Some useful and concise operations upon a given text file written in Java 8
The following "contains" method represents a concise way of checking whether a word exists or not within a file:
public static boolean contains(Path p, String word) {
try {
return new String(Files.readAllBytes(p), StandardCharsets.UTF_8).contains(word);
} catch (IOException ex) {
return false;
}
}
Here is another method that counts the number of words within a file using Java 8's new feature "parallel stream":
public static long countNumberOfWords(Path p) throws IOException {
return Arrays.asList(new String(Files.readAllBytes(p), StandardCharsets.UTF_8).split("[\\P{L}]+"))
.parallelStream().count();
}
public static boolean contains(Path p, String word) {
try {
return new String(Files.readAllBytes(p), StandardCharsets.UTF_8).contains(word);
} catch (IOException ex) {
return false;
}
}
Here is another method that counts the number of words within a file using Java 8's new feature "parallel stream":
public static long countNumberOfWords(Path p) throws IOException {
return Arrays.asList(new String(Files.readAllBytes(p), StandardCharsets.UTF_8).split("[\\P{L}]+"))
.parallelStream().count();
}
Consice way to collect sub-paths from a given path within Java 8
The following method represents a smart way of gathering subpaths within a path:
public static Path[] getDescendants(Path dir) {
try {
try (Stream<Path> entries = Files.walk(dir)) {
return entries.toArray(Path[]::new);
}
} catch (IOException ex) {
return new Path[0];
}
}
public static Path[] getDescendants(Path dir) {
try {
try (Stream<Path> entries = Files.walk(dir)) {
return entries.toArray(Path[]::new);
}
} catch (IOException ex) {
return new Path[0];
}
}
Wednesday, August 17, 2016
How to work with locales
In order to understand how to make use of locales in Java, let's try two useful examples. First, assume that you want to extract available locales speaking French which has the code "fr":
import java.util.Arrays;
import java.util.Locale;
class AvailableLocalesFrench {
public static void main(String[] args) {
Arrays.stream(Locale.getAvailableLocales()).filter(locale -> locale.getLanguage().equals("fr"))
.forEach(locale -> System.out.printf("Locale code: %s and it stands for %s %n", locale,
locale.getDisplayName()));
}
}
By running this you would get:
Locale code: fr_BE and it stands for French (Belgium)
Locale code: fr_CH and it stands for French (Switzerland)
Locale code: fr and it stands for French
Locale code: fr_LU and it stands for French (Luxembourg)
Locale code: fr_FR and it stands for French (France)
Locale code: fr_CA and it stands for French (Canada)
import java.util.Arrays;
import java.util.Locale;
class AvailableLocalesFrench {
public static void main(String[] args) {
Arrays.stream(Locale.getAvailableLocales()).filter(locale -> locale.getLanguage().equals("fr"))
.forEach(locale -> System.out.printf("Locale code: %s and it stands for %s %n", locale,
locale.getDisplayName()));
}
}
By running this you would get:
Locale code: fr_BE and it stands for French (Belgium)
Locale code: fr_CH and it stands for French (Switzerland)
Locale code: fr and it stands for French
Locale code: fr_LU and it stands for French (Luxembourg)
Locale code: fr_FR and it stands for French (France)
Locale code: fr_CA and it stands for French (Canada)
The Second example, let's set the default locale within the system to France and get some details about it:
import java.util.Locale;
public class LocaleDetails {
public static void main(String args[]) {
Locale.setDefault(Locale.FRANCE);
Locale defaultLocale = Locale.getDefault();
System.out.printf("The default locale is %s %n", defaultLocale);
System.out.printf("The default language code is %s and the name is %s %n", defaultLocale.getLanguage(),
defaultLocale.getDisplayLanguage());
System.out.printf("The default country code is %s and the name is %s %n", defaultLocale.getCountry(),
defaultLocale.getDisplayCountry());
System.out.printf("The default variant code is %s and the name is %s %n", defaultLocale.getVariant(),
defaultLocale.getDisplayVariant());
}
}
Outputs:
The default locale is fr_FR
The default language code is fr and the name is français
The default country code is FR and the name is France
The default variant code is and the name is
Subscribe to:
Posts (Atom)