Behavior parameterized

1. Let’s start with a small example

  • We’re going to sort an inventory and compare apples by weight
// inventory collections.sort (inventory, new Comparator<Apple>() { public int compare(Apple a1,Apple a2){ return a1.getWeight().compareTo(a2.getWeight()); }});Copy the code

When you do it with Stream, you pass code The idea of parameterizing operations

inventory.sort(comparing(Apple::getWeight));
Copy the code

The same example as 1

  • You want to filter all hidden files in a directory
File[] hiddenFiles = new File(".").listFiles(new FileFilter() { public boolean accept(File file) { return file.isHidden(); }})Copy the code

We already have the isHidden method, so let’s pass this method into the function

File[] hiddenFiles = new File(".").listFiles(File::isHidden);   
Copy the code
  • When you write File::isHidden in Java 8, you create a method reference that can also be passed.

Let’s do an example

Apple’s class

public static class Apple { private int weight = 0; private String color = ""; public Apple(int weight, String color){ this.weight = weight; this.color = color; } public Integer getWeight() { return weight; } public void setWeight(Integer weight) { this.weight = weight; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } public String toString() { return "Apple{" + "color='" + color + '\'' + ", weight=" + weight + '}'; }}Copy the code
  • Find apples that weigh more than 150
  • Find apples whose color is green

The following is not recommended

List<Apple> inventory = Arrays.asList(new Apple(80,"green"), new Apple(155, "green"), new Apple(120, "red")); Public static List<Apple> filterGreenApples(List<Apple> inventory){// color List<Apple> res = new ArrayList<>(); for(Apple apple : inventory){ if("green".equals(apple.getColor())){ res.add(apple); } } return res; } public static List<Apple> filterHeavyApples(List<Apple> inventory){// Weight List<Apple> result = new ArrayList<>(); for (Apple apple: inventory){ if (apple.getWeight() > 150) { result.add(apple); } } return result; }Copy the code

Recommend writing

public interface Predicate<T>{
        boolean test(T t);
    }

    public static boolean isGreenApple(Apple apple) {
        return "green".equals(apple.getColor());
    }
    
    public static List<Apple> filterApples(List<Apple> inventory, Predicate<Apple> p){
        List<Apple> result = new ArrayList<>();
        for(Apple apple : inventory){
            if(p.test(apple)){
                result.add(apple);
            }
        }
        return result;
    }


public static void main(String []args){
        List<Apple> inventory = Arrays.asList(new Apple(80,"green"),
                new Apple(155, "green"),
                new Apple(120, "red"));
        List<Apple> greenA1 = filterApples(inventory,FilteringApples::isGreenApple);
        List<Apple> greenA2 = filterApples(inventory,(Apple a) -> "green".equals(a.getColor()));

        System.out.println("------" + greenA1 + "------");
        System.out.println("···" + greenA2 + "···");
    }

Copy the code
  • The results

  • The Predicate interface defines an abstract method called test, which accepts generic T objects
  • And returns a Boolean. This is exactly the same as the one you created earlier and can be used directly now

For example, you can pass the parameter == like this

Predicate<String> nonEmptyStringPredicate = (String s) -> ! s.isEmpty(); List<String> nonEmpty = filter(listOfStrings, nonEmptyStringPredicate);Copy the code
  • ※ The methods of the generic Predicate interface are Boolean, so you can use behavior parameterization

The Stream small example

  • Filter the higher transactions from a list and then group them by currency
for (Transaction transaction : transactions) { if(transaction.getPrice() > 1000){ Currency currency = transaction.getCurrency(); List<Transaction> transactionsForCurrency = transactionsByCurrencies.get(currency); if (transactionsForCurrency == null) { transactionsForCurrency = new ArrayList<>(); transactionsByCurrencies.put(currency, transactionsForCurrency); } transactionsForCurrency.add(transaction); }}Copy the code

The above code converts to

Map<Currency, List<Transaction>> transactionsByCurrencies =
                transactions.stream()
                .filter((Transaction t) -> t.getPrice() > 1000)
                .collect(groupingBy(Transaction::getCurrency));
Copy the code

A powerful Stream

  • There is such a need
  • Choose dishes under 400 calories and rank them by calorie
List<String> lowCaloricDishesName = menus.stream ().filter(d -> D. GetCalorie () < 400) //400 below .sorted(comparing(Dish:: getName)) // sort.map (Dish::getName) // Collect (toList()); / / saveCopy the code
  • Link several basic operations together to express a complex pipeline of data processing
  • Add the sorted, map, and collect operations to the filter

  • Sequence of elements – Just like a collection, a stream provides an interface to access an ordered set of values of a particular element type.
  • Source – A stream uses a source that provides data, such as a collection, array, or input/output resource.
  • Data processing Operations – The data processing capabilities of streams support database-like operations, as well as operations commonly used in functional programming languages.
  • Such as filter, map, reduce, find, match, and sort.
  • Pipeline – Many stream operations themselves return a stream so that multiple operations can be linked together to form a large pipeline.
  • Internal iteration – Instead of explicitly iterating over a set of iterators, the iteration of a stream is done behind the scenes.

  • Filter — Accepts a Lambda to exclude certain elements from the stream.
  • Map — Takes a Lambda, converts elements into other forms or extracts information.
  • Limit – Truncates the stream so that it does not exceed a given number of elements.
  • Collect — converts the stream to another form.

Lambda small features

public interface Consumer<T>{ void accept(T t); } public static <T> void forEach(List<T> list,Consumer<T> c){ for (T i : list){ c.accept(i); }} public static void main(String[] args) {forEach(arrays.aslist (1,2,3,4,5), (Integer I) -> system.out.println (I)); }Copy the code
  • The Consumer defines an abstract method called Accept that accepts objects of the generic type T
  • No return (void). If you need to access an object of type T and perform operations on it, you can use this interface
  • Create a forEach method that takes a list of Integers and performs an action on each element in it

Screening and sectioning

Predicate filter

Create a vegetarian menu by sifting out all the vegetarian dishes

List<Dish> vegetarianMenu = menu.stream()
                .filter(Dish::isVegetarian)
                .collect(toList());
Copy the code

Filter the various elements

List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4); Number.stream ().filter(I -> I % 2 == 0).distinct().foreach (system.out ::println);Copy the code

truncated

List<Dish> dishes = menu.stream()
                .filter(d -> d.getCalories() > 300)
                .limit(3)
                .collect(toList());
Copy the code

Skip the element

Returns a stream with the first N elements thrown away

List<Dish> dishes = menu.stream()
                .filter(d -> d.getCalories() > 300)
                .skip(2)
                .collect(toList());
Copy the code

mapping

  • Map, which takes a function as an argument. This function is applied to each element and maps it to a new element
List<String> dishNames = menu.stream()
                .map(Dish::getName)
                .collect(toList());
Copy the code

Because the getName method returns a String, the type of the Stream output by the map method is Stream.

Case 2

Given a list of words, you want to return another list showing how many letters are in each word

List<String> words = Arrays.asList("Java 8", "Lambdas", "In", "Action");
        List<Integer> wordLen = words.stream()
                .map(String::length)
                .collect(toList());
Copy the code

Find element to find a vegetarian dish

Optional<Dish> dish =
          menu.stream()
             .filter(Dish::isVegetarian)
             .findAny();
Copy the code
  • The Optional class (java.util.Optional) is a container class that represents the presence or absence of a value
  • IsPresent () will return true if Optional contains the value, and false otherwise.
  • IfPresent (Consumer Block) executes a given block of code while the value is present.
  • T get() returns the value if it exists, otherwise a NoSuchElement exception is thrown.
  • T orElse(T other) returns the value if it exists, and a default value otherwise.
Stream ().filter(Dish::isVegetarian).findany ().ifpresent (d -> system.out.println (d.gatname ()));Copy the code