Async/await was introduced in NodeJS 7.6 and is currently supported in all modern browsers. I believe it has been the single greatest addition to JS since 2017. If you are not convinced, here are a bunch of reasons with examples why you should adopt it immediately and never look back.
package pt.joaobrito.java8;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.Month;
import java.time.Period;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
public class Main {
public static void main(String[] args) throws InterruptedException {
// simple lambda example
print("Hello Lambda", s -> s.length());
// another lambda example
new Thread(() -> System.out.println("Hello Runnable")).start();
List<Person> people = new ArrayList<>(Arrays.asList(
new Person("John Doe", LocalDate.of(1978, Month.JUNE, 14)),
new Person("Jane Doe", LocalDate.of(1983, Month.FEBRUARY, 16)),
new Person("Steven Smith", LocalDate.of(2008, Month.SEPTEMBER, 23)),
new Person("Martin", LocalDate.of(2010, Month.NOVEMBER, 27)),
new Person("Mike", LocalDate.of(2012, Month.NOVEMBER, 3)),
new Person("Louis", LocalDate.of(2014, Month.NOVEMBER, 6)),
new Person("Mary", LocalDate.of(2016, Month.FEBRUARY, 16))
));
System.out.println("---- All people sorted by name -----");
people.sort((p1, p2) -> p1.getName().compareTo(p2.getName()));
people.forEach(p -> System.out.println(p.getName()));
System.out.println("---- All people -----");
people = new ArrayList<>(Arrays.asList(
new Person("John Doe", LocalDate.of(1978, Month.JUNE, 14)),
new Person("Jane Doe", LocalDate.of(1983, Month.FEBRUARY, 16)),
new Person("Steven Smith", LocalDate.of(2008, Month.SEPTEMBER, 23)),
new Person("Martin", LocalDate.of(2010, Month.NOVEMBER, 27)),
new Person("Mike", LocalDate.of(2012, Month.NOVEMBER, 3)),
new Person("Louis", LocalDate.of(2014, Month.NOVEMBER, 6)),
new Person("Mary", LocalDate.of(2016, Month.FEBRUARY, 16))
));
people.stream().map(Person::getName).forEach(System.out::println); // using method reference
System.out.println("---- People older than 9 yrs -----");
people
.stream() // convert to stream
.filter(p -> Period.between(p.getDob(), LocalDate.now()).getYears() > 9) // get only the people thaht matches the given condition
.map(Person::getName) // get a new stream with only the names => returns Stream<String>
.forEach(System.out::println); // iterates the entire stream and prints out each element
System.out.println("---- Remove items from list -----");
people.removeIf(i -> i.getAge() < 2); // remove if the given condition is true
people.
stream()
.map(Person::getName)
.sorted(Comparator.reverseOrder()) // order the list in reverse order
.forEach(System.out::println);
// calculate time between two dates
LocalDate dob = LocalDate.of(1978, 6, 14);
LocalDate now = LocalDate.now();
Period p = Period.between(dob, now);
System.out.println("Priod of " + p.getYears() + " years; " + p.getMonths() + " months, " + p.getDays() + " days.");
// calculate time between two instants
Instant start = Instant.now();
Thread.sleep(1000);
Instant end = Instant.now();
System.out.println("The time is... " + Duration.between(start, end).toMillis());
// Optional<T>
Optional<String> opt = Optional.ofNullable("some string"); // not null value
System.out.println(opt.orElse("or else"));
opt.orElseThrow(UnsupportedOperationException::new);
opt = Optional.ofNullable(null); // notice that here we pass a null value
System.out.println(opt.orElse("or else"));
opt.orElseThrow(UnsupportedOperationException::new);
}
public static void print(String s, MyLambda l) {
System.out.println(l.getLength(s));
}
}
@FunctionalInterface
interface MyLambda {
int getLength(String s);
}
package pt.joaobrito.java8;
import java.time.LocalDate;
import java.time.Period;
public class Person {
private String name;
private LocalDate dob;
public Person(String name, LocalDate dob) {
this.name = name;
this.dob = dob;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public LocalDate getDob() {
return dob;
}
public void setDob(LocalDate dob) {
this.dob = dob;
}
public int getAge(){
return Period.between(dob, LocalDate.now()).getYears();
}
}
…and here are the results from running the file above
------------------------------------------------------------------------
Building Java8 0.0.1-SNAPSHOT
------------------------------------------------------------------------
--- exec-maven-plugin:1.2.1:exec (default-cli) @ Java8 ---
12
Hello Runnable
---- All people sorted by name -----
Jane Doe
John Doe
Louis
Martin
Mary
Mike
Steven Smith
---- All people -----
John Doe
Jane Doe
Steven Smith
Martin
Mike
Louis
Mary
---- People older than 9 yrs -----
John Doe
Jane Doe
---- Remove items from list -----
Steven Smith
Mike
Mary
Martin
Louis
John Doe
Jane Doe
Priod of 39 years; 9 months, 9 days.
The time is... 1014
some string
or else
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.Optional.orElseThrow(Optional.java:290)
at pt.joaobrito.java8.Main.main(Main.java:83)
------------------------------------------------------------------------
BUILD FAILURE
------------------------------------------------------------------------
Total time: 1.649 s
Finished at: 2018-03-23T00:07:33+00:00
Final Memory: 8M/309M
------------------------------------------------------------------------
Note that the build fails because we pass null to the Optional and we have a condition to throw an exception if null is passed to it (this is the reason why this line is the last statement of this example).
This is a simple JSF page with two date inputs and a submit button. When we press the button a the validation process will start via the backing bean that call a super class method.
Backing Bean:
@Named
@RequestScoped
public class SimpleDateRangeController extends AbstractController {
private SimpleDateRangeDto dto;
@PostConstruct
public void init() {
dto = new SimpleDateRangeDto();
}
public SimpleDateRangeController() {
}
public void action() {
super.validate(dto);
}
// getters and setters
}
</pre>
Note that in line 3 we have the super class named: AbstractController. In line 16, in the action method, we call a validate method and we pass as a parameter the dto wich has the data itself.
Abstract Controller
public class AbstractController implements Serializable {
protected <T extends DateRangeValidation> void validate(T dto) {
dto.validate();
}
}
In this abstract class we simple call the validate() method in the received DTO.
Data Transfer Object(DTO):
@ValidDateRange(endDesc = "end date", startDesc = "start date")
public class SimpleDateRangeDto extends DateRangeValidation {
private Date startDate;
private Date endDate;
// getters and setters
}
Here is the point where we annotate at the class-level with our special annotation. We simple use the annotation with 2 parameters. This parameters are optional and it’s purpose is only to personalize the error message. In case that your date fields are different from those in this example you must provide the annotation with more parameters, as you will see in the next class.
Here is where the magic happens. I will not discuss how annotations work, but I will cover the essential part: the constraint validation. The inner class DateIntervalValidator is responsible for the validation of the date fields with the help of reflection. We get the get methods of the two date fields and then we verify if endDate is after startDate. If that condition is false, we return false, otherwise we return true.
The message is required if you want personalize your message.
The start is required if your first date field is different from startDate. It indicates the name of the first field.
The end is required if your end date field is different from endDate. It indicates the name of the second date field.
The purpose the startDesc and endDesc is to use as a placeholder in the message parameter.
Validator:
public abstract class DateRangeValidation implements Serializable {
private static final long serialVersionUID = 7083856980011157895L;
public void validate() {
ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
Validator validator = validatorFactory.getValidator();
Set<ConstraintViolation<DateRangeValidation>> result = validator.validate(this);
if (!result.isEmpty()) {
Iterator<ConstraintViolation<DateRangeValidation>> it = result.iterator();
while (it.hasNext()) {
String mesg = it.next().getMessage();
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, mesg, mesg));
}
FacesContext.getCurrentInstance().validationFailed();
}
}
}
This class is the trigger of all the validation process. When in the DTO we call the validate method, is this method we are calling, because this class is the superclass of the DTO. It calls the annotation and validates the fields. If there are any erros it will collect them in a set, here called as result. Then we iterate all over the set and add the error messages to faces context.
The next few files demonstrate the same logic applied to 2 or more groups of date validations.
@Named
@RequestScoped
public class MultipleDateRangeController extends AbstractController {
private MultipleDateRangeDto dto;
@PostConstruct
public void init() {
dto = new MultipleDateRangeDto();
}
public MultipleDateRangeController() {
}
public void action() {
super.validate(dto);
}
// getters and setters
}
DTO:
@ValidDateRange.List({
@ValidDateRange(start = "date1", end = "date2", message = "{end} must be after {start}"),
@ValidDateRange(start = "date3", end = "date4", message = "{end} must be after {start}")
})
public class MultipleDateRangeDto extends DateRangeValidation {
private Date date1;
private Date date2;
private Date date3;
private Date date4;
// getters and setters
}
Plase feel free to comment or to suggest new features.
You can read more about this topic here
Download source code.
Thanks.
package staticbinder;
class Animal {
static void talk() { System.out.println("Animal doesen't talk!!"); }
void eat() { System.out.println("Animal eating..."); }
}
class Dog extends Animal {
static void talk() { System.out.println("Dog barking..."); }
@Override
void eat() { System.out.println("Dog eating..."); }
}
public class Main {
public static void main(String[] args) {
Animal a = new Dog();
/* static binding happens in private, final, static and
* overloaded methods at compile time
*/
a.talk(); // will print: Animal doesen't talk!!
/* dynamic binding happens in overriding methods at
* run time
*/
a.eat(); // will print: Dog eating...
}
}