lambda表达式(2)

方法引用:
方法引用是结合lambda表达式的一种语法特性,方法引用通过方法的名字来指向一个方法。方法引用可以使语言的构造更紧凑简洁,减少冗余代码。
方法引用可划分为:

  • 静态方法引用
  • 实例方法引用
  • 构造方法引用
    具体使用实例如下:

public class UserInfo {
    /**
     * 1、静态方法引用
     * 2、实例方法引用
     * 3、构造方法引用
     */
    public static void main(String[] args) {
        List<User> users = new ArrayList<>();
        users.add(new User("lili", 18, "女"));
        users.add(new User("tom", 17, "男"));
        users.add(new User("lilei", 28, "男"));
        users.add(new User("大张飞", 38, "男"));
        users.add(new User("李逵", 19, "男"));
        users.add(new User("貂蝉", 18, "女"));

        // 匿名内部类实现的排序
        Collections.sort(users, new Comparator<User>() {
            @Override
            public int compare(User o1, User o2) {
                return o1.getAge() - o2.getAge();
            }
        });

        // lambda方式的实现排序
        Collections.sort(users, (o1, o2) -> o1.getAge() - o2.getAge());

        // 静态方法引用
        // 类型名称 方法名称 -> 类型名称:方法名称
        Collections.sort(users, User::compareByAge);

        //实例方法引用
        // 创建对应的对象 -> 对象的运用:方法名称
        Collections.sort(users, new User()::compareByNameHashCode);

        // 构造方法引用 需要绑定一个构造方法
        IUser user = User::new;
        User initUser = user.initUser("花和尚", 50, "男");

        System.out.println(users);
    }
}

class User {
    private String name;
    private int age;
    private String gender;

    // 定义一个静态方法
    public static int compareByAge(User o, User o2) {
        return o.age - o2.age;
    }

    // 定义一个普通的方法
    public int compareByNameHashCode(User o1, User o2) {
        return o1.getName().hashCode() - o2.getName().hashCode();
    }

    public User() {
    }

    public User(String name, int age, String gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                '}';
    }
}

interface IUser {
    User initUser(String name, int age, String gender);
}

Stream的使用
Stream:Stream是java 8 中提供的一种新特性,新的抽象称为流Stream,可以让你以一种声明的方式处理数据。通过下面的代码可以 更好的体验Stream的好处。

public class App2 {

    public static void main(String[] args) {
        // 添加测试数据
        List<Integer> nums = new ArrayList<>();
        nums.add(1000);
        nums.add(500);
        nums.add(1500);
        nums.add(600);
        nums.add(550);
        nums.add(700);
        nums.add(650);
        nums.add(800);
        nums.add(30000);
        // 使用普通的for循环来完成(底层是使用Iterator实现的迭代器)
        for (Integer num : nums) {
            if (num > 600) {
                System.out.println(num);
            }
        }

        // 使用普通的迭代是实现的
        Iterator<Integer> it = nums.iterator();
        while (it.hasNext()) {
            Integer num = it.next();
            if (num > 600) {
                System.out.println(num);
            }
        }

        // 使用lambda表达式实现的循环过滤
        List<Integer> collect = nums.stream().filter(o -> o > 600).collect(Collectors.toList());
        System.out.println(collect);
    }
}

通过以上的循环过滤操作使用普通的for 和迭代器与实际操作的代码很少代码冗余较多,而使用stream和lambda表达式的结合可以较少代码冗余(仅仅只是编写与实际业务逻辑的代码)
Stream的Api详解
可以根据对数据操作影响分为

  • intermeidadte中间|记录操作(有状态或无状态)中间操作的结果是一个stream对象,所以可以是一个或者多个连续的中间操作,中间操作只是做记录操作,不做具体的执行,直到数据结束操作时,才能获取数据的最终执行。
    根据状态可分为:
    1、有状态:数据处理过程中,受前置中间操作结果影响(distinct/sorted/limit/skip)
    2、无状态:数据处理过程中,不受前置中间操作结果的影响(map/filter/parallet/sequential/unodered
  • terminal终结|结束操作(非短路或短路)一个终结操作只能包含一个stream对象,一旦发生就会真正的操作数据,得到最终结果,并且结果还是不可逆的过程。
    根据执行的过程可分为
    1、非短路操作:当前的stream对象必须要处理完当前的所有数据才能够返回最终的处理结果。forEach/forEachOrdered/toArray/reduce/collect/max/min/count/iterator
    2、短路操作:当前的stream对象不需要处理所有的数据,只要满足一定的条件就可以返回最终的结果。anyMatch/allMatch/noneMatch/findFirst/findAny使用短路操作的场景就是将一个无线大的stream对象,返回成一个有限大的stream对象。

stream处理数据流程为:获取数据源 -> 数据转换(可以一次或多次) ->最终结果

如何获取stream对象

  • 从集合或数组中获取 Collection.stream 如:nums.stream 获取一个并行的stream Collection.paralletStream 从数组中获取 Arrays.stream(T t)
  • 从缓冲区中获取BufferReadBufferReader.lines() -> stream
  • 静态工厂 java.util.stream.IntStream.range() java.nio.file.Files.walk()
  • 自定义构建 java.util.Spliterator
public class App3 {
    public static void main(String[] args) {
        // 如何获取stream对象

        // 1 通过批量数据
        Stream stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9);

        // 2 通过数组
        Integer[] arr = new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9};
        Stream arrStream = Arrays.stream(arr);

        // 通过列表
        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        Stream<Integer> listStream = list.stream();

        // 集合
        Set<Integer> set = new HashSet<>();
        set.add(1);
        set.add(2);
        Stream<Integer> setStream = set.stream();

        // map
        Map<Integer, Integer> map = new HashMap<>();
        map.put(1, 1);
        map.put(2, 2);
        Stream<Map.Entry<Integer, Integer>> entryStream = map.entrySet().stream();

        // 基本的数据类型
        IntStream.of(new int[]{1, 2}).forEach(System.out::println);
        IntStream.range(1, 10).forEach(System.out::println);
    }
}

通过stream对象转换成指定的数据类型:


        Stream stream = Stream.of("str", "ing", "hello", "world");

        //转换成数组
        Object[] arr = stream.toArray(Integer[]::new);

        // 转成字符串
        String str = stream.collect(Collectors.joining()).toString();

        // 转成列表
        List<String> strs = (List<String>) stream.collect(Collectors.toList());

        // 转成集合
        Set<String> set = (Set<String>) stream.collect(Collectors.toSet());

        // 转成map
        Map<String, String> map = (Map<String, String>) stream.collect(Collectors.toMap(x -> x, y -> y));

stream线程安全问题

 public static void main(String[] args) {

        List<Integer> list = new ArrayList<>();
        for (int i =0; i < 100000; i++) {
            list.add(i);
        }

        List<Integer> list2 = new ArrayList<>();
        // 串行的stream
        list.stream().forEach(x -> list2.add(x));
        System.out.println(list.size());
        System.out.println(list2.size());

        // 并行的stream
        List<Integer> list3 = new ArrayList<>();
        list.parallelStream().forEach(x -> list3.add(x));
        System.out.println(list.size());
        System.out.println(list3.size());
    }
    100000
    100000
    100000
    39836

通过上面的代码,使用parallelStream时会出现线程之间相互竞争的问题,线程是不安全的。
stream的性能分析可以参考下面这篇文章。

https://www.cnblogs.com/carpenterlee/p/6675568.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值