java8 实践_Java8实战 之 Lambda表达式实践

先看一段代码:

public String processFile() throws IOException{

try(BufferedReader reader = new BufferedReader(new FileReader("data.txt"))){

return reader.readLine();

}

}

这段代码只读取data.txt文件中的第一行数据,但它是有局限的,如果有需求想返回头两行,甚至是返回高频词该怎么办呢?

按照上节所学的,把processFile的行为参数化:把行为传递给processFile,以便它利用BufferedReader执行不同的行为。

定义函数式接口

@FunctionalInterface

public interface BufferedReaderProcessor{

String process(BufferedReader reader) throws IOException;

}

只有一个函数 :)

现在就可以把这个接口作为参数传给processFile()了:

public String processFile(BufferedReaderProcessor p) throws IOException{

......

}

2. 执行一个行为

public String processFile(BufferedReaderProcessor p) throws IOException{

try(BufferedReader reader = new BufferedReader(new FileReader("data.txt"))){

return p.processor(reader); // 行为动作交给BufferedReaderProcessor.process()函数处理,你不用care它的实际动作,只需要把对象reader给它即可。

}

}

但这种写法与Lambda一点鸟关系都没有,它反而是我们这种大叔级别的程序员所欢喜的。

3. 传递Lambda

String oneLine = processFile((BufferedReader br) -> br.readLine());

其中红色字体:(BufferedReader br) -> br.readLine(),其功能与等价于:try(BufferedReader reader = new BufferedReader(new FileReader("data.txt"))){

return reader.readLine();

}

也可以读取两行内容:

String twoLines = processFile((BufferedReader br) -> br.readLine() + br.readLine());

再举几个例子,加深一下印象:Predicate

@FunctionalInterface

public interface Predicate{

boolean test(T t);

}

public List filter(List srcList, Predicate p){

List results = new ArrayList<>();  // 定义一个结果集合

for(T item: srcList){  // 遍历原集合

if(p.test(item)){   // 执行函数式接口逻辑,满足者添加到结果集合中

results.add(item);

}

}

return results;  // 返回结果集合

}

Lambda使用示例:

Predicate nonEmptyStringPredicate = (String s) -> !s.isEmpty();  // 可理解为,定义了函数式接口Predicate实例nonEmptyStringPredicate

List nonEmpty = filter(listOfStrings, nonEmptyStringPredicate); // 让这个函数式接口实例去做过滤动作

备注:这里(String s) -> !s.isEmpty()其实就是接口Predicate中test方法的一个实现。

2.  Consumer

@FunctionalInterface

public interface Consumer{

void accept(T t);

}

public static void forEach(List srcList, Consumer c){

for(T t : srcList){ // 遍历srcList,通过Consumer.accept()处理符合条件的数据

c.accept(i);

}

}

Lambda使用示例:

forEach(Arrays.asList(1,2,3,4,5,6), (Integer i) -> System.out.println(i));

备注:这里(Integer i) -> System.out.println(i) 其实就是函数式接口Consumer中accept方法的一个具体实现。

3. Function

@FunctionalInterface

public interface Function{

R apply(T t);

}

public static List map(List srcList, Function f){

List result = new ArrayList<>();

for(T s : srcList){

result.add(f.apply(s));

}

return result;

}

Lambda使用示例:

List intList = map(Arrays.asList("lambdas", "in", "action", "demo"),  (String s) -> s.length());

备注:这里(String s) -> s.length() 其实就是函数式接口Function中map方法的一个具体实现。

经过上面的例子,大家应该了解了Lambda表达式如何使用。不管了,反正我已了解 :)

有人说Java是真正面向对象的语言,但它从它的支持的类型来看,Java还是有遗留尾巴的。

引用类型:诸如Byte、Integer、Double、List等

原始类型:诸如byte、int、double、char等

如果把原始类型转换为对应的引用类型(int -> Integer、byte -> Byte、double -> Double),这叫装箱; 反之,叫拆箱。 当然Java有自动装拆箱机制,让Java人员使用起来更方便一些:

List list = new ArrayList<>();

for (int i = 30; i < 400; i++){

list.add(i);  // 这里i本来是原始类型,但自动装箱后添加到list中。但这要付出性能代价的

}

另外上面的例子中,有3个接口Predicate、Consumer、Function,它们均是泛型函数式接口,这里就涉及到一个暗约束:泛型只能绑定到引用类型,不能绑定到原始类型,这是由泛型内部的实现方式造成的。

Java8为是否自动装箱做了一个专门的版本,请看下面的例子:

@FunctionalInterface

public interface IntPredicate{ // 定义函数式接口

boolean test(int t);

}

// 声明一个IntPredicate类型的实例

IntPredicate evenNums =(int i) -> i % 2 == 0;   // 标红部分即为接口IntPredicate的一个实现

evenNums.test(1000); // 这里无需装箱,也没有发生自动装箱动作

Predicate oddNums  =(Integer i) -> i % 2 == 1;  // 上面的函数式接口

oddNums.test(1000); // 这里会自动装箱

一般来说,针对专门的输入参数的函数式接口的名称都要加上对应的原始类型前缀,比如DoublePredicate、IntConsumer、LongBinaryOperator等。Function接口还有针对输出参数类型的变种:ToIntFunction、IntToDoubleFunction等。

反正好多接口,也没有必要记忆和背诵。

标签:Predicate,String,List,接口,BufferedReader,new,Java8,表达式,Lambda

来源: https://blog.51cto.com/qingkechina/2553167

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值