Thursday, February 11, 2016

JDK 8



http://www.rationaljava.com/2015/04/cheating-with-exceptions-java-8-lambdas.html
Consider this snippet of code which you might want to write:

public void createTempFileForKey(String key) {
  Map<String, File> tempFiles = new ConcurrentHashMap<>();
  //does not compile because it throws an IOException!!
  tempFiles.computeIfAbsent(key, k -> File.createTempFile(key, ".tmp"));
}

For it to compile you need to catch the exception which leaves you with this code:

public void createTempFileForKey(String key) {
    Map<String, File> tempFiles = new ConcurrentHashMap<>();
    tempFiles.computeIfAbsent(key, k -> {
        try {
            return File.createTempFile(key, ".tmp");
        }catch(IOException e) {
            e.printStackTrace();
            return null;
        }
    });
}

Although this compiles, the IOException has effectively been swallowed.  The user of this method should be informed that an Exception has been thrown.

http://www.baeldung.com/java-lambda-exceptions

https://www.nurkiewicz.com/2013/08/optional-in-java-8-cheat-sheet.html
1
2
3
opt.
   filter(x -> x.contains("ab")).
   ifPresent(this::print);
This is equivalent to more imperative:

?
1
2
3
if(opt.isPresent() && opt.get().contains("ab")) {
    print(opt.get());
}

1
2
3
4
opt.
    map(String::trim).
    filter(t -> t.length() > 1).
    ifPresent(this::print);
This becomes tricky. Optional.map() applies given function on a value inside Optional - but only if Optional is present. Otherwise nothing happens and empty()is returned.

With Optional we can say:

?
1
int len = opt.map(String::length).orElse(-1);
There is also a version that accepts Supplier<T> if computing default value is slow, expensive or has side-effects:

?
1
2
3
int len = opt.
    map(String::length).
    orElseGet(() -> slowDefault());     //orElseGet(this::slowDefault)


Optional<String> similar = opt.map(this::findSimilar);
If the function we map() over returns null, the result of map() is an empty Optional. Otherwise it’s the result of said function wrapped with (present) Optional. So far so good but why do we return null-able value if we have Optional?

?
1
public Optional<String> tryFindSimilar(String s)  //...
Our intentions are clear but using map() fails to produce correct type. Instead we must use flatMap():


?
1
2
Optional<Optional<String>> bad = opt.map(this::tryFindSimilar);
Optional<String> similar =       opt.flatMap(this::tryFindSimilar);

1
2
3
4
opt.
    filter(s -> !s.isEmpty()).
    map(s -> s.charAt(0)).
    orElseThrow(IllegalArgumentException::new);
We don’t want to create an instance of exception in advance because creating an exception has significant cost.
1
2
3
4
5
return person.
        flatMap(Person::getAddress).
        flatMap(Address::getValidFrom).
        filter(x -> x.before(now())).
        isPresent();
Is it more readable? Hard to tell. But at least it’s impossible to produce NullPointerException when Optional is used consistently.

http://www.deadcoderising.com/2017-02-14-java-8-declarative-ways-of-modifying-a-map-using-compute-merge-and-replace/
map.computeIfAbsent("Java", this::heavyOperationToFetchArticles);  

map.computeIfPresent("Java", (key, value) -> sortAlphabetically(value));  

if (map.containsKey("Java")) {  
  map.get("Java").addAll(javaArticles);
} else {
  map.put("Java", javaArticles);
}
=>

map.merge("Java", javaArticles, (list1, list2) ->  
  Stream.of(list1, list2)
    .flatMap(Collection::stream)
    .collect(Collectors.toList()));

map.replaceAll((key, val) -> getUpdatedListFor(key));  

http://www.deadcoderising.com/how-to-generate-a-stream-of-random-numbers-in-java/
new Random().ints(5);  
Setting a range for the random numbers
new Random().ints(0, 11);  
//> 5, 5, 10, 8, 4 (...)

new Random().ints(5, 0, 11);  

http://www.deadcoderising.com/java-9-10-4-new-methods-in-the-optional-api/
article.ifPresent(this::publish);  

article.ifPresentOrElse(  
  this::publish,                       
  this::notifyThatNothingWasPublished
);



getFeatureArticle().or(() -> Optional.of(getBackupArticle()));  



Stream.concat(  
  getFeatureArticle().stream(),
  getLatestArticles()
);



If the Optional is empty however, it'll throw a NoSuchElementException.

getFeatureArticle().orElseThrow();  

getFeatureArticle().orElseThrow(IllegalStateException::new);  

http://www.deadcoderising.com/2017-02-21-java-8-accumulate-your-streams-using-collectors/
articles.collect(Collectors.toMap(Article::getTitle, Function.identity()));  
articles.collect(Collectors.averagingInt(Article::getWordCount));  

articles.collect(Collectors.summingInt(Article::getWordCount));  



articles.map(Article::getTitle)  
        .collect(Collectors.joining());
articles.map(Article::getTitle)  
        .collect(Collectors.joining(", "));

That’s better, but there is actually one more version where you also can add a prefix and suffix to the resulting string.

articles.map(Article::getTitle)  
        .collect(Collectors.joining(", ", "Articles: ", "."));

Comparator<Article> wordCountComparator = (a1, a2) -> a1.getWordCount() - a2.getWordCount();

articles.collect(Collectors.maxBy(wordCountComparator));  

articles  
  .collect(Collectors.partitioningBy(article -> article.getWordCount() > 1000));
This will result in a map with two entries. One with the key true which contains the articles that satisfied the predicate and one with key false with the articles that didn’t satisfy the predicate.
Then you can use collectingAndThen to append a function that will be executed on the result of the collector.
articles.collect(  
  Collectors.collectingAndThen(
    Collectors.averagingInt(Article::getWordCount),
    average -> "Average count: " + average));

articles.collect(Collectors.groupingBy(Article::getTag));  



articles.collect(  
  Collectors.groupingBy(
    Article::getTag,
    Collectors.summingInt(Article::getWordCount)));


articles  
  .map(Article::getTitle)
  .collect(Collectors.toList());
Another option is to use Collectors.mapping.
articles.collect(Collectors.mapping(Article::getTitle, Collectors.toList()));  

We want to group our stream of articles by the tag, but we only want to keep the titles in the values.

To solve this, we need to keep the whole Article object long enough to do the grouping, but map to titles afterwards.
This is where mapping comes handy.
articles.collect(  
  Collectors.groupingBy(
    Article::getTag, 
    Collectors.mapping(Article::getTitle, Collectors.toList())));
By using mapping we’re able to first do grouping based on the whole Article object, before mapping it to titles.
The Collectors.filtering really starts to shine when it becomes part of another Collector.
we first want to group the articles by publisher year, then use the filteringmethod to keep only Java articles
getArticleStream().collect(  
  Collectors.groupingBy(
    Article::getPublishYear,
    Collectors.filtering(article -> article.getTags().contains("Java"), Collectors.toSet())));

 figure out what tags have been used in the different publishing years.
getArticleStream().collect(  
    Collectors.groupingBy(
      Article::getPublishYear,
      Collectors.flatMapping(article -> article.getTags().stream(), Collectors.toSet())));
https://stackoverflow.com/questions/10791568/calculating-average-of-an-array-list
If using Java8 you can get the average of the values from a List as follows:
    List<Integer> intList = Arrays.asList(1,2,2,3,1,5);

    Double average = intList.stream().mapToInt(val -> val).average().getAsDouble();
This has the advantage of having no moving parts. It can be easily adapted to work with a List of other types of object by changing the map method call.
For example with Doubles:
    List<Double> dblList = Arrays.asList(1.1,2.1,2.2,3.1,1.5,5.3);
    Double average = dblList.stream().mapToDouble(val -> val).average().getAsDouble();
or BigDecimals:
    List<BigDecimal> bdList = Arrays.asList(valueOf(1.1),valueOf(2.1),valueOf(2.2),valueOf(3.1),valueOf(1.5),valueOf(5.3));
    Double average = bdList.stream().mapToDouble(BigDecimal::doubleValue).average().getAsDouble();



http://www.deadcoderising.com/java-8-no-more-loops/
public Optional<Article> getFirstJavaArticle() {  
    return articles.stream()
        .filter(article -> article.getTags().contains("Java"))
        .findFirst();
    }
public List<Article> getAllJavaArticles() {  
    return articles.stream()
        .filter(article -> article.getTags().contains("Java"))
        .collect(Collectors.toList());
    }

public Map<String, List<Article>> groupByAuthor() {  
    return articles.stream()
        .collect(Collectors.groupingBy(Article::getAuthor));
}    

public Set<String> getDistinctTags() {  
    return articles.stream()
        .flatMap(article -> article.getTags().stream())
        .collect(Collectors.toSet());
}
https://github.com/biezhi/30-seconds-of-java8
获取当前工作目录。
public static String getCurrentWorkingDirectoryPath() {
    return FileSystems.getDefault().getPath("").toAbsolutePath().toString();
}
public static int[] stringToIntegers(String numbers) {
        return Arrays.stream(numbers.split(" ")).mapToInt(Integer::parseInt).toArray();
}
将给定的字符串转换为单词数组。
public static String[] words(String input) {
    return Arrays.stream(input.split("[^a-zA-Z-]+"))
            .filter(s -> !s.isEmpty())
            .toArray(String[]::new);
}
public static boolean isDebuggerAttached() {
    final RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
    return runtimeMXBean.getInputArguments()
            .stream()
            .anyMatch(arg -> arg.contains("-agentlib:jdwp"));

}

此方法检查指定的类是内部类还是静态嵌套类。
public static boolean isInnerClass(final Class<?> cls) {
    return cls != null && cls.getEnclosingClass() != null;
}
http://marxsoftware.blogspot.sg/2018/01/fine-grained-sorting-jdk-8.html
Java 8's introduction of streams and useful static/default methods on the Comparator interface make it easy to compare two objects based on individual fields' values without need to implement a compare(T,T) method on the class whose objects are being compared.

  1. private static List<Song> sortedSongsByYearArtistAlbum(  
  2.    final List<Song> songsToSort)  
  3. {  
  4.    return songsToSort.stream()  
  5.       .sorted(  
  6.          Comparator.comparingInt(Song::getYear)  
  7.                    .thenComparing(Song::getArtist)  
  8.                    .thenComparing(Song::getAlbum))  
  9.       .collect(Collectors.toList());  
http://marxsoftware.blogspot.sg/2018/01/jdk8-collections-maps.html
  1.    private static Map<String, Book> convertArrayToMap(final Book[] booksArray)  
  2.    {  
  3.       return Arrays.stream(booksArray).collect(  
  4.          Collectors.toMap(Book::getIsbn, book -> book));  
  5.    }  

https://blog.codefx.org/java/new-javadoc-tags/
* @apiNote This method was added after the interface was released in
*          version 1.0. It is defined as a default method for compatibility
*          reasons. From version 2.0 on, the method will be abstract and
*          all implementations of this interface have to provide their own
*          implementation of the method.
* @implSpec The default implementation will consider each player a winner
*           and return them in an unspecified order.
* @implNote This implementation has linear runtime and does not filter out
*           null players.

https://en.wikipedia.org/wiki/Higher-order_function
higher-order function (also functionalfunctional form or functor) is a function that does at least one of the following:
  • takes one or more functions as arguments (i.e., procedural parameters),
  • returns a function as its result
https://blog.idrsolutions.com/2015/02/java-8-method-references-explained-5-minutes/
Lambda FormList primeNumbers = ReferenceToStaticMethod.testPredicate(numbers, a -> ReferenceToStaticMethod.isPrime(a));
Method ReferenceList primeNumbers = ReferenceToStaticMethod.testPredicate(numbers, ReferenceToStaticMethod::isPrime);

Lambda FormList squaredNumbers = ReferenceToConstructor.findSquareRoot(numbers, x -> new Double(x));
Method ReferenceList squaredNumbers= ReferenceToConstructor.findSquareRoot(numbers,Double::new);


Lambda FormList allAges = ReferenceToInstanceMethodAOPT.listAllAges(persons, x -> x.getAge());
Method ReferenceList allAges = ReferenceToInstanceMethodAOPT.listAllAges(persons, Person::getAge);

Lambda FormReferenceToInstanceMethodOAPO.printNames(names, x -> System.out.println(x));
Method ReferenceReferenceToInstanceMethodOAPO.printNames(names,System.out::println);
https://forax.github.io/2014-01-29-8684788-Java8_in_8_methods.html
list.sort(null);                                    // use natural order
list.sort((s1, s2) -> s1.compareToIgnoreCase(s2));  // sort ignoring case
list.sort(String::compareToIgnoreCase);             // same with a method 
list.removeIf(s -> s.length() %2 == 0);

Java 8 introduces Map.getOrDefault to allow to specify the default value if there is no corresponding value in the Map.
Map<String, Long> map = new HashMap<>();
for(String s: args) {
    map.put(s, 1 + map.getOrDefault(s, 0L));
}
List<Person> people = ...
Map<String, List<Person>> byNameMap = new HashMap<>();
for(Person person: people) {
    String name = person.getName();
    List<Person> persons = byNameMap.get(name);
    if (persons == null) {
      persons = new ArrayList<>();
      byNameMap.put(name, persons);
    }
    persons.add(person);
}
Maybe, we can use getOrDefault ?
Map<String, List<Person>> byNameMap = new HashMap<>();
for(Person person: people) {
    String name = person.getName();
    List<Person> persons = byNameMap.getOrDefault(person.getName(), new ArrayList<>());
    byNameMap.put(name, persons);
    persons.add(person);
}
It works but it's inefficient because we create a new ArrayList at each call ofgetOrDefault even when a list already exist in the map. What we need is a way to delay the creation of the ArrayList until we really need it.
A lambda is a delayed calculation !
Map<String, List<Person>> byNameMap = new HashMap<>();
for(Person person: people) {
    byNameMap.computeIfAbsent(person.getName(), name -> new ArrayList<>()).add(person);
}
Note that this lambda doesn't use value of variable from outside of the lambda, so the JDK implementation will make it a constant (so please, do not store a lambda in a static final field, you do not need it !).
computeIfAbsent can also be used to implement a cache easily
Map<Integer, FairlyBigObject> map = ...
map.computeIfAbsent(id, id -> DB.findById(FairlyBigObject.class, id)); 

byNameMap.forEach((name, persons) -> {
  System.out.println(name + ' ' + persons);
});
which is in fact more efficient for maps like IdentityHashMap that doesn't store the key and the value in the same object (because IdentityHashMap.entrySet() has to re-create the Map.Entry on the fly :( ).
Map<String, List<Person>> byNameMap =
people.stream().collect(Collectors.groupingBy(Person::getName));

 Files.lines let you split a files into lines and closes cleanly the file descriptor when not needed anymore.

Path file = Paths.get("file.txt");
Map<String, Long> histoMap =
    Files.lines(file)
         .flatMap(line -> Arrays.stream(line.split(" ")))
         .collect(Collectors.groupingBy(Function.identity(),
             Collectors.counting()));
Temporal.query()
Let suppose I want to aggregate several source of data, e.g. a database, some REST service, etc, each source uses its own way to represent the concept of date and time and I want to know the day of week of these temporal objects to display them in a UI.
List<Temporal> temporals = ...
temporals.stream().map(temporal -> temporal.query(DayOfWeek::from)).forEach(System.out::println);
java.time not only provides immutable types to play with date and time but also a meta-description of each of these classes that allows to query the value of several different temporal object greatly simplifying the code of the UI.
http://www.leveluplunch.com/blog/2014/03/12/java8-date-time-temporal-query/
public class HurricaneSeasonQuery implements TemporalQuery<Boolean> {

    /*
     * (non-Javadoc)
     * 
     * @see java.time.temporal.TemporalQuery#queryFrom(java.time.temporal.
     * TemporalAccessor)
     */
    @Override
    public Boolean queryFrom(TemporalAccessor temporal) {

        LocalDate date = LocalDate.from(temporal);

        MonthDay juneFirst = MonthDay.of(Month.JUNE.getValue(), 1);
        MonthDay novemberThirty = MonthDay.of(Month.NOVEMBER.getValue(), 30);

        if (date.isAfter(juneFirst.atYear(date.getYear()))
                && date.isBefore(novemberThirty.atYear(date.getYear()))) {
            return true;
        } else {
            return false;
        }
    }
}
    Boolean isHurricaneSeason = date.query(new HurricaneSeasonQuery());









Hopefully using TemporalQueries will allow you to refactor or eliminate the static classes to produce cleaner code for asking questions about dates.
http://www.oracle.com/webfolder/technetwork/tutorials/moocjdk8/documents/week1/lesson-1-7.pdf
Iterable Interface
Iterable.forEach(Consumer c)
List<String> myList = ...
myList.forEach(s -> System.out.println(s));
myList.forEach(System.out::println);

Collection.removeIf(Predicate p)
List<String> myList = ...
myList.removeIf(s -> s.length() == 0);

List.replaceAll(UnaryOperator o)
List<String> myList = ...
myList.replaceAll(s -> s.toUpperCase());
myList.replaceAll(String::toUpperCase);

    default void replaceAll(UnaryOperator<E> operator) {
        Objects.requireNonNull(operator);
        final ListIterator<E> li = this.listIterator();
        while (li.hasNext()) {
            li.set(operator.apply(li.next()));
        }
    }

List.sort(Comparator c)
 Replaces Collections.sort(List l, Comparator c)
List<String> myList = ...
myList.sort((x, y) -> x.length() – y.length());
    default void sort(Comparator<? super E> c) {
        Object[] a = this.toArray();
        Arrays.sort(a, (Comparator) c);
        ListIterator<E> i = this.listIterator();
        for (Object e : a) {
            i.next();
            i.set((E) e);
        }
    }

Logger Class
 This is a common problem
– logger.finest(createComplexMessage());
 createComplexMessage() is always called, even when not required
– Heisenberg’s Uncertainty Principle in software
 New methods in Logger class
– Takes a Supplier as an argument (which is a functional interface)
 Simple change to code has big impact on performance
– logger.finest(() -> createComplexMessage());
 We now pass how to create the message, not the actual message

    public void warning(Supplier<String> msgSupplier) {
        log(Level.WARNING, msgSupplier);
    }
Represents a supplier of results.
@FunctionalInterface
public interface Supplier<T> {
    T get();
}

Use the new methods in JDK 8 to eliminate the frequent need for loops
 Remember that a Lambda provides behaviour, not a value
– Very useful for conditional uses of data
 Lambda expressions provide a simple way to pass behaviour as a
parameter, or assign to a variable
 They can be used wherever a functional interface type is used
– The Lambda provides the implementation of the single abstract method
 Method and constructor references can be used as shorthand
 Several useful new methods in JDK 8 that can use Lambdas
http://blog.jooq.org/2014/02/14/java-8-friday-goodies-map-enhancements/
If you want a quick overview of feature additions, go to the JDK8 Javadoc and click on the new “Default Methods” tab.

compute() methods

Often, we fetch a value from a map, make some calculations on it and put it back into the map. This can be verbose and hard to get right if concurrency is involved. With Java 8, we can pass a BiFunction to the new compute(),computeIfAbsent(), or computeIfPresent() methods and have the Mapimplementation handle the semantics of replacing a value.
The following example shows how this works:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// We'll be using this simple map
// Unfortunately, still no map literals in Java 8..
Map<String, Integer> map = new HashMap<>();
map.put("A", 1);
map.put("B", 2);
map.put("C", 3);
// Compute a new value for the existing key
System.out.println(map.compute("A",
    (k, v) -> v == null ? 42 : v + 41));
System.out.println(map);
// This will add a new (key, value) pair
System.out.println(map.compute("X",
    (k, v) -> v == null ? 42 : v + 41));
System.out.println(map);
The output of the above program is this:
42
{A=42, B=2, C=3}
42
{A=42, B=2, C=3, X=42}
This is really useful for ConcurrentHashMap, which ships with the following guarantee:
The entire method invocation is performed atomically. Some attempted update operations on this map by other threads may be blocked while computation is in progress, so the computation should be short and simple, and must not attempt to update any other mappings of this Map.
map.forEach((k, v) ->
    System.out.println(k + "=" + v));



Unfortunately, there are two types of Maps. Those supporting null keys and/or values and those who don’t support nulls. While the previousmerge() method didn’t distinguish between a map not containing a key and a map containing a key with a null value, this new getOrDefault() only returns the default when the key is not contained. It won’t protect you from aNullPointerException:
map.put("X", null);
try {
  System.out.println(map.getOrDefault("X", 21) + 21);
}
catch (NullPointerException nope) {
  nope.printStackTrace();
}
There are a few more methods, like putIfAbsent() (pulled up fromConcurrentHashMapremove() (with key and value arguments),replace().
List<String> list = ...
list.sort(null);                                    // use natural order
list.sort((s1, s2) -> s1.compareToIgnoreCase(s2));  // sort ignoring case
list.sort(String::compareToIgnoreCase);             // same with a method reference
If sort is called with null, the element of the list must be comparable with themselves, otherwise, you can specify a comparator, either as a lambda or as a method reference.
    public static <T> void Arrays.sort(T[] a, Comparator<? super T> c) {
        if (c == null) {
            sort(a);
        } else {
            if (LegacyMergeSort.userRequested)
                legacyMergeSort(a, c);
            else
                TimSort.sort(a, 0, a.length, c, null, 0, 0);
        }
    }

list.removeIf(s -> s.length() %2 == 0);
so now, there is no excuse to use an Iterator explicitly anymore.
Map<String, Long> map = new HashMap<>();
for(String s: args) {
    map.put(s, 1 + map.getOrDefault(s, 0L));
}

Let suppose I want to group a list of Person by their name into a Map. Again, I have to separate the case where there is no value associated to a string or not.

List<Person> people = ...
Map<String, List<Person>> byNameMap = new HashMap<>();
for(Person person: people) {
    String name = person.getName();
    List<Person> persons = byNameMap.get(name);
    if (persons == null) {
      persons = new ArrayList<>();
      byNameMap.put(name, persons);
    }
    persons.add(person);
}

Maybe, we can use getOrDefault ?

Map<String, List<Person>> byNameMap = new HashMap<>();
for(Person person: people) {
    String name = person.getName();
    List<Person> persons = byNameMap.getOrDefault(person.getName(), new ArrayList<>());
    byNameMap.put(name, persons);
    persons.add(person);
}

It works but it's inefficient because we create a new ArrayList at each call ofgetOrDefault even when a list already exist in the map. What we need is a way to delay the creation of the ArrayList until we really need it.
A lambda is a delayed calculation !

Map<String, List<Person>> byNameMap = new HashMap<>();
for(Person person: people) {
    byNameMap.computeIfAbsent(person.getName(), name -> new ArrayList<>()).add(person);
}

Note that this lambda doesn't use value of variable from outside of the lambda, so the JDK implementation will make it a constant (so please, do not store a lambda in a static final field, you do not need it !).

computeIfAbsent can also be used to implement a cache easily

map.computeIfAbsent(id, id -> DB.findById(FairlyBigObject.class, id)); 



In fact, you don't need to use computeIfAbsent if you want to do a groupBy, you can transform the collection or the array to a Stream of objects, do transformation on each one and then collect all the results in a List or a Map using a set predefinedCollectors.

Map<String, List<Person>> byNameMap =
people.stream().collect(Collectors.groupingBy(Person::getName));



Path file = Paths.get("file.txt");
Map<String, Long> histoMap =
    Files.lines(file)
         .flatMap(line -> Arrays.stream(line.split(" ")))
         .collect(Collectors.groupingBy(Function.identity(),
             Collectors.counting()));

putIfAbsent adds an element with the specified Value whereas computeIfAbsent adds an element with the value computed using the Key.
http://www.studytrails.com/java/java8/java8_collections_new_methods.jsp
authorBooks.compute("Clive Cussler", (a, b) -> b + 1);
If the compute function returns null then the entry for that key is removed from the map. If the key is not present then a new entry is added.

authorBooks.computeIfAbsent("Agatha Christie", b -> b.length());
The entry is added only if the computed value is not null.
authorBooks.computeIfPresent("Tom Clancy", (a, b) -> b + 1);

If the key is not present or if the value for the key is null, then adds the key-value pair to the map. If the key is present then replaces the value with the value from the remapping function. If the remapping function return null then the key is removed from the map.
authorBooks.merge("AuthorB", 1, (a, b) -> a + b);
System.out.println(authorBooks.get("AuthorB"));// 1
authorBooks.merge("AuthorB", 1, (a, b) -> a + b);
System.out.println(authorBooks.get("AuthorB"));//2

replaces all values by the values computed from this function.
authorBookMap.replaceAll((a,b)->a.length()+b);

V replace(K key, V newValue)

boolean replace(K key, V oldValue, V newValue)
If the key is present and is mapped to the oldValue, then it is remapped to the newValue.

boolean remove(Object key, Object value)

removes the key only if its associated with the given value

http://www.adam-bien.com/roller/abien/entry/java_8_reading_a_file
        String content = new String(Files.readAllBytes(Paths.get("duke.java")));
        try (BufferedReader buffer = new BufferedReader(new InputStreamReader(input))) {
            return buffer.lines().collect(Collectors.joining("\n"));
        }

        Map<String, Integer> workshopsMap = workshops.
                stream().
                collect(Collectors.toMap(Workshop::getName,Workshop::getAttendance));


        List<String> teamLanguages = team.stream().
                map(d -> d.getLanguages()).
                flatMap(l -> l.stream()).
                collect(Collectors.toList());

team.stream().flatMap(d -> d.getLanguages().stream()).collect(Collectors.toList());

        Files.write(Paths.get("./duke.txt"), msg.getBytes());
        StringJoiner sj = new StringJoiner(",");
        sj.add("duke").add("java");

        String actual = String.join(",", "duke", "java");


With Java 8 and the compiler flag: javac -parameters method parameter names are available via reflection.
        Method[] methods = Boundary.class.getMethods();
        for (Method method : methods) {
            System.out.print(method.getName() + "(");
            Parameter[] parameters = method.getParameters();
            for (Parameter parameter : parameters) {
                System.out.print(parameter.getType().getName() + " " + parameter.getName() + " ");
            }
            System.out.println(")");
        }

import static java.util.Objects.requireNonNull;
        requireNonNull(this.script, "Cannot initialize ScriptableSink without script.");

long lineCount = Files.lines(path).count();

    public static Stream<String> lines(Path path, Charset cs) throws IOException {

        BufferedReader br = Files.newBufferedReader(path, cs);

        try {

            return br.lines().onClose(asUncheckedRunnable(br));

        } catch (Error|RuntimeException e) {

            try {

                br.close();

            } catch (IOException ex) {

                try {

                    e.addSuppressed(ex);

                } catch (Throwable ignore) {}

            }

            throw e;

        }

    }
    private static Runnable asUncheckedRunnable(Closeable c) {
        return () -> {
            try {
                c.close();
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
        };

    }
http://www.adam-bien.com/roller/abien/entry/java_8_streaming_a_string
        "hey duke".chars().forEach(c -> System.out.println((char)c));

The parallel version does not preserve the order (and comes with additional overhead):
    public static void main(String[] args) {
        "hey duke".chars().parallel().forEach(c -> System.out.println((char) c));

http://www.adam-bien.com/roller/abien/entry/java_8_from_ordinary_for
IntStream.range(0, 10).forEach(
 nbr -> System.out.println(nbr)
);
Why? ...because the execution of the following snippet takes 1 second and not 10 seconds:
IntStream.range(0, 10).parallel().forEach(
 nbr -> {
 try {
  Thread.sleep(1000);
  } catch (InterruptedException ex) {}
         System.out.println(nbr);
        }
);

   Stream<String> uuidStream = Stream.
     generate(UUID::randomUUID).
     map(u -> u.toString());

   uuidStream.
     limit(10).
     forEach(System.out::println);

Java 8 comes with the java.util.Base64 class entirely dedicated to Basic, URL, Filenames and MIMEs encoding and decoding.


        List<String> mascots = new ArrayList<>();
        mascots.add("duke");
        mascots.add("juggy");

        String expected = "duke,juggy";
        String actual = mascots.stream().
                reduce((t, u) -> t + "," + u).
                get();


http://www.infoq.com/articles/Java-8-Quiet-Features
The problem is that the ReadWriteLock can be super slow(up to 10x), which kind of defeats its purpose. Java 8 introduces a new ReadWrite lock – called StampedLock. The good news here is that this guy is seriously fast. The bad news is that it’s more complicated to use and lugs around more state. It’s also not reentrant, which means a thread can have the dubious pleasure of deadlocking against itself.

To help with this Java 8 has added several new “exact” methods to the Math class geared towards protecting sensitive code from implicit overflows, by throwing an unchecked ArithmeticException when the value of an operation overflows its precision.
int safeC = Math.multiplyExact(bigA, bigB); // will throw ArithmeticException if result exceeds +-2^31
The only downside is that it’s up to you to find those places in your code where overflows can happen.
    public static int addExact(int x, int y) {
        int r = x + y;
        // HD 2-12 Overflow iff both arguments have the opposite sign of the result
        if (((x ^ r) & (y ^ r)) < 0) {
            throw new ArithmeticException("integer overflow");
        }
        return r;

    }
    public static int subtractExact(int x, int y) {
        int r = x - y;
        // HD 2-12 Overflow iff the arguments have different signs and
        // the sign of the result is different than the sign of x
        if (((x ^ y) & (x ^ r)) < 0) {
            throw new ArithmeticException("integer overflow");
        }
        return r;

    }

Java 8 has added a new method called SecureRandom.getInstanceStrong() whose aim is to have the JVM choose a secure provider for you. If you’re writing code without complete control of the OS / hardware / JVM on which it would run (which is very common when deploying to the cloud or PaaS), my suggestion is to give this approach some serious consideration.

7. Secure Random Generation

Java 8 has added a new method called SecureRandom.getInstanceStrong() whose aim is to have the JVM choose a secure provider for you. If you’re writing code without complete control of the OS / hardware / JVM on which it would run (which is very common when deploying to the cloud or PaaS), my suggestion is to give this approach some serious consideration.

5. Controlling OS Processes

Launching an OS process from within your code is right there with JNI calls – it’s something you do half-knowing there’s a good chance you’re going to get some unexpected results and some really bad exceptions down the line.
Even so, it’s a necessary evil. But processes have another nasty angle to them - they have a tendency to dangle. The problem with launching process from within Java code so far has been that is was hard to control a process once it was launched.
To help us with this Java 8 introduces three new methods in the Process class -
  1. destroyForcibly - terminates a process with a much higher degree of success than before.
  2. isAlive tells if a process launched by your code is still alive.
  3. A new overload for waitFor() lets you specify the amount of time you want to wait for the process to finish. This returns whether the process exited successfully or timed-out in which case you might terminate it.
Two good use-cases for these new methods are -
  • If the process did not finish in time, terminate and move forward:
if (process.wait(MY_TIMEOUT, TimeUnit.MILLISECONDS)){
       //success! }
else {
    process.destroyForcibly();
}
  • Make sure that before your code is done, you're not leaving any processes behind. Dangling processes can slowly but surely deplete your OS.
for (Process p : processes) {
       if (p.isAlive()) {
             p.destroyForcibly();
       }
}
https://nikolaygrozev.wordpress.com/2015/07/30/summary-of-the-oracle-jdk8-mooc/
an interface is called functional, if it has only one abstract method. In previous Java versions, all interface methods were abstractIn Java 8 interfaces can have default and static methods as well. In order for an interface to be function it should have exactly one abstract method regardless if any default or static methods are defined. It is recommended to annotate functional interfaces with the @FunctionalInterfaceannotation so that the compiler can check if they meet the requirement.

a lambda function can be thought of as a syntactic short-cut for defining anonymous instances of functional interfaces. Lambda expressions are defined with the following pattern:

1
(param1, param2, ... , paramN) -> expression | block of code

Comparator<Integer> cmp1 = (x, y) -> x.compareTo(y);   // Expression body. Types NOT specified

Comparator<Integer> cmp2 = (Integer x, Integer y) -> { // Block of code body. Types specified

    return x.compareTo(y);

};

Comparator<Integer> cmp3 = new Comparator<Integer>() { // Java 7 style

    public int compare(Integer x, Integer y) {

        return x.compareTo(y);

    }

};


Runnable r1 = () -> System.out.println("Test");         // Expression body

Runnable r2 = () -> { System.out.println("Test"); };    // Block of code body

Runnable r3 = new Runnable() {                          // Java 7 style

    public void run() {

        System.out.println("Test");

    }

};

Alike anonymous classes, lambdas can use the variables of their environment. When using local variables in lambdas, the must be effectively final, which means they are not assigned to from anywhere, regardless if they are actually marked as final.
Lambdas are a neat way to implement functional interfaces, but often all they do is call an existing method. To make things simpler Java 8 introduces method references. Method references are a shorthand for implementing functional interfaces by calling already defined methods.
REFERENCE TOSYNTAXLAMBDA EQUIVALENT
Static methodClass::staticMethod(param1, … paramN) -> Class.staticMethod(param1, … paramN)
Specific instance’s methodvar::instanceMethod(param1, … paramN) -> var.instanceMethod(param1, … paramN)
Instance methodClass::instanceMethod(var, param1, … paramN) -> var.instanceMethod(param1, … paramN)
ConstructorClass::new(param1, … paramN) -> new Class(param1, … paramN)
Predicate<String> p1 = Boolean::getBoolean;         // Static method reference
Predicate<String> p2 = s -> Boolean.getBoolean(s);  // Equivalent lambda
String var = "TestEquality";
Predicate<String> p1 = var::equals;         // Specific instance's method reference
Predicate<String> p2 = s -> var.equals(s);  // Equivalent lambda
Predicate<String> p1 = String::isEmpty;     // Instance method reference
Predicate<String> p2 = s -> s.isEmpty();    // Equivalent lambda
Predicate<String> p1 = Boolean::new;           // Constructor reference
Predicate<String> p2 = s -> new Boolean(s);    // Equivalent lambda
The standard library has always had a bunch of functional interfaces – Runnable, Callable, Comparator etc. Java 8 introduces a whole new package of functional interfaces called java.util.function.
In Java there are two kinds of types – referential and primitives. Java generics can only be used with referential types – e.g. List<int> is invalid. Thus, the java.util.function package contains multiple versions of each interface – a generic version for referential types, and specialised versions for the primitives. For example we’ve got Consumer<T> and IntConsumer
The andThen default method of the function interfaces works similarly – it chains the function invocation as in f(g(x)). The compose method does the same, but swaps the functions – i.e. g(f(x))instead of f(g(x)). The following example demonstrates this:
1
2
3
4
5
6
7
8
9
10
UnaryOperator<Integer> plus1 = x -> x + 1;
UnaryOperator<Integer> mult2 = x -> x * 2;
//Create a new function with andThen
Function<Integer, Integer> plus1Mult2 = plus1.andThen(mult2);
System.out.println(plus1Mult2.apply(1));// Prints 4
//Create a new function with compose
Function<Integer, Integer> mult2Plus1 = plus1.compose(mult2);
System.out.println(mult2Plus1.apply(1)); // Prints 3
Note: in the above example you may wish to use IntUnaryOperator instead of UnaryOperator<Integer> to avoid excessive boxing/unboxing.
Similarly, the predicate interfaces have default methods andor and negate, which can be used to create new predicates with combined logic.
    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }
    default Predicate<T> negate() {
        return (t) -> !test(t);
    }
    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }

Interfaces can now define static methods. For instance, a naturalOrder method was added to java.util.Comparator:
    enum NaturalOrderComparator implements Comparator<Comparable<Object>> {
        INSTANCE;

        @Override
        public int compare(Comparable<Object> c1, Comparable<Object> c2) {
            return c1.compareTo(c2);
        }

        @Override
        public Comparator<Comparable<Object>> reversed() {
            return Comparator.reverseOrder();
        }
    }
    public static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator) {
        return new Comparators.NullComparator<>(true, comparator);
    }
    public static <T> Comparator<T> nullsLast(Comparator<? super T> comparator) {
        return new Comparators.NullComparator<>(false, comparator);
    }

Why can't default methods override equals, hashCode, and toString?

An interface cannot provide a default implementation for any of the methods of the Object class. In particular, this means one cannot provide a default implementation for equals, hashCode, or toString from within an interface.
It would become more difficult to reason about when a default method is invoked. Right now it's simple: if a class implements a method, that always wins over a default implementation. Since all instances of interfaces are Objects, all instances of interfaces have non-default implementations of equals/hashCode/toString already. Therefore, a default version of these on an interface is always useless, and it may as well not compile.
Non-final variable capture - If a variable is assigned a new value, it can't be used within a lambda. The "final" keyword is not required, but the variable must be "effectively final" (discussed earlier). This code does not compile:
int count = 0;
List<String> strings = Arrays.asList("a", "b", "c");
strings.forEach(s -> {
    count++; // error: can't modify the value of count
});
Exception transparency - If a checked exception may be thrown from inside a lambda, the functional interface must also declare that checked exception can be thrown. The exception is not propogated to the containing method. This code does not compile:
void appendAll(Iterable<String> values, Appendable out)
        throws IOException { // doesn't help with the error
    values.forEach(s -> {
        out.append(s); // error: can't throw IOException here
                       // Consumer.accept(T) doesn't allow it
    });
}

Why abstract classes can't be instantiated using a lambda

An abstract class, even if it declares only one abstract method, cannot be instantiated with a lambda.
Two examples of classes with one abstract method are Ordering and CacheLoaderfrom the Guava library. Wouldn't it be nice to be able to declare instances of them using lambdas like this?
Ordering<String> order = (a, b) -> ...;
CacheLoader<String, String> loader = (key) -> ...;
The most common argument against this was that it would add to the difficulty of reading a lambda. Instantiating an abstract class in this way could lead to execution of hidden code: that in the constructor of the abstract class.
Another reason is that it throws out possible optimizations for lambdas. In the future, it may be the case that lambdas are not evaluated into object instances. Letting users declare abstract classes with lambdas would prevent optimizations like this.
The addition of List.sort(Comparator) is fantastic. Previously, the way to sort an ArrayList was this:
Collections.sort(list, comparator);
That code, which was your only option in Java 7, was frustratingly inefficient. It would dump the list into an array, sort the array, then use a ListIterator to insert the array contents into the list in new positions.
The default implementation of List.sort(Comparator) still does this, but concrete implementing classes are free to optimize. For instance, ArrayList.sort invokes Arrays.sort on the ArrayList's internal array. CopyOnWriteArrayList does the same.
Performance isn't the only potential gain from these new methods. They can have more desirable semantics, too. For instance, sorting a Collections.synchronizedList() is an atomic operation using list.sort. You can iterate over all its elements as an atomic operation using list.forEach. Previously this was not possible.
ArratList
    @SuppressWarnings("unchecked")
    public void sort(Comparator<? super E> c) {
        final int expectedModCount = modCount;
        Arrays.sort((E[]) elementData, 0, size, c);
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        modCount++;
    }
    public boolean removeIf(Predicate<? super E> filter) {
        Objects.requireNonNull(filter);
        // figure out which elements are to be removed
        // any exception thrown from the filter predicate at this stage
        // will leave the collection unmodified
        int removeCount = 0;
        final BitSet removeSet = new BitSet(size);
        final int expectedModCount = modCount;
        final int size = this.size;
        for (int i=0; modCount == expectedModCount && i < size; i++) {
            @SuppressWarnings("unchecked")
            final E element = (E) elementData[i];
            if (filter.test(element)) {
                removeSet.set(i);
                removeCount++;
            }
        }
        if (modCount != expectedModCount) { // this shoud be here
            throw new ConcurrentModificationException();
        }

        // shift surviving elements left over the spaces left by removed elements
        final boolean anyToRemove = removeCount > 0;
        if (anyToRemove) {
            final int newSize = size - removeCount;
            for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) {
                i = removeSet.nextClearBit(i);
                elementData[j] = elementData[i];
            }
            for (int k=newSize; k < size; k++) {
                elementData[k] = null// Let gc do its work
            }
            this.size = newSize;
            if (modCount != expectedModCount) {
                throw new ConcurrentModificationException();
            }
            modCount++;
        }

        return anyToRemove;
    }

http://www.trigent.com/blog/jdk-8-6-features-that-actually-matters-most-to-java-developers/
int sum = widgets.stream().filter(w -> w.getColor() == RED)
.mapToInt(w -> w.getWeight()).sum();

3. Compact profiles –

Today to develop java application we use java SE API which has all the packages in it. We may use only limited set of packages from the complete list of packages. JDK 8 brings the future called Compact profiles. A Compact profile is a profile with limited set of packages which can be used for application development. There are three types of profiles. They are Compact profile 1, Compact profile 2 and Compact profile 3. Compact profile 1 has the following set of packages like Core, Security, Serialization, Networking, Ref Objects, Regular expressions, Date and time, Collections, Logging, Concurrency, Reflection, JNDI, JAR, ZIP, Versioning, Internationalization and Scripting. Profile 2 has all the packages in profile 1 plus the following packages like JDBC, RMI and XML JAXP. Profile 3 has all the packages in profile 1 and profile 2 plus the following packages like Security, JMX, Management and instrumentation. Finally Full SE API has all the packages.
Depends on the requirement the application can use any one of the profile which will reduce the JRE memory and this feature will be useful for applications development for small device applications which has memory constraints.
http://howtodoinjava.com/java-8/base64-encoding-and-decoding-example-in-java-8/
String basicEncoded = Base64.getEncoder().encodeToString("subjects?abcd".getBytes("utf-8"));
System.out.println("Using Basic Alphabet: " + basicEncoded);

String urlEncoded = Base64.getUrlEncoder().encodeToString("subjects?abcd".getBytes("utf-8"));
http://colobu.com/2014/10/28/secrets-of-java-8-functional-interface/

函数式接口(Functional Interface)是Java 8对一类特殊类型的接口的称呼。 这类接口只定义了唯一的抽象方法的接口(除了隐含的Object对象的公共方法), 因此最开始也就做SAM类型的接口(Single Abstract Method)。
为什么会单单从接口中定义出此类接口呢? 原因是在Java Lambda的实现中, 开发组不想再为Lambda表达式单独定义一种特殊的Structural函数类型,称之为箭头类型(arrow type), 依然想采用Java既有的类型系统(class, interface, method等), 原因是增加一个结构化的函数类型会增加函数类型的复杂性,破坏既有的Java类型,并对成千上万的Java类库造成严重的影响。 权衡利弊, 因此最终还是利用SAM 接口作为 Lambda表达式的目标类型。
JDK中已有的一些接口本身就是函数式接口,如Runnable。 JDK 8中又增加了java.util.function包, 提供了常用的函数式接口。
函数式接口代表的一种契约, 一种对某个特定函数类型的契约。 在它出现的地方,实际期望一个符合契约要求的函数。 Lambda表达式不能脱离上下文而存在,它必须要有一个明确的目标类型,而这个目标类型就是某个函数式接口。
当然, Java 8发布快一年了, 你对以上的概念也应该有所了解了,这篇文章也不会介绍这些基础的东西, 而是想深入的探讨函数式接口的定义和应用。

JDK 8之前已有的函数式接口

  • java.lang.Runnable
  • java.util.concurrent.Callable
  • java.security.PrivilegedAction
  • java.util.Comparator
  • java.io.FileFilter
  • java.nio.file.PathMatcher
  • java.lang.reflect.InvocationHandler
  • java.beans.PropertyChangeListener
  • java.awt.event.ActionListener
  • javax.swing.event.ChangeListener

新定义的函数式接口

java.util.function中定义了几组类型的函数式接口以及针对基本数据类型的子接口。
  • Predicate -- 传入一个参数,返回一个bool结果, 方法为boolean test(T t)
  • Consumer -- 传入一个参数,无返回值,纯消费。 方法为void accept(T t)
  • Function -- 传入一个参数,返回一个结果,方法为R apply(T t)
  • Supplier -- 无参数传入,返回一个结果,方法为T get()
  • UnaryOperator -- 一元操作符, 继承Function,传入参数的类型和返回类型相同。
  • BinaryOperator -- 二元操作符, 传入的两个参数的类型和返回类型相同, 继承BiFunction
函数式接口中可以额外定义多个抽象方法,但这些抽象方法签名必须和Object的public方法一样
接口最终有确定的类实现, 而类的最终父类是Object。 因此函数式接口可以定义Object的public方法。
如以下的接口依然是函数式接口:

声明异常

函数式接口的抽象方法可以声明 可检查异常(checked exception)。 在调用目标对象的这个方法时必须catch这个异常。这和以前的接口/方法调用一样。
但是,如果在Lambda表达式中抛出异常, 而目标接口中的抽象函数没有声明这个可检查, 则此接口不能作为此lambda表达式的目标类型。
上面的例子中不能编译, 因为lambda表达式要求的目标类型和InterfaceWithException不同。InterfaceWithException的函数没有声明异常。

静态方法

函数式接口中除了那个抽象方法外还可以包含静态方法。
Java 8以前的规范中接口中不允许定义静态方法。 静态方法只能在类中定义。 Java 8中可以定义静态方法。
一个或者多个静态方法不会影响SAM接口成为函数式接口。
下面的例子中FunctionalInterfaceWithStaticMethod包含一个SAM: apply,还有一个静态方法sum。 它依然是函数式接口。
默认方法

Java 8中允许接口实现方法, 而不是简单的声明, 这些方法叫做默认方法,使用特殊的关键字default
因为默认方法不是抽象方法,所以不影响我们判断一个接口是否是函数式接口。

Labels

Review (572) System Design (334) System Design - Review (198) Java (189) Coding (75) Interview-System Design (65) Interview (63) Book Notes (59) Coding - Review (59) to-do (45) Linux (43) Knowledge (39) Interview-Java (35) Knowledge - Review (32) Database (31) Design Patterns (31) Big Data (29) Product Architecture (28) MultiThread (27) Soft Skills (27) Concurrency (26) Cracking Code Interview (26) Miscs (25) Distributed (24) OOD Design (24) Google (23) Career (22) Interview - Review (21) Java - Code (21) Operating System (21) Interview Q&A (20) System Design - Practice (20) Tips (19) Algorithm (17) Company - Facebook (17) Security (17) How to Ace Interview (16) Brain Teaser (14) Linux - Shell (14) Redis (14) Testing (14) Tools (14) Code Quality (13) Search (13) Spark (13) Spring (13) Company - LinkedIn (12) How to (12) Interview-Database (12) Interview-Operating System (12) Solr (12) Architecture Principles (11) Resource (10) Amazon (9) Cache (9) Git (9) Interview - MultiThread (9) Scalability (9) Trouble Shooting (9) Web Dev (9) Architecture Model (8) Better Programmer (8) Cassandra (8) Company - Uber (8) Java67 (8) Math (8) OO Design principles (8) SOLID (8) Design (7) Interview Corner (7) JVM (7) Java Basics (7) Kafka (7) Mac (7) Machine Learning (7) NoSQL (7) C++ (6) Chrome (6) File System (6) Highscalability (6) How to Better (6) Network (6) Restful (6) CareerCup (5) Code Review (5) Hash (5) How to Interview (5) JDK Source Code (5) JavaScript (5) Leetcode (5) Must Known (5) Python (5)

Popular Posts