Java 8 In Action 代码示例

说明

内容来自《Java 8 In Action》


例一

实体苹果属性:颜色、重量、产地。

需求:过滤出所需的苹果。

import java.util.function.Predicate;

public class Apple {

    private String color;
    private double weight;
    private String country;

    public Apple(String color) {
        this.color = color;
    }

    public Apple(String color, double weight) {
        this.color = color;
        this.weight = weight;
    }

    public Apple(String color, double weight, String country) {
        this.color = color;
        this.weight = weight;
        this.country = country;
    }

    public Predicate<Apple> redApple() {
        return (apple -> "red".equalsIgnoreCase(apple.getColor()));
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public double getWeight() {
        return weight;
    }

    public void setWeight(double weight) {
        this.weight = weight;
    }

    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }

    @Override
    public String toString() {
        return "Apple{" +
                "color='" + color + '\'' +
                ", weight=" + weight +
                ", country='" + country + '\'' +
                '}';
    }
}


import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public class AppleFilter {

    private List<Apple> inventory = Arrays.asList(
            new Apple("green", 150, "Japan"),
            new Apple("red", 160, "Japan"),
            new Apple("green", 180, "China"),
            new Apple("red", 160, "China")
    );

    public static void main(String[] args) {
        AppleFilter filter = new AppleFilter();
        List<Apple> greenApple = filter.filterColor();
        System.out.println(greenApple);
        List<Apple> gtApple = filter.filterWeight();
        System.out.println(gtApple);

        List<Apple> gtGreenApple = filter.filter(filter.inventory, apple -> "green".equals(apple.getColor()) && apple.getWeight() > 150);
        System.out.println(gtGreenApple);

        filter.inventory.sort((apple1, apple2) -> (int) (apple1.getWeight() - apple2.getWeight()));
        System.out.println(filter.inventory);
        filter.inventory.sort(Comparator.comparingDouble(Apple::getWeight).thenComparing(Apple::getCountry).reversed());
        System.out.println(filter.inventory);
        filter.inventory.sort((apple1, apple2) -> Double.compare(apple1.getWeight(), apple2.getWeight()));

        Apple apple = new Apple("Red", 100);
        Predicate<Apple> redApple = apple.redApple();
        Predicate<Apple> notRedApple = redApple.negate();
        Predicate<Apple> redAppleHeavyAppleOrGreen = redApple.and((a) -> apple.getWeight() > 100)
                .or((a) -> "green".equalsIgnoreCase(a.getColor()));
    }

    public List<Apple> filterColor() {
        return inventory.stream()
                .filter(apple -> "green".equals(apple.getColor()))
                .collect(Collectors.toList());
    }

    public List<Apple> filterWeight() {
        return inventory.stream()
                .filter(apple -> apple.getWeight() > 150)
                .collect(Collectors.toList());
    }

    public <T> List<T> filter(List<T> list, Predicate<T> predicate) {
        return list.stream().filter(predicate).collect(Collectors.toList());
    }
}


例二

我们在使用流时,通常形式Stream<T>,但如果是基本数字类型就涉及到装箱和拆箱,如Stream<Integer>。为了避免在流中频繁装箱拆箱,Java提供了基本数字类型流,如IntStream

Stream<Integer>IntStream是可以相互转换的。

public class Dish {

    private final String name;
    private final boolean vegetarian;
    private final int calories;
    private final Type type;

    public Dish(String name, boolean vegetarian, int calories, Type type) {
        this.name = name;
        this.vegetarian = vegetarian;
        this.calories = calories;
        this.type = type;
    }

    public String getName() {
        return name;
    }

    public String getNamet(String name) {
        return name;
    }

    public boolean isVegetarian() {
        return vegetarian;
    }

    public int getCalories() {
        return calories;
    }

    public Type getType() {
        return type;
    }

    public enum Type {
        MEAT, FISH, OTHER    }

    @Override
    public String toString() {
        return "Dish{" +
                "name='" + name + '\'' +
                ", vegetarian=" + vegetarian +
                ", calories=" + calories +
                ", type=" + type +
                '}';
    }
}


import java.util.Arrays;
import java.util.List;
import java.util.OptionalInt;

public class BoxedMain {

    public static void main(String[] args) {
        List<Dish> menu = Arrays.asList(
                new Dish("pork", false, 800, Dish.Type.MEAT),
                new Dish("beef", false, 700, Dish.Type.MEAT),
                new Dish("chicken", false, 400, Dish.Type.MEAT),
                new Dish("french fries", true, 530, Dish.Type.OTHER),
                new Dish("rice", true, 350, Dish.Type.OTHER),
                new Dish("season fruit", true, 120, Dish.Type.OTHER),
                new Dish("pizza", true, 550, Dish.Type.OTHER),
                new Dish("prawns", false, 300, Dish.Type.FISH),
                new Dish("salmon", false, 450, Dish.Type.FISH));

        sum(menu);
        box(menu);
        max(menu);
    }

    private static void sum(List<Dish> menu) {
        int _sum = menu.stream()
                .mapToInt(Dish::getCalories)
                .sum();
        System.out.println(_sum);
    }

    private static void box(List<Dish> menu) {
        menu.stream()
                .mapToInt(Dish::getCalories)
                .boxed()
                .reduce(Integer::sum)
                .ifPresent(System.out::println);
    }

    public static void max(List<Dish> menu) {
        OptionalInt optionalInt = menu.stream()
                .mapToInt(Dish::getCalories)
                .max();
        optionalInt.ifPresent(System.out::println);
    }
}


例三

获取文件行内容

灵活的需求:某些情况需要文件第一行内容;某些情况需要文件前二行内容或前三行内容。

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.function.Function;

public class ProcessFile {

    public static void main(String[] args) throws Exception {
        processFile();

        processFile(bufferedReader -> bufferedReader.readLine());
        processFile(bufferedReader -> bufferedReader.readLine() + bufferedReader.readLine());
    }

    /**
     * 常规方式
     * @return
     * @throws Exception
     */
    public static String processFile() throws Exception {
        try (BufferedReader reader = new BufferedReader(new FileReader("App.java"))) {
            return reader.readLine();
        }
    }

    /**
     * 传递功能函数方式
     * @param func
     * @return
     * @throws Exception
     */
    public static String processFile(BufferedReaderProcessor<BufferedReader, String> func) throws Exception {
        try (BufferedReader reader = new BufferedReader(new FileReader("App.java"))) {
            return func.apply(reader);
        }
    }
}


BufferedReaderProcessor与内置的Function是一样的,只是具有可读性。

@FunctionalInterface
public interface BufferedReaderProcessor<T, R> {

    R apply(T t) throws Exception;
}


例四

避免空指针问题

import java.util.Optional;

public class Person {

    private Car car;

    private Optional<Car> optionalCar;

    public Car getCar() {
        return car;
    }

    public Optional<Car> getOptionalCar() {
        return optionalCar;
    }
}


import java.util.Optional;

public class Car {

    private Insurance insurance;

    private Optional<Insurance> optionalInsurance;

    public Insurance getInsurance() {
        return insurance;
    }

    public Optional<Insurance> getOptionalInsurance() {
        return optionalInsurance;
    }
}


public class Insurance {

    private String name;

    public String getName() {
        return name;
    }
}


import java.util.Optional;

public class PersonMain {

    private final static String UN_KNOWN = "UNKNOWN";

    private String s;

    public static void main(String[] args) {
        // NullPointerException
        // new PersonMain().getCarInsuranceName(new Person());
        String name = new PersonMain().optionalGetCarInsuranceName(Optional.empty());
        System.out.println(name);
        String s = new PersonMain().commonUsage(Optional.empty());
        System.out.println(s);
        System.out.println(new PersonMain().testString());
    }

    public String getCarInsuranceName(Person person) {
        return person.getCar().getInsurance().getName();
    }

    public String optionalGetCarInsuranceName(Optional<Person> optionalPerson) {
        return optionalPerson.flatMap(Person::getOptionalCar)
                .flatMap(Car::getOptionalInsurance)
                .map(Insurance::getName)
                .orElse(UN_KNOWN);
    }

    public String commonUsage(Optional<Person> optionalPerson) {
        return optionalPerson.map(person -> person.getCar())
                .map(car -> car.getInsurance())
                .map(insurance -> insurance.getName())
                .orElse(UN_KNOWN);
    }

    public String testString() {
        Optional<String> optional = Optional.ofNullable(s);
        return optional.orElse(UN_KNOWN);
    }
}


getCarInsuranceName容易引发NullPointerExceptionoptionalGetCarInsuranceName将实体以Optional引用,可以避免NullPointerException,但需要实体类提供相应的Optional<T>commonUsage是常规使用模式,使用optional的内置方法,既可以避免NullPointerException,也无需对实体类进行修改。


例五

分别使用lambda和函数引用对字符串进行排序。

import java.util.Arrays;
import java.util.List;

public class CompareString {

    public static void main(String[] args) {
        List<String> list = Arrays.asList("a", "b", "A", "B");
        list.sort((s1, s2) -> s1.compareToIgnoreCase(s2));
        System.out.println(list);

        list.sort(String::compareToIgnoreCase);
        System.out.println(list);
    }
}


  

展开阅读全文