Java java지도 시간 Java 프로그래밍에서 람다 표현식 사용에 대한 팁

Java 프로그래밍에서 람다 표현식 사용에 대한 팁

Jan 23, 2017 pm 03:03 PM

람다 표현식을 사용하는 이유
몇 가지 예를 살펴보겠습니다.

첫 번째 예는 독립 스레드에서 작업을 수행하는 것입니다. 일반적으로 다음과 같이 구현합니다.

class Worker implements Runnable {
  public void run() {
    for (int i = 0; i < 100; i++)
      doWork();
  }
  ...
}
 
Worker w = new Worker();
new Thread(w).start();
로그인 후 복사

두 번째 예는 문자열 비교 방법을 사용자 정의하는 것입니다(문자열 길이를 통해). 일반적으로 다음을 수행합니다.

class LengthComparator implements Comparator<String> {
  public int compare(String first, String second) {
    return Integer.compare(first.length(), second.length());
  }
}
Arrays.sort(strings, new LengthComparator());
로그인 후 복사

아니요, 세 가지 예입니다. JavaFX에서는 버튼에 콜백을 추가합니다.

button.setOnAction(new EventHandler<ActionEvent>() {
  public void handle(ActionEvent event) {
    System.out.println("Thanks for clicking!");
  }
});
로그인 후 복사

이러한 예에는 한 가지 공통점이 있습니다. 즉, 먼저 코드 블록을 정의하고 이를 객체나 메소드에 전달하고, 그런 다음 실행되었습니다. Lambda 테이블
표현식 이전에는 Java가 객체 지향이기 때문에 Java가 코드 블록을 직접 전달할 수 없으므로 코드 블록을 객체로 캡슐화하기 위해 객체를 전달해야
합니다.

람다 표현식의 구문
위 두 번째 예의 LengthComparator는 람다 표현식으로 표현됩니다.

(String first, String second) -> Integer.compare(first.length(),
  second.length());
로그인 후 복사

-> 그 뒤에 식 문 본문이 옵니다.

식 문 본문이 한 줄 이상인 경우 일반 함수와 마찬가지로 {}에 문 본문을 작성합니다.

(String first, String second) -> {
  if (first.length() > second.length()) {
    return 1;
  } else if (first.length() == second.length()) {
    return 0;
  } else {
    return -1;
  }
};
로그인 후 복사

매개변수가 없는 경우에도 ()를 가져와야 합니다. 예를 들어 위의 첫 번째 예는 다음과 같이 표현할 수 있습니다.

() -> {
  for (int i = 0; i < 1000; i ++) {
    doWork();
  }
}
로그인 후 복사

매개변수 유형을 자동으로 지정할 수 있는 경우 컨텍스트에서 추론된 경우 생략 가능:

Comparator<String> comp
  = (first, second) // Same as (String first, String second)
  -> Integer.compare(first.length(), second.length());
로그인 후 복사

매개변수가 하나만 있고 유형을 자동으로 추론할 수 있는 경우 괄호()도 생략할 수 있습니다:

// Instead of (event) -> or (ActionEvent event) ->
eventHandler<ActionEvent> listener =
  event -> System.out.println("Thanks for clicking!");
로그인 후 복사

lambda 표현식의 반환 값 유형은 자동으로 유추되므로 람다 표현식에서 이를 지정할 필요가 없습니다. 일부 조건부 분기에는
반환 값이 있고 다른 분기에는

반환 값이 있습니다. 다음과 같은 반환 값은 허용되지 않습니다.

(x) -> {
  if (x >= 0) {
    return 1;
  }
}
로그인 후 복사


또한 식 람다와 명령문 람다의 차이점은 식 람다에서는 반환을 작성하는 데
가 필요하지 않다는 점입니다. 키워드. Java 런타임은 표현식의 결과를 반환 값으로 반환합니다. while 문 람다

가 {}로 작성한 표현식이며, return 키워드를 사용해야 합니다. 예:

// expression lambda
Comparator<String> comp1 =
  (first, second) -> Integer.compare(first.length(), second.length());
 
// statement lambda
Comparator<String> comp2 = (first, second) ->
  { return Integer.compare(first.length(), second.length());};
로그인 후 복사


함수형 인터페이스
인터페이스에 추상 메서드(추상 메서드)가 하나만 있는 경우
Runnable, Comparator 등 함수형 인터페이스라고 합니다.

Functional Interface 객체가 필요할 때마다 람다 식을 사용할 수 있습니다.

Arrays.sort(words,
  (first, second) -> Integer.compare(first.length(), second.length()));
로그인 후 복사


여기에서 sort()의 두 번째 매개변수에는 Comparator 객체가 필요합니다. Comparator는
입니다. 기능적 인터페이스이므로 객체의 Compare() 메서드

가 호출되면 람다 표현식의 명령문 본문이 실행됩니다. 람다 표현식이 예외를 발생시키는 경우 기능 인터페이스의 해당 추상 메소드는 예외를

발생시켜야 합니다. 그렇지 않으면 예외는 람다 표현식에서 명시적으로 캡처되어야 합니다:

Runnable r = () -> {
  System.out.println("------");
  try {
    Thread.sleep(10);
  } catch (InterruptedException e) {
    // catch exception
  }
};
 
Callable<String> c = () -> {
  System.out.println("--------");
  Thread.sleep(10);
  return "";
};
로그인 후 복사

메서드 참조

람다 식의 매개 변수가 메서드에 매개 변수로 전달되고 해당 실행 효과가 동일한 경우 람다 식
은 다음 두 가지 방법으로 메서드 참조를 사용하여 표현할 수 있습니다.

(x) -> System.out.println(x)
System.out::println
로그인 후 복사

여기서 System.out::println은 Method Reference라고 합니다.

메서드 참조에는 주로 세 가지 형식이 있습니다.

object::instanceMethod

Class::staticMethod

Class::instanceMethod

처음 두 메서드의 경우 해당 람다 식의 매개 변수는 메서드의 매개 변수와 일치합니다. 예:

System.out::println
(x) -> System.out.println(x)
 
Math::pow
(x, y) -> Math.pow(x, y)
로그인 후 복사

세 번째 메서드의 경우 해당 람다 식은 다음과 같습니다. 명령문 본문에서 첫 번째 매개변수는 객체로 사용되고 메서드가 호출되며 다른 매개변수

는 메서드의 매개변수로 사용됩니다. 예:

String::compareToIgnoreCase
(s1, s2) -> s1.compareToIgnoreCase(s2)
1.5 Constructor Reference
로그인 후 복사

생성자 참조 Method Reference와 비슷하지만 특별한 메소드입니다. new는 호출되는 생성자가 컨텍스트에 따라 결정됩니다. 예를 들어

List<String> labels = ...;
Stream<Button> stream = labels.stream().map(Button::new);
로그인 후 복사

Button::new는 (x와 동일합니다. ) -> Button(x), 따라서 호출되는 생성자는 다음과 같습니다. Button(x);

단일 개체를 만드는 것 외에도 다음 두 가지 방법은 동일합니다.

int[]::new
(x) -> new int[x]
로그인 후 복사

변수 범위

lambd 표현식은 다음과 같이 현재 범위에서 사용 가능한 변수를 캡처합니다.

public void repeatMessage(String text, int count) {
  Runnable r = () -> {
    for (int i = 0; i < count; i ++) {
      System.out.println(text);
      Thread.yield();
    }
  };
  new Thread(r).start();
}
로그인 후 복사

그러나 이러한 변수는 불변이어야 하는데, 왜 그렇습니까? 다음 예를 살펴보세요.

int matches = 0;
for (Path p : files)
  new Thread(() -> { if (p has some property) matches++; }).start();
  // Illegal to mutate matches
로그인 후 복사

변경 가능한 변수는 람다 식에서 스레드로부터 안전하지 않기 때문에 이는 내부 클래스의 요구 사항과 일치합니다.

외부적으로만 참조할 수 있습니다.

람다 식의 범위는 중첩된 코드 블록의 범위와 동일하므로 람다 식의 매개변수 이름이나 변수 이름은

지역 변수 충돌과 동일할 수 없습니다. 예:

Path first = Paths.get("/usr/bin");
Comparator<String> comp = (first, second) -> Integer.compare(first.length(),
   second.length()); // Error: Variable first already defined
로그인 후 복사

이 변수가 람다 식에서 참조되는 경우 다음과 같이 람다 식을 만든 메서드의 this 변수입니다.

public class Application() {
  public void doWork() {
    Runnable runner = () -> {
      ...;
      System.out.println(this.toString());
      ...
    };
  }
}
로그인 후 복사

여기서 this.toString()은 Runnable

객체가 아닌 Application 객체의 toString()을 호출합니다.

기본 메서드

인터페이스에는 추상 메서드만 있을 수 있습니다. 기존 인터페이스에 새 메서드가 추가되는 경우 인터페이스의 모든 구현 클래스는 이 메서드를 구현해야 합니다.
기본 메서드 개념은 Java 8에서 도입되었습니다. 인터페이스에 새 기본 메서드를 추가해도 기존 인터페이스 규칙은 삭제되지 않습니다. 인터페이스의 구현 클래스는 기본 메서드를 재정의하거나 직접 상속하도록 선택할 수 있습니다.
아아아아

Java是允许多继承的,如果一个类的父类中定义的方法和接口中定义的default方法完全相同,或者
一个类的两个接口中定义了完全相同的方法, 则如何处理这种冲突呢?处理规则如下:

如果是父类和接口的方法冲突:以父类中的方法为准,接口中的方法被忽略;
如果两个接口中的default方法冲突,则需要重写该方法解决冲突;

Static Method
Java 8之前,接口中只能定义static变量,Java 8开始,接口中可以添加static方法,比如
Comparator接口新增了一系列comparingXXX的static方法,比如:

public static <T> Comparator<T> comparingInt(ToIntFunction<? super T>
  keyExtractor) {
  Objects.requireNonNull(keyExtractor);
  return (Comparator<T> & Serializable)
   (c1, c2) -> Integer.compare(keyExtractor.applyAsInt(c1),
       keyExtractor.applyAsInt(c2));
}
로그인 후 복사

使用这个static方法,以下两种方式也是等价的:

1、

Arrays.sort(cities, (first, second) -> Integer.compare(first.length(),
  second.length()));
로그인 후 복사

2、

Arrays.sort(cities, Comparator.comparingInt(String::length));
로그인 후 복사

所以,以后我们在设计自己的接口时,不需要再定义单独的工具类(如Collections/Collection),
在接口中使用static方法就行了。

匿名内部类

在 Java 世界中,匿名内部类 可以实现在应用程序中可能只执行一次的操作。例如,在 Android 应用程序中,一个按钮的点击事件处理。你不需要为了处理一个点击事件单独编写一个独立的类,可以用匿名内部类完成该操作:

Button button = (Button) findViewById(R.id.button1);
button.setOnClickListener(new OnClickListener() {
  
  @Override
  public void onClick(View view) {
    Toast.makeText(MainActivity.this, "Button Clicked", Toast.LENGTH_SHORT).show();
  }
  
});
로그인 후 복사

Lambda 示例

1.Runnable Lambda

来看几个示例, 下面是一个 Runnable 的示例:

public void runnableTest() {
    System.out.println("=== RunnableTest ===");
    // 一个匿名的 Runnable
    Runnable r1 = new Runnable() {
      @Override
      public void run() {
        System.out.println("Hello world one!");
      }
    };
    // Lambda Runnable
    Runnable r2 = () -> System.out.println("Hello world two!");
    // 执行两个 run 函数
    r1.run();
    r2.run();
  }
로그인 후 복사
public void runnableTest() {
  System.out.println("=== RunnableTest ===");
  // 一个匿名的 Runnable
  Runnable r1 = new Runnable() {
    @Override
    public void run() {
      System.out.println("Hello world one!");
    }
  };
 
  // Lambda Runnable
  Runnable r2 = () -> System.out.println("Hello world two!");
 
  // 执行两个 run 函数
  r1.run();
  r2.run();
}
로그인 후 복사

这两个实现方式都没有参数也没有返回值。Runnable lambda 表达式使用代码块的方式把五行代码简化为一个语句。
2.Comparator Lambda

在 Java 中,Comparator 接口用来排序集合。在下面的示例中一个 ArrayList 中包含了一些 Person 对象, 并依据 Person 对象的 surName 来排序。下面是 Person 类中包含的 fields:

public class Person {
  private String givenName;
  private String surName;
  private int age;
  private Gender gender;
  private String eMail;
  private String phone;
  private String address;
}
로그인 후 복사
로그인 후 복사
public class Person {
  private String givenName;
  private String surName;
  private int age;
  private Gender gender;
  private String eMail;
  private String phone;
  private String address;
}
로그인 후 복사
로그인 후 복사

下面是分别用匿名内部类和 Lambda 表达式实现 Comparator 接口的方式:

 
public class ComparatorTest {
  public static void main(String[] args) {
    List<Person> personList = Person.createShortList();
    // 使用内部类实现排序
    Collections.sort(personList, new Comparator<Person>() {
      public int compare(Person p1, Person p2) {
        return p1.getSurName().compareTo(p2.getSurName());
      }
    });
    System.out.println("=== Sorted Asc SurName ===");
    for (Person p : personList) {
      p.printName();
    }
    // 使用 Lambda 表达式实现
    // 升序排列
    System.out.println("=== Sorted Asc SurName ===");
    Collections.sort(personList, (Person p1, Person p2) -> p1.getSurName().compareTo(p2.getSurName()));
    for (Person p : personList) {
      p.printName();
    }
    // 降序排列
    System.out.println("=== Sorted Desc SurName ===");
    Collections.sort(personList, (p1, p2) -> p2.getSurName().compareTo(p1.getSurName()));
    for (Person p : personList) {
      p.printName();
    }
  }
}
로그인 후 복사
public class ComparatorTest {
  public static void main(String[] args) {
    List<Person> personList = Person.createShortList();
  
    // 使用内部类实现排序
    Collections.sort(personList, new Comparator<Person>() {
      public int compare(Person p1, Person p2) {
        return p1.getSurName().compareTo(p2.getSurName());
      }
    });
  
    System.out.println("=== Sorted Asc SurName ===");
    for (Person p : personList) {
      p.printName();
    }
  
    // 使用 Lambda 表达式实现
  
    // 升序排列
    System.out.println("=== Sorted Asc SurName ===");
    Collections.sort(personList, (Person p1, Person p2) -> p1.getSurName().compareTo(p2.getSurName()));
    for (Person p : personList) {
      p.printName();
    }
  
    // 降序排列
    System.out.println("=== Sorted Desc SurName ===");
    Collections.sort(personList, (p1, p2) -> p2.getSurName().compareTo(p1.getSurName()));
    for (Person p : personList) {
      p.printName();
    }
  }
}
로그인 후 복사

   

可以看到 匿名内部类可以通过 Lambda 表达式实现。注意 第一个 Lambda 表达式定义了参数的类型为 Person;而第二个 Lambda 表达式省略了该类型定义。Lambda 表达式支持类型推倒,如果通过上下文可以推倒出所需要的类型,则可以省略类型定义。这里由于 我们把 Lambda 表达式用在一个使用泛型定义的 Comparator 地方,编译器可以推倒出这两个参数类型为 Person 。

更多Java编程中使用lambda表达式的奇技淫巧相关文章请关注PHP中文网!

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25 : Myrise에서 모든 것을 잠금 해제하는 방법
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

Java의 클래스로드 메커니즘은 다른 클래스 로더 및 대표 모델을 포함하여 어떻게 작동합니까? Java의 클래스로드 메커니즘은 다른 클래스 로더 및 대표 모델을 포함하여 어떻게 작동합니까? Mar 17, 2025 pm 05:35 PM

Java의 클래스 로딩에는 부트 스트랩, 확장 및 응용 프로그램 클래스 로더가있는 계층 적 시스템을 사용하여 클래스로드, 링크 및 초기화 클래스가 포함됩니다. 학부모 위임 모델은 핵심 클래스가 먼저로드되어 사용자 정의 클래스 LOA에 영향을 미치도록합니다.

카페인 또는 구아바 캐시와 같은 라이브러리를 사용하여 자바 애플리케이션에서 다단계 캐싱을 구현하려면 어떻게해야합니까? 카페인 또는 구아바 캐시와 같은 라이브러리를 사용하여 자바 애플리케이션에서 다단계 캐싱을 구현하려면 어떻게해야합니까? Mar 17, 2025 pm 05:44 PM

이 기사는 카페인 및 구아바 캐시를 사용하여 자바에서 다단계 캐싱을 구현하여 응용 프로그램 성능을 향상시키는 것에 대해 설명합니다. 구성 및 퇴거 정책 관리 Best Pra와 함께 설정, 통합 및 성능 이점을 다룹니다.

Java에서 기능 프로그래밍 기술을 어떻게 구현할 수 있습니까? Java에서 기능 프로그래밍 기술을 어떻게 구현할 수 있습니까? Mar 11, 2025 pm 05:51 PM

이 기사는 Lambda 표현식, 스트림 API, 메소드 참조 및 선택 사항을 사용하여 기능 프로그래밍을 Java에 통합합니다. 간결함과 불변성을 통한 개선 된 코드 가독성 및 유지 관리 가능성과 같은 이점을 강조합니다.

캐싱 및 게으른 하중과 같은 고급 기능을 사용하여 객체 관계 매핑에 JPA (Java Persistence API)를 어떻게 사용하려면 어떻게해야합니까? 캐싱 및 게으른 하중과 같은 고급 기능을 사용하여 객체 관계 매핑에 JPA (Java Persistence API)를 어떻게 사용하려면 어떻게해야합니까? Mar 17, 2025 pm 05:43 PM

이 기사는 캐싱 및 게으른 하중과 같은 고급 기능을 사용하여 객체 관계 매핑에 JPA를 사용하는 것에 대해 설명합니다. 잠재적 인 함정을 강조하면서 성능을 최적화하기위한 설정, 엔티티 매핑 및 모범 사례를 다룹니다. [159 문자]

고급 Java 프로젝트 관리, 구축 자동화 및 종속성 해상도에 Maven 또는 Gradle을 어떻게 사용합니까? 고급 Java 프로젝트 관리, 구축 자동화 및 종속성 해상도에 Maven 또는 Gradle을 어떻게 사용합니까? Mar 17, 2025 pm 05:46 PM

이 기사에서는 Java 프로젝트 관리, 구축 자동화 및 종속성 해상도에 Maven 및 Gradle을 사용하여 접근 방식과 최적화 전략을 비교합니다.

비 블로킹 I/O에 Java의 NIO (새로운 입력/출력) API를 어떻게 사용합니까? 비 블로킹 I/O에 Java의 NIO (새로운 입력/출력) API를 어떻게 사용합니까? Mar 11, 2025 pm 05:51 PM

이 기사에서는 선택기와 채널을 사용하여 단일 스레드와 효율적으로 처리하기 위해 선택기 및 채널을 사용하여 Java의 NIO API를 설명합니다. 프로세스, 이점 (확장 성, 성능) 및 잠재적 인 함정 (복잡성,

적절한 버전 및 종속성 관리로 Custom Java 라이브러리 (JAR Files)를 작성하고 사용하려면 어떻게해야합니까? 적절한 버전 및 종속성 관리로 Custom Java 라이브러리 (JAR Files)를 작성하고 사용하려면 어떻게해야합니까? Mar 17, 2025 pm 05:45 PM

이 기사에서는 Maven 및 Gradle과 같은 도구를 사용하여 적절한 버전 및 종속성 관리로 사용자 정의 Java 라이브러리 (JAR Files)를 작성하고 사용하는 것에 대해 설명합니다.

네트워크 통신에 Java의 Sockets API를 어떻게 사용합니까? 네트워크 통신에 Java의 Sockets API를 어떻게 사용합니까? Mar 11, 2025 pm 05:53 PM

이 기사는 네트워크 통신을위한 Java의 소켓 API, 클라이언트 서버 설정, 데이터 처리 및 리소스 관리, 오류 처리 및 보안과 같은 중요한 고려 사항에 대해 자세히 설명합니다. 또한 성능 최적화 기술, i

See all articles