java8+stream+remove_JAVA8你只需要知道这些(2)

前言

上篇文章我们讲了JAVA8中接口和匿名内部类的一些新特性。这篇文章我们将继续深入的研究JAVA8。

1.Function包

在JAVA8中引入了java.util.function包,这个包里面全是接口,其中有四个接口值得我们注意:

1.Function 功能型接口

public interface Function {

R apply(T t);

}

需要注意的是@FunctionalInterface注解说明这是一个函数式接口,函数式接口中只能包含一个抽象方法,如果多于一个会报错,但是可以有默认方法,静态方法。

从Function接口来看,该接口接收一个参数返回一个参数。

2.Consumer 消费型接口

public interface Consumer {

void accept(T t);

}

Consumer接口接收一个参数,但是没有返回值。

3.Supplier 供给型接口

public interface Supplier {

/**

* Gets a result.

*

* a result

*/

T get();

}

Supplier接口不接收参数,但是有返回值。

4.Predicate 断言型接口

public interface Predicate {

boolean test(T t);

}

Predicate接口接收一个参数,返回一个boolean类型。

知道这4个接口有什么用呢?这4个接口是我们接下来要讲的stream的基础,在stream中,有大量的方法用到了以上的接口。

2.Stream

Stream API真正的把函数式编程风格引入了JAVA。Stream主要用来对数据进行处理,尤其是对集合数据的处理。Stream Api对应的是java.util.stream包,在这个包下面有一个Stream接口,是我们主要研究的对象。

我们先来看看创建Stream的几种方式:

//1.使用Stream接口中的方法

Stream stream = Stream.of("1", "2", "3");

// 2. 使用Arrays.stream方法

String [] strs = new String[] {"1", "2", "3"};

stream = Arrays.stream(strs );

// 3. 使用Collection接口中的stream方法

List list = Arrays.asList(strs );

stream = list.stream();

但是不论是用哪一种方式创建Stream,其内部都是通过以下代码实现:

public static Stream stream(Spliterator spliterator, boolean parallel) {

Objects.requireNonNull(spliterator);

return new ReferencePipeline.Head<>(spliterator,

StreamOpFlag.fromCharacteristics(spliterator),

parallel);

}

知道如何创建Stream以后,我们就要开始使用它:

String [] strs = new String[] {"java", "android", "ios"};

Arrays.stream(strs).filter((x)-> x.length()>3).forEach(System.out::println);

以上代码很简单,首先创建了一个String数组,然后通过Arrays.stream创建一个Stream,再通过filter方法把长度大于3的字符串过滤出来,最后通过System.out::println输出到控制台。

到这里就不得不提到Stream的操作了:

1af96c309eb6ea621c0dc0475e966995.png

Stream操作分为中间操作和终端操作,中间操作就比如上面的filter方法,终端操作就比如上面的forEach方法。Stream的中间操作会惰性执行,只有执行到终端操作了才会立即去处理。这样的好处就是可以提升性能。

中间操作又分为有状态和无状态两种,有状态的操作必须等到所有元素处理完之后才知道最终结果,比如排序操作,在读取完所有元素前,就不能确定排序的结果。而无状态的操作中,元素的处理不受前面元素的影响,比如filter操作就是无状态的,当前元素的操作不会受到前面元素的影响。

终端操作也分为非短路操作和短路操作,短路操作即不用处理全部元素就可以返回结果,比如anyMatch方法,找到第一个满足条件的元素就返回。非短路操作就是要处理完全部元素才可以返回结果。

中间操作包括:map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered

终端操作包括:forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator

3.方法引用

可能细心的朋友已经发现了,在以上我们的代码中使用了System.out::println而不是System.out.prinlnt。这种语法我们以前似乎没有见过?对,它叫方法引用,这也是JAVA8中的新特性,我们来看看它的语法:

1.引用静态方法: 类名称::静态方法名

2.引用普通方法:  实例化对象名::普通方法名

3.引用特定类方法:  特定类::普通方法名

4.引用构造方法:  类名称::new

你可能会说,不就是把以前的方法调用由.变成了::么?有什么可稀奇的?方法引用跟以前方法调用最大的区别在于,你可以用另外一个方法来引用该方法,说通俗一点就是可以给方法取一个别名,例如:

范例:把Int型转换为String

interface Action

{

R convert(P p);

}

public static void main(String[]args){

Action a=String::valueOf;

String str=a.convert(123);

System.out.println(str);

}

在上面代码中,我们首先定义了函数式接口,关于函数式接口的定义我们上篇文章已经说过了,要是忘记了可以再回上篇文章看看。Action接口中有convert方法,接收一个参数,返回一个值。这跟我们String类中的valueOf方法一样,valueOf方法也是传入一个参数,返回一个值:

public static String valueOf(int i)

所以我们就可以用convert来引用valueOf方法,可以看见我们的convert方法是没有被实现的,他的功能完全取决于valueOf方法。并且因为valueOf方法是静态的,所以我们按照方法引用的语法,可以用类名::静态方法名直接引用。

范例:把小写字符串转换为大写

interface Action{

R convert();

}

public static void main(String[]args){

Action a="abc"::toUpperCase;

String str=a.convert();

System.out.println(str);

}

在上面代码中,我们通过方法引用把小写的abc,转换为大写的ABC,在使用方法引用的时候,我们用了"abc"这就是String类的一个实例,而toUpperCase的定义是一个普通方法:

public String toUpperCase()

范例:比较两个字符的大小

interface Action

{

int convert(P p1,P p2);

}

public static void main(String[]args){

Action a=String::compareTo;

System.out.println(a.convert("a","b"));

在以上代码中我们引用了compareTo方法来比较两个字符串的大小。但是我们来看该方法的定义:

public int compareTo(String anotherString)

它竟然不是静态方法,我们却用类名直接引用,这是为什么?正常情况下,类名::方法名,这个方法肯定是静态方法。但是为什么这里普通方法也可以呢?这就要分析一下compareTo这个方法了,这个方法是两个字符串进行对比,正常情况下的写法应该是"a".compareTo("b"),对应的方法引用应该是"a"::compareTo。

如果是这样,我们定义函数式接口的时候,就应该定义成以下这样:

interface Action

{

int convert(P p1);

}

public static void main(String[]args){

Action a="a"::compareTo;

System.out.println(a.convert("b"));

}

如果接口定义成这样,就可以使用"a"::compareTo这种形式的方法引用。到这里聪明的你应该明白,为什么在上面可以通过类名引用普通方法了吧?我们想想在String类里面除了compareTo还有其他方法没?很多是不是?equals,endsWith都属于,所以他们都可以通过把方法参数定义为两个,然后用类名::方法名。

class ShopCar{

private String name;

private double price;

private int amount;

public ShopCar(String name,double price,int amount){

this.name=name;

this.price=price;

this.amount=amount;

}

public int getAmount() {

return amount;

}

public String getName() {

return name;

}

public double getPrice() {

return price;

}

public String toString() {

// TODO Auto-generated method stub

return "商品名:"+this.name+" 价格:"+this.price+" 数量:"+this.amount;

}

}

interface Action{

C create(String name,double price,int amount);

}

public static void main(String[]args){

Action a=ShopCar :: new;

ShopCar car=a.create("苹果",5,2);

System.out.println(car);

}

以上代码演示了如何通过类名称::new 来构造一个ShopCar对象。

结语:

今天的文章主要讲了JAVA8新引入的两个包和方法引用,其中Function包是基础,大家一定要多多理解。Stream包是函数式编程风格的主要提现,下一篇文章我们会着重介绍Stream接口中的方法。

如果你觉得本篇文章帮助到了你,希望大爷能够打赏。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
mport java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import javax.sound.sampled.AudioFileFormat; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.Control; import javax.sound.sampled.DataLine; import javax.sound.sampled.FloatControl; import javax.sound.sampled.Line; import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.Mixer; import javax.sound.sampled.SourceDataLine; import javax.sound.sampled.UnsupportedAudioFileException; import javazoom.spi.PropertiesContainer; import org.tritonus.share.sampled.TAudioFormat; import org.tritonus.share.sampled.file.TAudioFileFormat; import static com.hadeslee.yoyoplayer.player.BasicPlayerEvent.*; /** * BasicPlayer is a threaded simple player class based on JavaSound API. * It has been successfully tested under J2SE 1.3.x, 1.4.x and 1.5.x. */ @SuppressWarnings("unchecked") public class BasicPlayer implements BasicController, Runnable { public static int EXTERNAL_BUFFER_SIZE = 4000 * 4; public static int SKIP_INACCURACY_SIZE = 512; protected Thread m_thread = null; protected Object m_dataSource; protected AudioInputStream m_encodedaudioInputStream; protected int encodedLength = -1; protected AudioInputStream m_audioInputStream; protected AudioFileFormat m_audioFileFormat; protected SourceDataLine m_line; protected FloatControl m_gainControl; protected FloatControl m_panControl; protected String m_mixerName = null; private int m_lineCurrentBufferSize = -1; private int lineBufferSize = -1; private long threadSleep = -1; private static Logger log = Logger.getLogger(BasicPlayer.class.getName()); /** * These variables are used to distinguish stopped, paused, playing states. * We need them to control Thread. */ // public static final int UNKNOWN = -1; // public static final int PLAYING = 0; // public static final int PAUSED = 1; // public static final int STOPPED = 2; // public static final int OPENED = 3; // public static final int SEEKING = 4; private int m_status = UNKNOWN; private Map empty_map = new HashMap(); private BasicPlayerEventLauncher laucher;//浜嬩欢鍒嗘淳鍣? /** * Constructs a Basic Player. */ public BasicPlayer() { m_dataSource = null; laucher = new BasicPlayerEventLauncher(); laucher.start(); reset(); } protected void reset() { m_status = UNKNOWN; if (m_audioInputStream != null) { synchronized (m_audioInputStream) { closeStream(); } } m_audioInputStream = null; m_audioFileFormat = null; m_encodedaudioInputStream = null; encodedLength = -1; if (m_line != null) { m_line.stop(); m_line.close(); m_line = null; } m_gainControl = null; m_panControl = null; } /** * Add listener to be notified. * @param bpl */ public void addBasicPlayerListener(BasicPlayerListener bpl) { laucher.addBasicPlayerListener(bpl); } /** * Return registered listeners. * @return */ public Collection getListeners() { return laucher.getBasicPlayerListeners(); } /** * Remove registered listener. * @param bpl */ public void removeBasicPlayerListener(BasicPlayerListener bpl) { laucher.removeBasicPlayerListener(bpl); } /** * Set SourceDataLine buffer size. It affects audio latency. * (the delay between line.write(data) and real sound). * Minimum value should be over 10000 bytes. * @param size -1 means maximum buffer size available. */ public void setLineBufferSize(int size) { lineBufferSize = size; } /** * Return SourceDataLine buffer size. * @return -1 maximum buffer size. */ public int getLineBufferSize() { return lineBufferSize; } /** * Return SourceDataLine current buffer size. * @return */ public int getLineCurrentBufferSize() { return m_lineCurrentBufferSize; } /** * Set thread sleep time. * Default is -1 (no sleep time). * @param time in milliseconds. */ public void setSleepTime(long time) { threadSleep = time; } /** * Return thread sleep time in milliseconds. * @return -1 means no sleep time. */ public long getSleepTime() { return threadSleep; } /** * Returns BasicPlayer status. * @return status */ public int getStatus() { return m_status; } /** * Open file to play. */ public void open(File file) throws BasicPlayerException { log.info("open(" + file + ")"); if (file != null) { m_dataSource = file; initAudioInputStream(); } } /** * Open URL to play. */ public void open(URL url) throws BasicPlayerException { log.info("open(" + url + ")"); if (url != null) { m_dataSource = url; initAudioInputStream(); } } /** * Open inputstream to play. */ public void open(InputStream inputStream) throws BasicPlayerException { log.info("open(" + inputStream + ")"); if (inputStream != null) { m_dataSource = inputStream; initAudioInputStream(); } }
### 回答1: 可以使用Java 8中的Stream API的distinct()方法来实现去重。例如,假设我们有一个字符串列表,我们可以使用以下代码来去重并打印每个唯一的字符串: ``` List<String> stringList = Arrays.asList("apple", "banana", "apple", "orange", "banana"); stringList.stream().distinct().forEach(System.out::println); ``` 输出结果为: ``` apple banana orange ``` 在这个例子中,我们使用了Stream API的distinct()方法来去重字符串列表,并使用forEach()方法打印每个唯一的字符串。 ### 回答2: 使用Java Stream去重可以通过使用distinct()方法来实现。distinct()方法是Stream接口的一个中间操作,它会返回一个去重后的新Stream,该新Stream不包含重复的元素。 示例代码如下: List<Integer> numbers = Arrays.asList(1, 2, 3, 3, 4, 5, 5); List<Integer> distinctNumbers = numbers.stream().distinct().collect(Collectors.toList()); 在上述代码中,我们有一个整型的List,其中包含了一些重复的数字。通过使用stream()方法,我们可以将List转换为Stream,然后使用distinct()方法去重,最后通过collect(Collectors.toList())方法将去重后的Stream转换为List。 输出结果为:[1, 2, 3, 4, 5],可以看到去重后的List中只包含了不重复的数字。 需要注意的是,distinct()方法会根据元素的hashCode()和equals()方法来进行去重。所以,如果我们在自定义类中需要去重,需要确保重写了hashCode()和equals()方法。 另外,如果想要对自定义类的多个字段进行去重,可以使用如下方式: List<Person> people = new ArrayList<>(); List<Person> distinctPeople = people.stream().distinct().collect(Collectors.toList()); 在这个例子中,我们使用了自定义的Person类。如果希望根据Person对象的多个字段进行去重,就需要在Person类中重写hashCode()和equals()方法,确保根据多个字段的值来判断两个对象是否相同。 ### 回答3: Java StreamJava 8及以上版本引入的一种新的数据处理方式。在Java Stream中去重操作可以通过使用distinct()方法来实现。 通过调用Stream的distinct()方法,可以返回一个去重后的新的Stream。该方法使用元素的equals()方法来确定元素是否重复,从而保留唯一的元素并删除重复的元素。 以下是一个示例代码: ```java import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class RemoveDuplicates { public static void main(String[] args) { List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 3, 2, 1); List<Integer> distinctNumbers = numbers.stream() .distinct() .collect(Collectors.toList()); System.out.println(distinctNumbers); // 输出结果:[1, 2, 3, 4] } } ``` 在以上代码中,我们创建了一个包含重复元素的List,并通过Stream的distinct()方法去除了重复的元素,最后将去重后的结果收集到一个新的List中打印出来。 需要注意的是,distinct()方法依赖元素的equals()方法来判断元素是否相等,因此在自定义类的情况下需要重写equals()方法。此外,distinct()方法是没有顺序保证的,如果希望保留原有顺序,则可以使用LinkedHashSet来实现。 以上就是使用Java Stream进行去重操作的方式。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值