Java高效编程(1)-Lambda

Java高效编程(1)-Lambda,第1张

Java高效编程(1)-Lambda

Java高效编程之Lambda
    • 从硬编码到lambda的演变
    • Lambda编程好处及优点
      • Lambda编程思想
      • Lambda编程优点
    • 常见的函数式接口及基本使用
      • Supplier接口
        • 抽象方法 :T get()
      • Consumer接口
        • 抽象方法 : void accept(T t)
        • 默认方法 : Consumer andThen​(Consumer after)
      • Predicate接口
        • 抽象方法 :boolean test(T t)
        • 默认方法 :and​(Predicate other)
        • 默认方法 :or​(Predicate other)
        • 默认方法 :negate​()
      • Function接口
        • 抽象方法 : R apply(T t)
        • 默认方法 : andThen​(Function after)
    • 经典练习题

从硬编码到lambda的演变
  • 我们从模拟的购物车小需求开始演变
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Sku {
    
    private Integer skuId;
    
    private String skuName;
    
    private Double skuPrice;
    
    private Integer totalName;
    
    private Double totalPrice;
    
    private Enum skuCategory;
}

public enum SkuCategoryEnum {
    CLOTHING(10,"服装类"),
    ELECTRONICS(20,"数码类"),
    SPORTS(30,"运动类"),
    BOOKS(40,"图书类");

    
    private Integer code;

    
    private String name;

    SkuCategoryEnum(Integer code, String name) {
        this.code = code;
        this.name = name;
    }
}
  • 定义初始服务类
@SuppressWarnings("all")
public class CartService {

    private static List cartSkuList = new ArrayList() {
        {

            add(new Sku(654032, "无人机",
                    4999.00, 1, 4999.00, SkuCategoryEnum.ELECTRONICS));

            add(new Sku(642934, "VR一体机",
                    2299.00, 1,
                    2299.00, SkuCategoryEnum.ELECTRONICS));

            add(new Sku(645321, "纯色衬衫",
                    409.00, 3,
                    1227.00, SkuCategoryEnum.CLOTHING));

            add(new Sku(654327, "牛仔裤",
                    528.00, 1,
                    528.00, SkuCategoryEnum.CLOTHING));

            add(new Sku(675489, "跑步机",
                    2699.00, 1,
                    2699.00, SkuCategoryEnum.SPORTS));

            add(new Sku(644564, "Java编程思想",
                    79.80, 1,
                    79.80, SkuCategoryEnum.BOOKS));

            add(new Sku(678678, "Java核心技术",
                    149.00, 1,
                    149.00, SkuCategoryEnum.BOOKS));

        }
    };
} 
  • Version1.0.0: 找出购物车中所有电子类产品
    public static List filterElectronicsSkus(List cartSkuList) {
        List resultList = new ArrayList<>();
        for (Sku sku : cartSkuList) {
            if (SkuCategoryEnum.ELECTRONICS.equals(sku.getSkuCategory())) {
                resultList.add(sku);
            }
        }
        return resultList;
    }


public class version1Test {

    @Test
    public void testFilterElectronicsSkus(){
        List cartSkuList = CartService.getCartSkuList();
        List skus = CartService.filterElectronicsSkus(cartSkuList);
        System.out.println(JSON.toJSONString(skus,true));
    }

}
  • Version2.0.0 : 根据传入商品类型参数,找出购物车中同种商品类型的商品列表
    public static List filterSkusByCategory(List cartSkuList,
                                                 SkuCategoryEnum categoryEnum) {
        List resultList = new ArrayList<>();
        for (Sku sku : cartSkuList) {
            if (categoryEnum.equals(sku.getSkuCategory())) {
                resultList.add(sku);
            }
        }
        return resultList;
    }

public class version2Test {

    @Test
    public void testFilterSkusById(){
        List cartSkuList = CartService.getCartSkuList();
        List skus = CartService.filterSkusByCategory(cartSkuList, SkuCategoryEnum.BOOKS);
        System.out.println(JSON.toJSONString(skus,true));
    }
}
  • Version3.0.0 : 支持通过商品类型或总价来过滤商品
    public static List filterSkus(List cartSkuList,
                                       SkuCategoryEnum categoryEnum, Double totalPrice, Boolean categoryOrPrice) {
        List resultList = new ArrayList<>();
        for (Sku sku : cartSkuList) {
            if (
                    (categoryOrPrice
                            && categoryEnum.equals(sku.getSkuCategory()))
                    ||
                    (!categoryOrPrice
                            && sku.getTotalPrice() > totalPrice)
            ) resultList.add(sku);
        }
        return resultList;
    }

public class version3Test {

    @Test
    public void testFilterSkusById(){
        List cartSkuList = CartService.getCartSkuList();
        List skus = CartService.filterSkus(cartSkuList, SkuCategoryEnum.BOOKS,2000.00,false);
        System.out.println(JSON.toJSONString(skus,true));
    }
}
  • 不知道大家看完这三个版本的迭代 , 有没有发现我们的代码已经存在硬编码了 , 如果现在要根据 SKu的多个参数进行过滤 , 显然前面的三个方法都不能完成该功能 , 那么有没有一种方法 能动态根据不同的条件来进行Sku的过滤呢?显然是可以的
Lambda编程好处及优点 Lambda编程思想
  1. Java8引入函数式编程风格(函数式编程思想)
  2. Lambda就是Java引入函数式编程的一次革命性的尝试
  3. 可以理解为一种匿名函数的替代
  4. Lambda编程的规则 : 有且仅有一个抽象方法的接口
 
  • Version4.0.0 : 根据不同的sku判断标准,对sku列表进行过滤
@FunctionalInterface //使用该注解来定义接口,编译器将会强制检查该接口是否确实有且仅有一个抽象方法,否则将会报错
public interface SkuPredicate {

    
    boolean test(Sku sku);

}


    public static List filterSkus(List cartSkuList,SkuPredicate skuPredicate){
        List resultList = new ArrayList<>();
        for (Sku sku : cartSkuList) {
            if (skuPredicate.test(sku)) resultList.add(sku);
        }
        return resultList;
    }

public class version4Test {

    @Test
    public void testFilterSkusById(){
        List cartSkuList = CartService.getCartSkuList();
        //匿名内部类的写法
        List skus = CartService.filterSkus(cartSkuList, new SkuPredicate() {
            
            @Override
            public boolean test(Sku sku) {
                return sku.getSkuPrice() > 1000;
            }
        });
        //lambda的写法
        List skus1 = CartService.filterSkus(cartSkuList, sku -> sku.getSkuPrice() > 1000);
        System.out.println(JSON.toJSONString(skus,true));
    }

}
  • 大家有没有发现Lambda的写法其实就是从匿名内部类简化而来的呢
  • Lambda语法的省略规则
	//1.小括号内参数的类型可以省略;
    //2.如果小括号内有且仅有一个参,则小括号可以省略;
    //3.如果大括号内有且仅有一个语句,则无论是否有返回值,都可以省略大括号、return关键字及语句分号。
Lambda编程优点
  • 延迟执行 , 用一个案例具体体现
public class Demo01Logger {
    private static void log(int level, String msg) {
        if (level == 1) {
            System.out.println(msg);
        }
    }

    public static void main(String[] args) {
        String msgA = "Hello";
        String msgB = "World";
        String msgC = "Java";
        log(1, msgA + msgB + msgC);
    }
}

//使用Lambda必然需要一个函数式接口
@FunctionalInterface
interface MessageBuilder {
    String buildMessage();
}


public class Demo02Logger {
    private static void log(int level, MessageBuilder builder) {
    if (level == 1) {
        System.out.println(builder.buildMessage());
    }
}
    public static void main(String[] args) {
        String msgA = "Hello";
        String msgB = "World";
        String msgC = "Java";
        log(1, () ‐> msgA + msgB + msgC );
    }
}
常见的函数式接口及基本使用
  • JDK提供了大量常用的函数式接口以丰富Lambda的典型使用场景,它们主要在 java.util.function 包中被提供,大家可以自行查看JDK的API文档
Supplier接口
  • 接口仅包含一个无参的方法 : T get() , 用来获取一个泛型参数指定类型的对象数据
抽象方法 :T get()
public class Demo08Supplier {
    private static String getString(Supplier function) {
        return function.get();
    }

    public static void main(String[] args) {
        String msgA = "Hello";
        String msgB = "Supplier";
        System.out.println(getString(() -> msgA + msgB));
    }
}
Consumer接口
  • 正好与Supplier接口相反 , 它不是生产一个数据 , 而是消费一个数据 , 其数据类型由泛型决定
抽象方法 : void accept(T t)
class Demo09Consumer {
    private static void consumeString(Consumer function) {
        function.accept("Hello");
    }

    public static void main(String[] args) {
        consumeString(s -> System.out.println(s));
    }
}
默认方法 : Consumer andThen​(Consumer after)
class Demo10ConsumerAndThen {
    private static void consumeString(Consumer one, Consumer two) {
        one.andThen(two).accept("Hello");
    }

    public static void main(String[] args) {
        consumeString(s ->System.out.println(s.toUpperCase()), s->System.out.println(s.toLowerCase()));
    }
}
Predicate接口
  • 有时候我们需要对某种类型的数据进行判断 , 从而得到一个boolean值结果。这时可以使用 java.util.function.Predicate 接口
抽象方法 :boolean test(T t)
class Demo15PredicateTest {
    private static void method(Predicate predicate) {
        boolean veryLong = predicate.test("HelloWorld");
        System.out.println("字符串很长吗:" + veryLong);
    }

    public static void main(String[] args) {
        method(s -> s.length() > 5);
    }
}
默认方法 :and​(Predicate other)
class Demo16PredicateAnd {
    private static void method(Predicate one, Predicate two) {
        boolean isValid = one.and(two).test("Helloworld");
        System.out.println("字符串符合要求吗:" + isValid);
    }

    public static void main(String[] args) {
        method(s -> s.contains("H"), s->s.contains("W"));
    }
}
默认方法 :or​(Predicate other)
boolean isValid = one.or(two).test("Helloworld");
默认方法 :negate​()
class Demo17PredicateNegate {
    private static void method(Predicate predicate) {
        boolean veryLong = predicate.negate().test("HelloWorld");
        System.out.println("字符串很长吗:" + veryLong);
    }

    public static void main(String[] args) {
        method(s -> s.length() < 5);
    }
}
Function接口
  • java.util.function.Function 接口用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件, 后者称为后置条件,Function的前置条件泛型和后置条件泛型可以相同
抽象方法 : R apply(T t)
class Demo11FunctionApply {
    private static void method(Function function) {
        int num = function.apply("10");
        System.out.println(num + 20);
    }

    public static void main(String[] args) {
        method(s -> Integer.parseInt(s));
    }
}
默认方法 : andThen​(Function after)
class Demo12FunctionAndThen {
    private static void method(Function one, Function two) {
        int num = one.andThen(two).apply("10");
        System.out.println(num + 20);
    }

    public static void main(String[] args) {
        method(str -> Integer.parseInt(str) + 10, i -> i *= 10);
    }
}
经典练习题
 题目一:
      使用 Supplier 接口作为方法参数类型,通过Lambda表达式求出int数组中的最大值。提示:接口的泛型请使用 java.lang.Integer类
 题目二:
        下面的字符串数组当中存有多条信息,
        请按照格式"姓名:XX。性别:XX。"的格式将信息打印出来,
        要求将打印姓名的动作作为第一个Consumer接口的Lambda实例,将打印性别的动作作为第二个Consumer接口的Lambda实例,        
        将两个Consumer 接口按照顺序"拼接"到一起
        String[] array = { "迪丽热巴,女", "杨洋,男", "杨颖,女" };
 题目三:
       数组当中有多条"姓名+性别"的信息如,请通过 Predicate 接口的拼装将符合要求的字符串筛选到集合 ArrayList 中,需要同时满足两个条件:
       1. 必须为女生; 2. 姓名为4个字
       String[] array = { "迪丽热巴,女", "杨洋,男", "杨颖,女" };
 题目四:
       请使用 Function 进行函数模型的拼接,按照顺序需要执行的多个函数 *** 作为
       String str = "赵丽颖,20";
       		1. 将字符串截取数字年龄部分,得到字符串;
       		2. 将上一步的字符串转换成为int类型的数字;
            3. 将上一步的int数字累加100,得到结果int数字

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/4968182.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-11-13
下一篇 2022-11-13

发表评论

登录后才能评论

评论列表(0条)

保存