Java+8+in+Action is a great book introducing new features in java 1.8. Have read some chapters. A lot of good examples. Taking some notes here.
- A lambda expression can be understood as a kind of anonymous function: it doesn’t have a name, but it has a list of parameters, a body, a return type, and also possibly a list of exceptions that can be thrown.
- Lambda expressions let you pass code concisely.
- A functional interface is an interface that declares exactly one abstract method.
- Lambda expressions can be used only where a functional interface is expected.
- Lambda expressions let you provide the implementation of the abstract method of a functional interface directly inline and treat the whole expression as an instance of a functional interface.
- Java 8 comes with a list of common functional interfaces in the java.util .function package, which includes Predicate<T>, Function<T, R>, Supplier<T>, Consumer<T>, and BinaryOperator<T>.
- There are primitive specializations of common generic functional interfaces such as Predicate<T> and Function<T, R> that can be used to avoid boxing operations: IntPredicate, IntToLongFunction, and so on.
- Method references let you reuse an existing method implementation and pass it around directly.
- Functional interfaces such as Comparator, Predicate, and Function have several default methods that can be used to combine lambda expressions.
the Streams API in Java 8 lets you write code that’s
Declarative— More concise and readable
Composable— Greater flexibility
Parallelizable— Better performance
Stream vs Collection
Streams is declarative while Collections is imperative.
Streams is internal iteration while Collections is external iteration
Collection is like a DVD where we have the whole thing, Stream is like movie online and we get bytes to bytes.
Problems with null
- It’s a source of error. NullPointerException is by far the most common exception in Java.
- It bloats your code. It worsens readability by making it necessary to fill your code with often deeply nested null checks.
- It’s meaningless. It doesn’t have any semantic meaning, and in particular it represents the wrong way to model the absence of a value in a statically typed language.
- It breaks Java philosophy. Java always hides pointers from developers except in one case: the null pointer.
- It creates a hole in the type system. null carries no type or other information, meaning it can be assigned to any reference type. This is a problem because, when it’s propagated to another part of the system, you have no idea what that null was initially supposed to be.
other language solution
Haskell includes a Maybe type, which essentially encapsulates an optional value. A value of type Maybe can contain either a value of a given type or nothing. There’s no concept of a null reference. Scala has a similar construct called Option[T] to encapsulate the presence or absence of a value of type T. You then have to explicitly check whether a value is present or not using operations available on the Option type, which enforces the idea of “null checking.” You can no longer forget to do it because it’s enforced by the type system.
java 8 option
It’s important to note that the intention of the Optional class is not to replace every single null reference. Instead, its purpose is to help you design more-comprehensible APIs so that by just reading the signature of a method, you can tell whether to expect an optional value. This forces you to actively unwrap an optional to deal with the absence of a value.
If we have a object needed to be de/serialized, we should avoid Optional or provide both the raw field and the Optional field.
Use map/flatMap plus orElse to achieve what if/else has.
discourage of using primitive optional like Optional<Integer> due to lack of methods like map/flatMap/filter etc. use OptionalInt, OptionalLong and OptionalDouble.
- Reducing shared mutable data structures can help you maintain and debug your programs in the long term.
- Functional-style programming promotes side-effect-free methods and declarative programming.
- Function-style methods are characterized only by their input arguments and their output result.
- A function is referentially transparent if it always returns the same result value when called with the same argument value. Iterative constructs such as while loops can be replaced by recursion.
- Tail recursion may be a better practice than classic recursion in Java because it opens the way to eventual compiler optimization. (currently java does NOT do this optimization)
problems with Data/Calendar
In Java 1.0 the only support for date and time was the java.util.Date class. Despite its name, this class doesn’t represent a date but a point in time with milliseconds precision. Even worse, the usability of this class is harmed by some nebulous design decisions like the choice of its offsets: the years start from 1900, whereas the months start at index 0.
The DateFormat also comes with its own set of problems. For example, it isn’t thread-safe. This means that if two threads try to parse a date using the same formatter at the same time, you may receive unpredictable results.
Finally, both Date and Calendar are mutable classes. What does it mean to mutate the 18th of March 2014 to the 18th of April? This design choice can lead you into a maintenance nightmare, as you’ll learn in more detail in the next chapter, which is about functional programming.
- The date-time objects of the new Date and Time API are all immutable.
- This new API provides two different time representations to manage the different needs of humans and machines when operating on it.
- You can manipulate date and time objects in both an absolute and relative manner, and the result of these manipulations is always a new instance, leaving the original one unchanged.
- TemporalAdjusters allow you to manipulate a date in a more complex way than just changing one of its values, and you can define and use your own custom date transformations.
- You can define a formatter to both print and parse date-time objects in a specific format. These formatters can be created from a pattern or programmatically and they’re all thread-safe.
Interface Default method(cha-9)
Interfaces in Java 8 can have implementation code through default methods and static methods.
Default method is great for interface(API) enhancement. It is a good fit for optional method so that the implementer does not have to provide implementation.
There are three rules to follow when a class inherits a method with the same signature from multiple places (such as another class or interface):
1. Classes always win. A method declaration in the class or a superclass takes priority over any default method declaration.
2. Otherwise, sub-interfaces win: the method with the same signature in the most specific
default-providing interface is selected. (If B extends A, B is more specific than A).
3. Finally, if the choice is still ambiguous, the class inheriting from multiple interfaces has to explicitly select which default method implementation to use by overriding it and calling the desired method explicitly.