开发中装x必备(编程新风格、新姿势、新走向)—— Java 8的新特性

一、lambda表达式

/**
 * 1、例子:(int 01,int 02) -> return 01 - 01
 * 2、格式:
 *      ->:lambda表达式操作符
 *      左边:形参列表(就是接口中的抽象方法的形参列表)
 *      右边:方法体(重写抽象方法的方法体)
 * 3、表达式本质:作为函数式接口(接口中只有一个抽象方法,@FunctionInterface标记)的实例(对象)
 * */

在java中的主角的就是对象,几乎所有东西都是对象,包括方法(通过反射可以拿到Method对象)。而lambda表达式也不例外,表达式基于接口的抽象方法的,这个是前提。我们来看lambda表达式六种格式。

1、无参数无返回值

public interface InterfaceDemo1 {
    void print();
}
    /**
     * 语法格式1:无参数,无返回值
     */
    public static void test1(){
        //原来的写法
        InterfaceDemo1 interfaceDemo1 = new InterfaceDemo1() {
            @Override
            public void print() {
                System.out.println("hello 我是原来的写法");
            }
        };
        interfaceDemo1.print();

        //Lambda表达式写法
        InterfaceDemo1 demo1 = () -> System.out.println("hello");
        demo1.print();
    }

2、需要参数,无返回值

public interface InterfaceDemo2 {
    void print(String str);
}
    /**
     * 语法格式2:需要参数,无返回值
     */
    public static void test2(){
        //原来的写法
        InterfaceDemo2 interfaceDemo2 = new InterfaceDemo2() {
            @Override
            public void print(String str) {
                System.out.println("hello 我是原来的写法");
            }
        };
        interfaceDemo2.print("hello");

        //Lambda表达式写法
        InterfaceDemo2 demo2 = (String str) -> System.out.println(str);
        demo2.print("hello");
    }

3、数据类型可以省略:由编译器推断得出

 /**
     * 语法格式3:数据类型可以省略:由编译器推断得出
     */
    public static void test3(){
        InterfaceDemo2 demo2 = (str) -> System.out.println(str);
        demo2.print("hello");
    }

4、只需要一个参数的时候,括号可以省略

    /**
     * 语法格式4:只需要一个参数的时候,括号可以省略
     */
    public static void test4(){
        InterfaceDemo2 demo2 = str -> System.out.println(str);
        demo2.print("hello");
    }

5、需要两个及以上参数的时候,多条语句执行,并且有返回值

public interface InterfaceDemo3 {
    int print(int a,int b);
}
 /**
     * 语法格式5:需要两个及以上参数的时候,多条语句执行,并且有返回值
     */
    public static void test5(){
        InterfaceDemo3 interfaceDemo3 = new InterfaceDemo3() {
            @Override
            public int print(int a, int b) {
                System.out.println("hello 我是原来的写法");
                return a + b;
            }
        };
        System.out.println(interfaceDemo3.print(1,2));

        InterfaceDemo3 demo3 = (a,b) -> {
            System.out.println("hello");
            return a + b;
        };
        System.out.println(demo3.print(1,2));
    }

6、当lambda体只有y一条语句的时候,return与大括号若有,都可以省略

    /**
     * 语法格式6:当lambda体只有y一条语句的时候,return与大括号若有,都可以省略
     */
    public static void test6(){
        InterfaceDemo3 demo3 = (a,b) -> a + b;
        System.out.println(demo3.print(1,2));
    }

大家可以把上面的例子运行一遍,应该就有感觉了。创建的表达式实际上也是一个函数接口的实例。

二、函数式接口

接口中只有一个抽象方法,@FunctionInterface标记。

    public static void test1(){
        //原来写法
        happyTime(500.0, new Consumer<Double>() {
            @Override
            public void accept(Double aDouble) {
                System.out.println("价格 => " + aDouble);
            }
        });

        //lambda
        happyTime(500.0,(money) -> {System.out.println("价格 => " + money);});
    }

    /**
     * Consumer
     */
    public static void happyTime(double money, Consumer<Double> con){
        con.accept(money);
    }

这个表达式实例可以当作参数来传递,然后调用实际的方法。

    /**
     * Predicate
     */
    public static void test2(){
        List<String> strings = new ArrayList<>();
        strings.add("aaaaa");
        strings.add("bbb");
        strings.add("cccc");
        filterString(strings,(String str) -> {return str.length() > 3;});
    }
    /**
     * Predicate
     */
    public static void filterString(List<String> list, Predicate<String> predicate){
        List<String> strings = new ArrayList<>();
        for(String str:list){
            if(predicate.test(str)){
                strings.add(str);
            }
        }
        System.out.println(strings);
    }

实际上这四个方法,我们只需要按照参数和返回值传入相应的东西就可以了!!!

三、方法引用与构造器引用

1、方法引用

/**
 * 方法引用的使用
 * 1、使用情景:当要传递给lambda体的操作,已经有实现的方法了,可以使用方法引用。
 * 2、方法引用:本质上就是lambda表达式。也是函数接口的实例
 * 3、格式:类(对象)::方法名
 * 4、具体分为如下几种情况:
 *      对象::实例方法
 *      类::静态方法
 *      类::实例方法
 * 5、要求:接口中的抽象方法的形参列表和返回值类型与方法引用的形参列表和返回值相同。
 **/

方法引用,引用的是已经存在的方法,帮我们来执行。

public class User {

    private String name;
    private int age;
    private char sex;

    //constructor、getter、setter...
}
    /**
     * 情景1:对象::实例方法
     * Consumer     void accept(T t)
     * PrintStream  void println(T t)
     */
    public static void test1(){
        //lambda
        Consumer<String> con = str -> System.out.println(str);
        con.accept("hhhhhh");

        //方法引用
        PrintStream ps = System.out;
        Consumer<String> con2 = ps::println;
        con2.accept("hhhhh");
    }

    /**
     * Supplier     T get()
     * User     String getName()
     */
    public static void test2(){
        User user = new User("aaa",12,'m');
        Supplier<String> sp = user::getName;
        System.out.println(sp.get());
    }
   /**
     * 情景2:类::静态方法
     * Comparator   int compare(T t1,T t2)
     * Integer      int compare(int t1,int t2)
     */
    public static void test3(){
        Comparator<Integer> comparator1 = (t1,t2) -> Integer.compare(t1,t2);
        System.out.println(comparator1.compare(1,2));

        Comparator<Integer> comparator2 = Integer::compare;
        System.out.println(comparator2.compare(1,2));
    }


    /**
     * Function     R apply(T t)
     * Math         long round(Double d)
     */
    public static void test4(){
        Function<Double,Long> function1 = (d) -> Math.round(d);
        System.out.println(function1.apply(2.54));

        Function<Double,Long> function2 = Math::round;
        System.out.println(function2.apply(2.1));
    }
    /**
     * 情景3:类::实例方法
     * Comparator       int compare(T t1,T t2)
     * String           int t1.compareTo(t2)
     */
    public static void test5(){
        Comparator<String> comparator1 = (s1,s2) -> s1.compareTo(s2);
        System.out.println(comparator1.compare("hhhh","bbbbb"));

        Comparator<String> comparator2 = String::compareTo;
        System.out.println(comparator2.compare("hhhh","bbbbb"));
    }

    /**
     * BiPredicate        boolean test(T t1,T t2)
     * String           boolean t1.equals(t2)
     */
    public static void test6(){
        BiPredicate<String,String> predicate = (t1, t2) ->  t1.equals(t2);
        System.out.println(predicate.test("aaa","aaa"));

        BiPredicate<String,String> predicate2 = String::equals;
        System.out.println(predicate2.test("aaa","aaa"));

    }

    /**
     * Function     R apply(T t)
     * User       String getName()
     */
    public static void test7(){
        Function<User,String> function1 = (t1) -> t1.getName();
        System.out.println(function1.apply(new User("zhangsan",12,'c')));

        Function<User,String> function2 = User::getName;
        System.out.println(function2.apply(new User("lisi",12,'c')));
    }

要重点注意第三种场景,这种场景之所以成立,是引入传入的参数(或者第一个参数)实际上是一个对象,然后用对象调用一个方法。

2、构造器引用

/**
 * 一、构造器引用
 *      与方法引用类似,函数式接口的抽象方法的形参列表和构造器的形参列表一致
 *      抽象方法的返回值类型即为构造器所属的类的类型
 *
 * 二、数组引用
 *      可以把数组看作是一个特殊的类,则写法与构造器引用一致
 *
 **/
public class ConstructDemo {

    /**
     * 构造器引用
     * Supplier     T get()
     * User 空参构造器
     */
    public static void test1(){
        Supplier<User> supplier = () -> new User("张三",12,'a');
        System.out.println(supplier.get());

        Supplier<User> supplier1 = User::new;
        System.out.println(supplier1.get());
    }

    /**
     * Function     R apply(T t)
     */
    public static void test2(){
        Function<String,User> function1 = (name) -> new User(name);
        System.out.println(function1.apply("zhangsan "));

        Function<String,User> function2 = User::new;
        System.out.println(function2.apply("lisi "));
    }

    /**
     * BiFunction       apply(T t,U u)
     */
    public static void test3(){
        BiFunction<String,Integer,User> function1 = (name,age) -> new User(name,age);
        System.out.println(function1.apply("zhangsan",12));

        BiFunction<String,Integer,User> function2 = User::new;
        System.out.println(function2.apply("lisi",12));
    }

    /**
     * 情景2:数组引用
     */
    public static void test4(){
        Function<Integer,String[]> function1 = (len) -> new String[len];
        String[] arr1 = function1.apply(10);

        Function<Integer,String[]> function2 = String[]::new;
        String[] arr2 = function2.apply(10);
    }

    public static void main(String[] args) {
        test3();
    }
}

用了new关键字!!

四、stream的API

/**
 * 1、stream:关注对数据的运算,与cpu打交道
 *    集合:关注的是数据存储,与内存打交道
 *
 * 2、stream:
 *      自己不会存储数据
 *      不会改变源对象,相反会返回一个持有结果的新Stream
 *      操作时延迟的,这意味着他们会等到需要看结果的时候才执行。
 * 3、执行流程:
 *      Stream实例化
 *      一些列中间操作(过滤、映射。。。。)
 *      中止操作(不能再被使用)
 **/
public class UserData {

    public static List<User> getListUser(){
        List<User> list = new ArrayList<>();
        list.add(new User("小明",22,'m'));
        list.add(new User("小刚",32,'m'));
        list.add(new User("小张",24,'f'));
        list.add(new User("小张",24,'f'));
        list.add(new User("小子",200,'m'));
        return list;
    }
}

1、创建Stream

/**
     * 创建一个Stream方式一:集合
     */
    public static void test1(){
        //顺序流
        List<User> listUser = UserData.getListUser();
        Stream<User> stream = listUser.stream();

        //并行流
        Stream<User> userStream = listUser.parallelStream();

    }

    /**
     * 创建一个Stream方式二:数组
     */
    public static void test2(){
        int[] arr = new int[]{1,2,3,4,5};
        IntStream stream = Arrays.stream(arr);

    }

    /**
     * 创建一个Stream方式三:Stream的of
     */
    public static void test3(){
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
    }

2、筛选与分片

package stream;

import method_reference.User;
import method_reference.UserData;

import java.util.List;
import java.util.stream.Stream;

/**
 * 中间操作:筛选与切片
 **/
public class StreamA {

    private static List<User> listUser = UserData.getListUser();
    private static Stream<User> stream = listUser.stream();

    /**
     * 筛选:filter方法api
     */
    public static void test1(){
        stream.filter(u -> u.getAge() > 30).forEach(System.out::println);
    }

    /**
     * 截断流limit方法api
     */
    public static void test2(){
        stream.limit(3).forEach(System.out::println);
    }

    /**
     * 跳过n数据skip(n)方法api
     */
    public static void test3(){
        stream.skip(2).forEach(System.out::println);
    }

    /**
     * 去重distinct方法,通过流所生成的元素的hashCode()和equals()去重复元素
     */
    public static void test4(){
        stream.distinct().forEach(System.out::println);
    }


    public static void main(String[] args) {
        test4();
    }
}

3、映射

package stream;

import method_reference.User;
import method_reference.UserData;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

/**
 * 映射
 *
 **/
public class StreamB {

    private static List<User> listUser = UserData.getListUser();
    private static Stream<User> stream = listUser.stream();

    /**
     * map:接收一个函数作为参数,将元素转换成其他形式或提取信息,该函数会应用到每一个元素上面,将其映射成一个新的元素
     */
    public static void test1(){
        stream.map(user -> {
            user.setName(user.getName() + "hh");
            return user;
        }).forEach(System.out::println);
    }

    /**
     * flatMap:接收一个函数作为参数,将流中每一个值转换成另一个流,然后把所有流连接起来
     */
    public static void test2(){
        List<String> strings = Arrays.asList("aa","bb","cc");
        //正常写法
        Stream<Stream<Character>> streamStream = strings.stream().map(StreamB::fromStringToStream);
        streamStream.forEach(stream -> {
            stream.forEach(System.out::print);
        });
        System.out.println();
        //flatmap
        strings.stream().flatMap(StreamB::fromStringToStream).forEach(System.out::print);
    }

    public static Stream<Character> fromStringToStream(String str){
        List<Character> list = new ArrayList<>();
        for(char ch:str.toCharArray()){
            list.add(ch);
        }
        return list.stream();
    }

    public static void main(String[] args) {
        test2();
    }

}

4、排序

package stream;

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

/**
 * 排序
 **/
public class StreamC {

    /**
     * 自然排序
     */
    public static void test1(){
        List<Integer> list = Arrays.asList(12,7,9,10,23,57,3);
        list.stream().sorted().forEach(System.out::println);
    }

    /**
     * 比较器排序
     */
    public static void test2(){
        List<Integer> list = Arrays.asList(12,7,9,10,23,57,3);
        list.stream().sorted((a,b) -> b - a).forEach(System.out::println);
    }

    public static void main(String[] args) {
        test2();
    }
}

五、中止操作

package stream;

import method_reference.User;
import method_reference.UserData;

import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 中止操作
 **/
public class EndDemo {

    private static List<User> listUser = UserData.getListUser();

    /**
     * 匹配与查找
     */
    public static void test1(){
        //allMatch:检查是否匹配所有元素都大于30
        boolean b = listUser.stream().allMatch(e -> e.getAge() > 30);

        //anyMatch:检查至少匹配一个元素大于30
        boolean b1 = listUser.stream().anyMatch(e -> e.getAge() > 30);

        //noneMatch:检查是否没有匹配元素
        boolean b2 = listUser.stream().noneMatch(e -> e.getName().startsWith("张"));

        //findFirst:查找第一个元素
        Optional<User> first = listUser.stream().findFirst();

        //findAny:返回当前流中的任意元素
        Optional<User> any = listUser.stream().findAny();

        //count:数量
        long count = listUser.stream().filter(e -> e.getAge() > 30).count();

        //找最大:max
        Optional<Integer> max = listUser.stream().map(e -> e.getAge()).max(Integer::compare);

        //找最小:min
        Optional<User> min = listUser.stream().min((a, c) -> a.getAge() - c.getAge());

        //forEash:内部迭代
        listUser.stream().forEach(System.out::println);
        //forEash:外部迭代
        listUser.forEach(System.out::println);
    }

    /**
     * 归约
     */
    public static void test2(){
        //reduce(T identity,BinaryOperator):可以将流中的值反复结合起来,得到一个值,返回。
        //identity:初始值
        Integer reduce = listUser.stream().map(e -> e.getAge()).reduce(0, Integer::sum);
        System.out.println(reduce);

        //reduce(BinaryOperator)

    }
     /**
     * 收集:collect
     */
    public static void test3(){
        //将流转换成其他形式,接收一个Collector接口的实现,用于给Stream中元素做汇总方法
        List<User> userList = listUser.stream().filter(e -> e.getAge() > 30).collect(Collectors.toList());
        Set<User> collect = listUser.stream().filter(e -> e.getAge() > 30).collect(Collectors.toSet());

    }

    public static void main(String[] args) {
        test3();
    }

}

 六、Optional

如果我们传入null值,那么就会创建一个非空对象

package optional;

import java.util.Optional;

/**
 * 为了在程序中避免空指针异常而创建的!!!
 * Optional.of(T t):创建一个Optional实例,t必须非空
 * Optional.empty:创建一个空的Optional实例
 * Optional.ofNullable:t可以为空
 *
 **/
public class OptionalTest {

    /**
     * Optional.of
     */
    public static void test1(){
        Girl girl = new Girl();
        Optional<Girl> optionalGirl = Optional.of(girl);
    }

    /**
     * Optional.ofNullable
     */
    public static void test2(){
        Optional<Girl> optionalGirl = Optional.ofNullable(null);
    }

    /**
     * 平时写:空指针
     */
    public static void test3(){
        Boy boy = new Boy();
        System.out.println(boy.getGirl().getName());
    }

    public static void test4(){
        Boy boy = new Boy();

        //保证boy不是null
        Optional<Boy> optionalBoy = Optional.ofNullable(boy);
        //如果boy是空,那么boy就变成我们new的对象
        optionalBoy.orElse(new Boy(new Girl("hhhh")));

        Girl girl = boy.getGirl();
        Optional<Girl> optionalGirl = Optional.ofNullable(girl);
        optionalGirl.orElse(new Girl("aaaaa"));

        System.out.println(girl.getName());
    }



    public static class Boy{
        private Girl girl;

        public Boy(){}

        public Boy(Girl girl){
            this.girl = girl;
        }

        public Girl getGirl() {
            return girl;
        }

        public void setGirl(Girl girl) {
            this.girl = girl;
        }
    }

    public static class Girl{
        private String name;

        public Girl(){}

        public Girl(String name){
            this.name = name;
        }

        public String getName() {
            return name;
        }

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

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章