visit
The material is designed for developers with little experience with Java, and the main reason is to refresh their knowledge.
== equal to
!= not equal to
> greater than
>= greater than or equal to
< less than
<= less than or equal to
// Integer != int
int a = 1, b = 1;
System.out.println(a == b); // true
int c = 1, j = c;
System.out.println(c == j); // true
Integer ai = Integer.valueOf(1), bi = Integer.valueOf(1);
System.out.println(ai == bi); // true
Integer ci = Integer.valueOf(128), ji = Integer.valueOf(128);
System.out.println(ci == ji); // false
/* You can always count on the fact that
* for values between -128 and 127,
* you get the identical Integer objects after autoboxing,
* and on some implementations you might get identical objects
* even for higher values.
*/
It’s important to learn that the Integer class is not a primitive value because it is a regular class. Class Object
is the root of the class hierarchy. Every class has Object
as a superclass. All objects, including arrays, implement the methods of this class.
// Indicates whether some other object is "equal to" this one.
public boolean equals(Object obj)
Or Comparable interface for natural ordering (if you need to sort your collection with your own type of object):
public class HugePoint implements Comparable<HugePoint> {
// same as before
@Override
public int compareTo(HugePoint otherHugePoint) {
return Integer.compare(getSize(), otherHugePoint.getSize());
}
}
The Comparator interface defines a compare(arg1, arg2) method:
public class HugePointComparator implements Comparator<HugePoint> {
@Override
public int compare(HugePoint firstPoint, HugePoint secondPoint) {
return Integer.compare(firstPoint.getSize(), secondPoint.getSize());
}
}
It’s easy to use Java 8+ this way:
Comparator<Person> byAge = Comparator.comparing(Person::getAge);
Comparator byAge = (Person person1, Person person2) ->
Integer.compare(person1.getAge(), person2.getAge());
Which one do you need to use and when? I would recommend using “Comparable” interface for ordering (if you have a sorting method, etc.), and “Comparator” if you need to compare objects by a special field.
Date and time
Why? For the current timestamp, just use Instant.now()
. We don’t need to convert to milliseconds.
// Instant class, one of the main classes of the Date-Time API, encapsulates a point on the timeline.
Instant.now();
Instant now = Instant.parse("2021-02-09T11:19:42.12Z");
Instant before = now.minus(Duration.ofDays(1));
For the local date format use the following:
// LocalDateTime is an immutable date-time object
// that represents a date-time, often viewed
// as year-month-day-hour-minute-second.
LocalDateTime.now();
LocalDateTime.of(2001, Month.FEBRUARY, 10, 03, 01);
UUID
// uuid
UUID uuid = UUID.randomUUID();
UUID uuid = new UUID(mostSignificant64Bits, leastSignificant64Bits);
Random
// random for int
int randomWithMathRandom = (int) ((Math.random() * (max - min)) + min);
// or easy way
Random random = new Random();
int randomWithNextInt = random.nextInt();
// case
int expression = 9;
switch(expression) {
case 2:
System.out.println("Small Size");
break;
case 3:
System.out.println("Large Size");
break;
// default case
default:
System.out.println("Unknown Size");
}
Also, up Java to version 19 or more, and we can use the expression:
Day day = Day.WEDNESDAY;
var resultDay = switch (day) {
case MONDAY, FRIDAY, SUNDAY -> 6;
case TUESDAY -> 7;
case THURSDAY, SATURDAY -> 8;
case WEDNESDAY -> 9;
default -> throw new IllegalStateException("Invalid day: " + day);
}
System.out.println(resultDay);
Don’t forget to use try/catch with methods that can throw exceptions. Try/catch and try with resources:
// old
public int find(String playerFile) {
try {
Scanner contents = new Scanner(new File(playerFile));
return Integer.parseInt(contents.nextLine());
} catch (FileNotFoundException noFile) {
throw new IllegalArgumentException("Couldn't find the file");
}
}
// with resources
public int find(String playerFile) {
try (Scanner contents = new Scanner(new File(playerFile))) {
return Integer.parseInt(contents.nextLine());
} catch (FileNotFoundException e ) {
logger.warn("Couldn't find the file");
return 0;
}
}
// don't do it!
public int find(String playerFile) {
try {
// action
} catch (Exception e) {} // <== catch and swallow
return 0;
}
Use finally, especially with channels:
// close it!
public int find(String playerFile) throws FileNotFoundException {
Scanner contents = null;
try {
contents = new Scanner(new File(playerFile));
return Integer.parseInt(contents.nextLine());
} finally {
if (contents != null) {
contents.close();
}
}
}
// Always close it!
public int find(String playerFile){
MessageChannel channel = buildChannel(port);
try {
// do some action with channel
} finally {
channel.close(); // close!
}
}
Also, it would be good to go through the algorithms’ complexity table. I strongly recommend using this link:
// old way:
List<String> old = new ArrayList<>();
old.add("one");
// new way:
List<String> list = Arrays.asList("one", "two");
List<String> list = List.of("one", "two", "three");
Set<String> set = Set.of("one", "two", "three");
We can simplify working with the map.
// old:
HashMap<Integer, String> hm = new HashMap<Integer, String>();
hm.put(1, "foo");
// new:
Map<String, String> map = Map.of("foo", "one", "bar", "two");
As you know, we have only two types of operations: intermediate and terminal operations.
// Intermediate Operations
var stream = ...;
stream.filter();
stream.map();
stream.flatMap();
stream.distinct();
stream.sorted();
stream.peek();
stream.limit();
stream.skip();
// Terminal
stream.reduce();
stream.forEach();
stream.min();
stream.max();
stream.anyMatch();
stream.allMatch();
stream.noneMatch();
stream.findAny();
stream.findFirst();
stream.toArray();
stream.collect();
stream.count();
stream.forEachOrdered();
// Java 7 way
ArrayList results = new ArrayList();
for (Score score: scores) {
if (score.getVal() > 10) {
results.add(score.getVal());
}
}
System.out.println(results);
// Java 8+ way
ArrayList results = scores.stream()
.filter(score -> score.getVal() > 10)
.collect(Collectors.toList());
System.out.println(results);
// Functional
Consumer<Integer> consumer = (n) -> { System.out.println(n); };
numbers.forEach(consumer);
Throwing exceptions every time an object is not found is not a good idea; you should use the “Optional” class for this:
var empty = Optional.empty();
empty.isPresent(); // false
var notEmpty = Optional.of(name);
notEmpty.isPresent(); // true
String name = null;
Optional<String> opt = Optional.ofNullable(name);
opt.isPresent(); // false
String name = null;
String result = Optional.ofNullable(nullName).orElse("Default");
// get result
var name = Optional.of("Name");
name.get();
String name = Optional.ofNullable(name)
.orElseThrow(IllegalArgumentException::new);
// throw NoSuchElementException.class
Optional.ofNullable(name).orElseThrow();
public class TestObject {
private String string;
// public contructor
// getters and setters
}
// create new object
ExecutorService executor = Executors.newFixedThreadPool(10);
var testObject = new UsefulObject();
executor.submit(() -> testObject.setTestString("test_1"));
executor.submit(() -> testObject.setTestString("test_2"));
executor.submit(() -> testObject.setTestString("test_3"));
executor.submit(() -> testObject.setTestString("test_4"));
// the result might be anything!
// test_1 or test_2
// or test_3
System.out.println(testObject.getTestString());
Record classes are special classes that act as transparent carriers for immutable data. They are immutable classes and are implicitly final classes, which means they can’t be extended. Just use a record class instead of a class:
record MainObject(int x) { }
The compiler implicitly provides the constructor, getters, equals
& hashCode
, and toString
.
public final class MainObject {
private final int x;
public Rectangle(int x) {
this.x = x;
}
double x() { return this.x; }
// Implementation of equals() and hashCode(), which specify
// that two record objects are equal if they
// are of the same type and contain equal field values.
public boolean equals...
public int hashCode...
// An implementation of toString() that returns a string
// representation of all the record class's fields,
// including their names.
public String toString() {...}
}
If we need to share the class now, we can do it without synchronization.
Java primitives
Class object
How we can work with collections after Java 7:
Java intermediate and terminal operation: