1.8新特性

lamda

  • Lambda表达式(闭包),Lambda允许把函数作为一个方法的参数(函数作为参数传递方法中),或者把代码看成数据。Lamda表达式用于简化Java中接口式的匿名内部类。被称为函数式接口的概念。函数式接口就是一个具有 一个方法 的普通接口。像这样的接口可以被隐式的转换成Lambda表达式。

  • 格式

(parameters) -> expression
或
(parameters) ->{ statements; }
  • 例子
public class Java8Tester {
   public static void main(String args[]){
      Java8Tester tester = new Java8Tester();
        
      // 类型声明
      MathOperation addition = (int a, int b) -> a + b;
        
      // 不用类型声明
      MathOperation subtraction = (a, b) -> a - b;
        
      // 大括号中的返回语句
      MathOperation multiplication = (int a, int b) -> { return a * b; };
        
      // 没有大括号及返回语句
      MathOperation division = (int a, int b) -> a / b;
        
      System.out.println("10 + 5 = " + tester.operate(10, 5, addition));
      System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction));
      System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication));
      System.out.println("10 / 5 = " + tester.operate(10, 5, division));
        
      // 不用括号
      GreetingService greetService1 = message ->
      System.out.println("Hello " + message);
        
      // 用括号
      GreetingService greetService2 = (message) ->
      System.out.println("Hello " + message);
        
      greetService1.sayMessage("Runoob");
      greetService2.sayMessage("Google");
   }
    
   interface MathOperation {
      int operation(int a, int b);
   }
    
   interface GreetingService {
      void sayMessage(String message);
   }
    
   private int operate(int a, int b, MathOperation mathOperation){
      return mathOperation.operation(a, b);
   }
}
  • 对字符串数组按字符串长度排序
package org.xxxx.demo01;
 
import java.util.Arrays;
import java.util.Comparator;
 
public class Demo01 {
    public static void main(String[] args) {
        // 定义字符串数组
        String[] strArr = { "abc", "cd", "abce", "a" };
 
        // 传统方法
        // 匿名内部类
        Arrays.sort(strArr, new Comparator<String>() {
 
            @Override
            public int compare(String s1, String s2) {
                return Integer.compare(s2.length(), s1.length());
            }
        });
 
        // 输出排序结果
        for (String s : strArr) {
            System.out.println(s);
        }
        System.out.println("---------------------");
 
        // Lambda表达式
        Arrays.sort(strArr, (s1, s2) -> Integer.compare(s2.length(), s1.length()));
 
        // 输出
        for (String s : strArr) {
            System.out.println(s);
        }
    }
}
  • 用Lambda实现多线程
package org.xxxx.demo01;
 
public class Demo01 {
    public static void main(String[] args) {
        // Lambda表达式
        new Thread(() -> System.out.println(1 + "hello world")).start();
 
        System.out.println("----------------");
 
        // 方法体
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                System.out.println(2 + "hello world");
            }
        }).start();
    }
}

函数式接口

  • @FunctionalInterface:该注解是定义一个lambda表达式的基础, 即是否是函数式接口可以标注也可以不标注。
  • 函数式接口分类
    • 系统与定义函数接口(Comparator, Runnable)
    • 用户自定义函数接口(注解必须有,表达式是直接通过参数列表来实现的,只能有一个有效方法)
@FunctionalInterface
public interface MyInterface {
    String info(String tip);
}
  • 公共定义的函数式接口

  • Function<T, R>

    • 有输入参数,有返回值
    • 是对接收一个T类型参数,返回R类型的结果的方法的抽象
    • 通过调用apply方法执行内容
    • 例子:给定一个字符串,返回字符串长度
package org.xxxx.demo01;
 
import java.util.function.Function;
 
public class Demo01 {
    public static void main(String[] args) {
        // 定义字符串
        String str = "helloworld";
        
        // 调用方法
        // 在调用的时候写方法体,方法比较灵活
        int length = testFun(str, (s) -> s.length());
        
        System.out.println(length);
    }
    
    // 方法
    /**
     * 
     * @param str 输入参数
     * @param fun 表达式 String 为输入类型,Integer为输出类型
     * @return 返回字符串长度
     */
    public static int testFun(String str, Function<String, Integer> fun) {
        // 执行
        Integer length = fun.apply(str);
        
        return length;
    }
}
  • 消费型接口:Consumer<T>
    • 有输入参数,没返回值
    • Consumer 使用accept对参数执行行为
    • 例子:输出字符串

package org.xxxx.demo01;
 
import java.util.function.Consumer;
 
public class Demo01 {
    public static void main(String[] args) {
        // 创建字符串
        String str = "hello world";
        
        // 调用
        testCon(str, (s) -> System.out.println(s));
    }
    
    /**
     * 
     * @param str 传入参数
     * @param con
     */
    public static void testCon(String str, Consumer<String> con) {
        // 执行
        con.accept(str);
    }
  • 供给型接口:Supplier<T>
    • 无传入参数,有返回值
    • 该接口对应的方法类型不接受参数,但是提供一个返回值
    • 使用get()方法获得这个返回值
package org.xxxx.demo01;
 
import java.util.function.Supplier;
 
public class Demo01 {
    public static void main(String[] args) {
        // 创建字符串
        String str = "hello world";
        
        // 调用
        String sup = testSup(() -> str);
        
        System.out.println(sup);
    }
    
    /**
     * 
     * @param sup
     * @return
     */
    public static String testSup(Supplier<String> sup) {
        // 执行
        String s = sup.get();
        return s;
    }
  • 断言型接口:Predicate<T>
    • 有传入参数,有返回值Boolean
    • 该接口对应的方法为接收一个参数,返回一个Boolean类型值
    • 多用于判断与过滤,使用test()方法执行这段行为
    • 需求:输入字符串,判断长度是否大于0
package org.xxxx.demo01;
 
import java.util.function.Predicate;
 
public class Demo01 {
    public static void main(String[] args) {
        // 创建字符串
        String str = "hello world";
        
        // 调用
        boolean flag = testPre(str, (s) -> s.length() > 0);
        
        System.out.println(flag);
    }
    
    /**
     * 
     * @param str
     * @param pre
     * @return
     */
    public static boolean testPre(String str, Predicate<String> pre) {
        // 执行
        boolean flag = pre.test(str);
        
        return flag;
    }
}

方法引用

  • 某些lambda表达式里面仅仅是调用了一个已存在的方法,在这种情况下

  • 直接通过方法名称引用方法的形式可读性更高一些,这种形式就是方法引用

  • 方法引用是一种更简洁易懂的lambda 表达式替换

image.png
  • 方法引用中::后只是方法名,不能加();
import java.util.ArrayList;
import java.util.List;
 
public class Demo01 {
    public static void main(String[] args) {
        // 创建集合
        List<String> list = new ArrayList<>();
        
        // 添加元素
        list.add("e");
        list.add("c");
        list.add("a");
        list.add("d");
        list.add("b");
        
        // 排序
        list.sort((s1, s2) -> s1.compareTo(s2));
        
        // 遍历
        list.forEach((s) -> System.out.println(s));
        list.forEach(System.out::println);
    }
}

Stream

  • 是用函数式编程方式在集合类上进行复杂操作的工具,更像一个高级版本的 Iterator

  • 而和迭代器又不同的是,Stream 可以并行化操作

  • 在Java1.8 中, 集合接口提供了两个方法来生成流:stream()串行流和parallelStream()并行流,即Stream的操作可以分为串行stream()和并行parallelStream()。举个例子来说:

List<String> strings = Arrays.asList("who","what","when","why","which");
List<String> filterd = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
  • forEach 循环
       List<String> stringList = Arrays.asList("who","what","when","why","which");

        // 方式一:JDK1.8之前的循环方式
        for(String string:stringList){
            System.out.println(string);
        }

        // 方式二:使用Stream的forEach方法
        stringList.stream().forEach(e -> System.out.println(e));

        // 方式三:方式二的简化形式,因为方法引用也属于函数式接口,因此Lambda表达式可以用方法引用来代替
        stringList.stream().forEach(System.out::println);
  • filter 过滤
    • filter方法用于通过设置条件来过滤出满足条件的元素。举个例子来说,下面就是用于输出字符串列表中的空字符串的个数:
        List<String> stringList = Arrays.asList("","welcome","","to","visit","my","","website");
        long count = stringList.stream().filter(e -> e.isEmpty()).count();
        System.out.println(count);
  • map 映射
    • 是一种函数,用于映射每个元素执行某些操作得到对应的结果。举个例子来说,下面就是使用map来输出元素对应的平方数:
        List<Integer> integerList = Arrays.asList(2,3,4,5,6);
        List<Integer> integers = integerList.stream().map(i->i*i).collect(Collectors.toList());
        integerList.stream().forEach(System.out::println);
  • flatMap 映射
    • flatMap映射和map映射类似,不过它的每个元素转换得到的是Stream对象,会把子Stream中的元素压缩到父集合中,说白了就是将几个小的list合并成一个大的list。
        List<String> fruitList = Arrays.asList("banana","orange","watermelon");
        List<String> vegetableList = Arrays.asList("kale","leek","carrot");
        List<String> transportList = Arrays.asList("car","bike","train");
        
        //将多个元素合成一个复合类型集合,元素类型List<String>
        List<List<String>> lists = Stream.of(fruitList,vegetableList,transportList).collect(Collectors.toList());

        //将多个元素合成一个单一类型集合,元素类型String
        List<String> flatMap = Stream.of(fruitList,vegetableList,transportList)
                .flatMap(list ->list.stream())
                .collect(Collectors.toList());
        System.out.println(flatMap);
  • sorted 排序
    • sorted方法用于对流进行排序。举个例子来说,下面的代码就是用于对字符串按照给定的规则进行排序并输出:
        List<String> stringList = Arrays.asList("c","a","f","d","b","e");
        stringList.stream().sorted((s1,s2) -> s1.compareTo(s2)).forEach(System.out::println);
  • distinct
    • 缺点就是不能设置去重的条件
        List<String> stringList = Arrays.asList("do","what","you","want","to","do","and","do","it");
        stringList.stream().distinct().forEach(System.out::println);
  • of 生成Stream对象
    • of方法用于生成Stream对象,注意它是Stream对象的方法。举个例子来说:
        Stream<Object> objectStream= Stream.of("do","what","you","want","to","do","and","do","it");
        objectStream.forEach(System.out::println);
  • count 计算总数
    • count方法用于计算流中元素的总数。举个例子来说:
        Stream<Object> objectStream = Stream.of("do","what","you","want","to","do","and","do","it");
        long count = objectStream.count();
        System.out.println(count);
  • min和max 最小/最大
    • collect方法的使用较为复杂,这里仅仅介绍一些常用的方法即可。collect方法可以将Stream转为Collection对象或者是Object类型的数组等,举个例子来说:
        List<String> stringList= Arrays.asList("do","what","you","want","to","do","and","do","it");
        //Stream转Collection
        stringList.stream().collect(Collectors.toList());
        //Stream转Object[]数组
        Object[] objects = stringList.stream().toArray();
  • collect
    • collect方法的使用较为复杂,这里仅仅介绍一些常用的方法即可。collect方法可以将Stream转为Collection对象或者是Object类型的数组等,举个例子来说:
        List<String> stringList= Arrays.asList("do","what","you","want","to","do","and","do","it");
        //Stream转Collection
        stringList.stream().collect(Collectors.toList());
        //Stream转Object[]数组
        Object[] objects = stringList.stream().toArray();
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容