java8特性随记

Java 8 至 Java 23 版本特性对比表 Java 8 至 Java 23 版本特性对比 阅读详情

接口的默认方法

Java 8 使我们能够通过使用关键字default将非抽象方法实现添加到接口中。

这是我们的第一个示例:

interface Formula {
    double calculate(int a);
 
    default double sqrt(int a) {
        return Math.sqrt(a);
    }

}

除了抽象方法,接口还定义了默认方法。具体类只需要实现抽象方法。默认方法可以开箱即用。

Formula formula = new Formula() {
    @Override
    public double calculate(int a) {
        return sqrt(a * 100);
    }
};

formula.calculate(100);     // 100.0
formula.sqrt(16);           // 4.0

该公式是作为匿名对象实现的。代码非常冗长:6 行代码用于如此简单的计算sqrt(a * 100)。正如我们将在下一节中看到的,在 Java 8 中实现单方法对象有一种更好的方法。

Lambda 表达式

让我们从一个简单的例子开始,说明如何在早期版本的 Java 中对字符串列表进行排序:

List<String> names = Arrays.asList("peter", "anna", "mike", "xenia");

Collections.sort(names, new Comparator<String>() {
    @Override
    public int compare(String a, String b) {
        return b.compareTo(a);
    }
});

静态实用程序方法接受一个列表和一个比较器,以便对给定列表的元素进行排序Collections.sort。您经常发现自己创建了匿名比较器并将它们传递给排序方法。

Java 8 不是整天创建匿名对象,而是提供了更短的语法,即 lambda 表达式:

Collections.sort(names, (String a, String b) -> {
    return b.compareTo(a);
});

正如你所看到的,代码要短得多,更易于阅读。对于一行方法主体,您可以跳过大括号{}和关键字return,使它变得更短。

Collections.sort(names, (String a, String b) -> b.compareTo(a));

List接口同样存在方法sort成员方法,java 编译器知道参数类型,因此您也可以跳过它们。

names.sort((a, b) -> b.compareTo(a));

Functional接口

lambda 表达式如何合理的适配 Java 类?

每个 lambda 对应于一个给定的类型,由接口指定。所谓的函数接口必须只包含一个抽象方法声明。该类型的每个 lambda 表达式都将与此抽象方法匹配。由于默认方法不是抽象的,因此您可以自由地将默认方法添加到函数接口中。

我们可以使用任意接口作为 lambda 表达式,只要该接口只包含一个抽象方法即可。为确保你的接口满足要求,你应该添加@FunctionalInterface注解。编译器会识别到此注解,并在你尝试向接口添加第二个抽象方法声明时立即引发编译器错误。

例:

@FunctionalInterface
interface Converter<F, T> {
    T convert(F from);
}
Converter<String, Integer> converter = from -> Integer.valueOf(from);
Integer converted = converter.convert("123");
System.out.println(converted);    // 123

请记住,如果省略注解@FunctionalInterface,代码也有效。

方法和构造函数引用

上面的示例代码可以通过使用静态方法引用来进一步简化:

Converter<String, Integer> converter = Integer::valueOf;
Integer converted = converter.convert("123");
System.out.println(converted);   // 123

Java 8 允许您通过关键字::传递方法或构造函数的引用。上面的示例演示如何引用静态方法。但是我们也可以引用对象方法:

class Something {
    String startsWith(String s) {
        return String.valueOf(s.charAt(0));
    }
}
Something something = new Something();
Converter<String, String> converter = something::startsWith;
String converted = converter.convert("Java");
System.out.println(converted);    // "J"

让我们看看关键字::如何为构造函数工作。首先,我们定义一个具有不同构造函数的示例类:

class Person {
    String firstName;
    String lastName;

    Person() {}
    
    Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

}

接下来,我们指定一个用于创建新人员的人员工厂接口:

interface PersonFactory<P extends Person> {
    P create(String firstName, String lastName);
}

我们不是手动实现工厂,而是通过构造函数引用将所有内容粘合在一起:

PersonFactory<Person> personFactory = Person::new;
Person person = personFactory.create("Peter", "Parker");

我们通过 创建一个对 Person 构造函数的引用Person::new。Java 编译器通过匹配调用PersonFactory.create来自动选择正确的构造函数。

Lambda 作用域

从 lambda 表达式访问外部作用域变量与匿名对象非常相似。您可以从局部外部作用域以及实例字段和静态变量访问最终变量。

访问局部变量
我们可以从 lambda 表达式的外部作用域读取最终的局部变量:

final int num = 1;
Converter<Integer, String> stringConverter =
        from -> String.valueOf(from + num);

stringConverter.convert(2);     // 3

但与匿名对象不同的是,num变量不必声明为最终变量。此代码也有效:

int num = 1;
Converter<Integer, String> stringConverter =
        from -> String.valueOf(from + num);

stringConverter.convert(2);     // 3

但是num必须是隐式的最终版本才能编译。以下代码不编译:

int num = 1;
Converter<Integer, String> stringConverter =
        from -> String.valueOf(from + num);
num = 3;

也禁止num从 lambda 表达式中写入。

访问字段和静态变量

与局部变量相比,我们可以从 lambda 表达式中读取和写入实例字段和静态变量。这种行为在匿名对象中是众所周知的。

class Lambda4 {
    static int outerStaticNum;
    int outerNum;

    void testScopes() {
        Converter<Integer, String> stringConverter1 = from -> {
            outerNum = 23;
            return String.valueOf(from);
        };
    
        Converter<Integer, String> stringConverter2 = from -> {
            outerStaticNum = 72;
            return String.valueOf(from);
        };
    }

}

访问默认接口方法

还记得第一部分的示例吗?Formula接口定义了一个默认方法,可以从每个公式实例(包括匿名对象)访问该方法。这不适用于 lambda 表达式。

无法从 lambda 表达式中访问默认方法sqrt。以下代码不编译:

Formula formula = (a) -> sqrt(a * 100);

内置功能接口

JDK 1.8 API 包含许多内置功能接口。其中一些在旧版本的 Java 中是众所周知的,例如 Comparator或Runnable 。这些现有接口已扩展为通过注解@FunctionalInterface启用 Lambda 表达式支持。

但 Java 8 API 也新添了很多功能接口,让编码更加简洁。

Predicate

Predicate是一个参数的布尔值函数。该接口包含各种默认方法,用于将谓词组合为复杂的逻辑术语(和、或否定)

Predicate<String> predicate = s -> s.length() > 0;

predicate.test("foo");              // true
predicate.negate().test("foo");     // false

Predicate<Boolean> nonNull = Objects::nonNull;
Predicate<Boolean> isNull = Objects::isNull;

Predicate<String> isEmpty = String::isEmpty;
Predicate<String> isNotEmpty = isEmpty.negate();

Function

Function接受一个参数并生成结果。默认方法可用于将多个函数链接在一起(compose 和 Then)。

Function<String, Integer> toInteger = Integer::valueOf;
Function<String, String> backToString = toInteger.andThen(String::valueOf);

backToString.apply("123");     // "123"

Supplier

Supplier生成给定泛型类型的结果。与Function不同,Supplier不接受参数。

Supplier<Person> personSupplier = Person::new;
personSupplier.get();   // new Person

Consumer

Consumer表示要对单个输入参数执行的操作。

Consumer<Person> greeter = p -> System.out.println("Hello, " + p.firstName);
greeter.accept(new Person("Luke", "Skywalker"));

Comparator

Comparator在旧版本的 Java 中是众所周知的。Java 8 向接口添加了各种默认方法。

Comparator<Person> comparator = (p1, p2) -> p1.firstName.compareTo(p2.firstName);

Person p1 = new Person("John", "Doe");
Person p2 = new Person("Alice", "Wonderland");

comparator.compare(p1, p2);             // > 0
comparator.reversed().compare(p1, p2);  // < 0

Optional

Optional不是功能接口,而是要帮助我们优雅的处理NullPointerException。

Optional是值的简单容器,该值可以是 null 或非 null。想想一个方法,它可能返回一个非 null 结果,但有时什么都不返回,在 Java 8 中,你可以返回一个Optional而避免返回null。

Optional<String> optional = Optional.of("bam");

optional.isPresent();           // true
optional.get();                 // "bam"
optional.orElse("fallback");    // "bam"

optional.ifPresent(s -> System.out.println(s.charAt(0)));     // "b"

Streams

一个Stream流可以表示可以对其执行一个或多个操作的元素序列。流操作可以是中间操作,也可以是终端操作。终端操作返回特定类型的结果,而中间操作返回流本身,因此可以连续链接多个方法调用。流是在源上创建的,如java.util.Collection中的List和Set等(不支持Map)。流操作可以按顺序执行,也可以并行执行。

让我们先看看顺序流是如何工作的。首先,我们以字符串列表的形式创建一个示例源数据:

List<String> stringCollection = new ArrayList<>();
stringCollection.add("ddd2");
stringCollection.add("aaa2");
stringCollection.add("bbb1");
stringCollection.add("aaa1");
stringCollection.add("bbb3");
stringCollection.add("ccc");
stringCollection.add("bbb2");
stringCollection.add("ddd1");

Java 8 中的集合进行了扩展,因此您可以简单地通过调用Collection.stream() 或Collection.parallelStream() 来创建流,以下是几种常见的流操作。

Filter

Filter 接受一个Predicate来筛选流的所有元素。此操作是中间操作,它使我们能够对结果调用另一个流操作 (forEach)。ForEach 接受要为筛选流中的每个元素执行的使用者。ForEach 是一个终端操作。它是void ,因此我们不能调用另一个流操作。

stringCollection
    .stream()
    .filter(s -> s.startsWith("a"))
    .forEach(System.out::println);

// "aaa2", "aaa1"

Sorted

Sorted 是一个中间操作,它返回流的排序视图。元素按自然顺序排序,除非你传递自定义的Comparator。

stringCollection
    .stream()
    .sorted()
    .filter((s) -> s.startsWith("a"))
    .forEach(System.out::println);

// "aaa1", "aaa2"

请记住,sorted只会创建流的排序情况,而不会操作集合源数据stringCollection的顺序。

System.out.println(stringCollection);
// ddd2, aaa2, bbb1, aaa1, bbb3, ccc, bbb2, ddd1

Map

中间操作map通过给定的函数将每个元素转换为另一个对象。下面的示例将每个字符串转换为大写字符串。但您也可以使用map将每个对象转换为另一种类型。生成的流的泛型类型取决于传递给map的函数的泛型类型。

stringCollection
    .stream()
    .map(String::toUpperCase)
    .sorted((a, b) -> b.compareTo(a))
    .forEach(System.out::println);

// "DDD2", "DDD1", "CCC", "BBB3", "BBB2", "AAA2", "AAA1"

Match

可以使用各种匹配操作来检查某个谓词是否与流匹配。所有这些操作都是终端操作,并返回布尔结果。

boolean anyStartsWithA =
    stringCollection
        .stream()
        .anyMatch(s -> s.startsWith("a"));

System.out.println(anyStartsWithA);      // true

boolean allStartsWithA =
    stringCollection
        .stream()
        .allMatch(s -> s.startsWith("a"));

System.out.println(allStartsWithA);      // false

boolean noneStartsWithZ =
    stringCollection
        .stream()
        .noneMatch(s -> s.startsWith("z"));

System.out.println(noneStartsWithZ);      // true

Count

Count 是一个终端操作,返回long

long startsWithB =
    stringCollection
        .stream()
        .filter(s -> s.startsWith("b"))
        .count();

System.out.println(startsWithB);    // 3

Reduce

reduce操作使用给定函数对流的元素执行简化合并,返回的结果是一个简化后的optional

Optional<String> reduced =
    stringCollection
        .stream()
        .sorted()
        .reduce((s1, s2) -> s1 + "#" + s2);

reduced.ifPresent(System.out::println);
// "aaa1#aaa2#bbb1#bbb2#bbb3#ccc#ddd1#ddd2"

Parallel Streams

如上所述,流可以是有序的,也可以是并行的。对有序流的操作在单个线程上执行,而对并行流的操作在多个线程上并发执行。

下面的例子将说明使用并行流提高性能是多么容易。

首先,我们创建一个大型唯一元素列表:

int max = 1000000;
List<String> values = new ArrayList<>(max);
for (int i = 0; i < max; i++) {
    UUID uuid = UUID.randomUUID();
    values.add(uuid.toString());
}

现在,我们测量对此集合的流进行排序所需的时间。

顺序排序

long t0 = System.nanoTime();

long count = values.stream().sorted().count();
System.out.println(count);

long t1 = System.nanoTime();

long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0);
System.out.println(String.format("sequential sort took: %d ms", millis));

// sequential sort took: 899 ms

并行排序

long t0 = System.nanoTime();

long count = values.parallelStream().sorted().count();
System.out.println(count);

long t1 = System.nanoTime();

long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0);
System.out.println(String.format("parallel sort took: %d ms", millis));

// parallel sort took: 472 ms

正如你所看到的,两个代码片段几乎相同,但并行排序的速度大约快了 50%。您所要做的就是将 stream()更改为parallelStream()

Maps

如前所述,Map不直接支持流,其接口本身没有可用的stream()方法,但是您可以通过在map的key、value或entry上创建专用流。

map.keySet().stream()

map.values().stream()

map.entrySet().stream()

此外,map还支持各种有用的新方法来执行常见任务,如

Map<Integer, String> map = new HashMap<>();

for (int i = 0; i < 10; i++) {
    map.putIfAbsent(i, "val" + i);
}

map.forEach((id, val) -> System.out.println(val));

上面的代码应该是不言自明的:putIfAbsent防止我们编写额外的 if null 检查; forEach接受使用者对映射的每个值执行操作。

如何利用函数在map上计算代码:

map.computeIfPresent(3, (num, val) -> val + num);
map.get(3);             // val33

map.computeIfPresent(9, (num, val) -> null);
map.containsKey(9);     // false

map.computeIfAbsent(23, num -> "val" + num);
map.containsKey(23);    // true

map.computeIfAbsent(3, num -> "bam");
map.get(3);             // val33

接下来,我们将学习如何删除给定键的条目,仅当它当前映射到给定值时:

map.remove(3, "val3");
map.get(3);             // val33

map.remove(3, "val33");
map.get(3);             // null

另一个有用的方法:

map.getOrDefault(42, "not found");  // not found

合并map的entry非常容易:

map.merge(9, "val9", (value, newValue) -> value.concat(newValue));
map.get(9);             // val9

map.merge(9, "concat", (value, newValue) -> value.concat(newValue));
map.get(9);             // val9concat

如果不存在键/值的条目,则将键/值放入映射中,或者将调用合并函数来更改现有值。

日期 API

Java 8 在java.time包下包含了一个全新的日期和时间 API。新的 Date API 可与 Joda-Time 库相媲美,但并不相同。以下示例介绍了此新 API 的最重要部分。

Clock

Clock提供对当前日期和时间的访问。时钟知道一个时区,可以代替System.currentTimeMillis()用来检索自 Unix EPOCH 以来的当前时间(以毫秒为单位)。时间轴上的这样一个瞬时点也用Instant类来表示。Instants 可用于创建旧java.util.Date对象。

Clock clock = Clock.systemDefaultZone();
long millis = clock.millis();

Instant instant = clock.instant();
Date legacyDate = Date.from(instant);   // legacy java.util.Date

Timezones

Timezones通过ZoneId表示,它可以通过静态工厂方法轻松访问。时区定义了偏移量,这些偏移量对于在即时和本地日期和时间之间转换非常重要。

System.out.println(ZoneId.getAvailableZoneIds());
// prints all available timezone ids

ZoneId zone1 = ZoneId.of("Europe/Berlin");
ZoneId zone2 = ZoneId.of("Brazil/East");
System.out.println(zone1.getRules());
System.out.println(zone2.getRules());

// ZoneRules[currentStandardOffset=+01:00]
// ZoneRules[currentStandardOffset=-03:00]

LocalTime

LocalTime 表示没有时区的时间,例如晚上 10 点或 17:30:15。以下示例为上面定义的时区创建两个本地时间。然后我们比较两个时间,并计算两个时间之间的小时和分钟差异。

LocalTime now1 = LocalTime.now(zone1);
LocalTime now2 = LocalTime.now(zone2);

System.out.println(now1.isBefore(now2));  // false

long hoursBetween = ChronoUnit.HOURS.between(now1, now2);
long minutesBetween = ChronoUnit.MINUTES.between(now1, now2);

System.out.println(hoursBetween);       // -3
System.out.println(minutesBetween);     // -239

LocalTime 附带了各种工厂方法,以简化新实例的创建,包括时间字符串的解析。

LocalTime late = LocalTime.of(23, 59, 59);
System.out.println(late);       // 23:59:59

DateTimeFormatter germanFormatter =
    DateTimeFormatter
        .ofLocalizedTime(FormatStyle.SHORT)
        .withLocale(Locale.GERMAN);

LocalTime leetTime = LocalTime.parse("13:37", germanFormatter);
System.out.println(leetTime);   // 13:37

LocalDate

LocalDate 表示不同的日期,例如 2014-03-11。它是不可变的,并且与 LocalTime 完全类似。此例子演示如何通过添加或减去天、月或年来计算新日期。请记住,每次操作都会返回一个新实例。

LocalDate today = LocalDate.now();
LocalDate tomorrow = today.plus(1, ChronoUnit.DAYS);
LocalDate yesterday = tomorrow.minusDays(2);

LocalDate independenceDay = LocalDate.of(2014, Month.JULY, 4);
DayOfWeek dayOfWeek = independenceDay.getDayOfWeek();
System.out.println(dayOfWeek);    // FRIDAY

从字符串解析 LocalDate 与解析 LocalTime 一样简单:

DateTimeFormatter germanFormatter =
    DateTimeFormatter
        .ofLocalizedDate(FormatStyle.MEDIUM)
        .withLocale(Locale.GERMAN);

LocalDate xmas = LocalDate.parse("24.12.2014", germanFormatter);
System.out.println(xmas);   // 2014-12-24
LocalDateTime

LocalDateTime 表示日期时间。它将上述部分中所示的日期和时间合并到一个实例中。 是不可变的,其工作方式类似于 LocalTime 和 LocalDate。我们可以利用从日期时间检索某些字段的方法:LocalDateTime

LocalDateTime sylvester = LocalDateTime.of(2014, Month.DECEMBER, 31, 23, 59, 59);

DayOfWeek dayOfWeek = sylvester.getDayOfWeek();
System.out.println(dayOfWeek);      // WEDNESDAY

Month month = sylvester.getMonth();
System.out.println(month);          // DECEMBER

long minuteOfDay = sylvester.getLong(ChronoField.MINUTE_OF_DAY);
System.out.println(minuteOfDay);    // 1439

通过时区的附加信息,它可以转换为即时信息。即时可以很容易地转换为类型java.util.Date的旧日期。

Instant instant = sylvester
        .atZone(ZoneId.systemDefault())
        .toInstant();

Date legacyDate = Date.from(instant);
System.out.println(legacyDate);     // Wed Dec 31 23:59:59 CET 2014

设置日期时间格式的工作方式与设置日期或时间格式一样。我们可以从自定义模式创建格式化程序,而不是使用预定义的格式。

DateTimeFormatter formatter =
    DateTimeFormatter
        .ofPattern("MMM dd, yyyy - HH:mm");

LocalDateTime parsed = LocalDateTime.parse("Nov 03, 2014 - 07:13", formatter);
String string = formatter.format(parsed);
System.out.println(string);     // Nov 03, 2014 - 07:13

与java.text.SimpleDateFormat不同的是,DateTimeFormatter是不可变的和线程安全的。

更多详细用法,可以参考官方文档

Annotations

Java 8 中的注解是可重复的。让我们直接进入一个例子来弄清楚这一点。

首先,我们定义一个包装器注解,它包含一个实际注解的数组:

@Repeatable(Hints.class)
@interface Hint {
    String value();
}
@interface Hints {
    Hint[] value();
}

Java 8 允许我们通过声明@Repeatable 来使用多个相同类型的注解

变体 1:使用容器注解(老方式)

@Hints({@Hint("hint1"), @Hint("hint2")})
class Person {}

变体 2:使用可重复注释(新方式)

@Hint("hint1")
@Hint("hint2")
class Person {}

使用变体 2,java 编译器隐式地在后台设置@Hints注解。这对于通过反射读取注释信息非常重要。

Hint hint = Person.class.getAnnotation(Hint.class);
System.out.println(hint);                   // null

Hints hints1 = Person.class.getAnnotation(Hints.class);
System.out.println(hints1.value().length);  // 2

Hint[] hints2 = Person.class.getAnnotationsByType(Hint.class);
System.out.println(hints2.length);          // 2

虽然我们从未在类Person上声明过注解@Hints,但它仍然可以通过getAnnotation(Hints.class)被读到,但是,更方便的方法是getAnnotationsByType直接访问所有带@Hint的注释。

此外,Java 8 中的注解扩展了两个新作用范围:

@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
@interface MyAnnotation {}

ElementType.TYPE_PARAMETER表示注解可以应用于类型参数(泛型参数)上。
下面是一个简单的例子,演示如何使用ElementType.TYPE_PARAMETER:

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

@Target(ElementType.TYPE_PARAMETER)
public @interface TypeParameterAnnotation {
    // 这里可以定义一些注解的属性
}

class Example<T> {
    public void method(@TypeParameterAnnotation T param) {
        // 方法体
    }
}

ElementType.TYPE_USE 表示注解可以应用于任何使用类型的地方,包括类、接口、枚举、注解、泛型类型、方法的返回类型、字段、局部变量、方法参数等。

ElementType.TYPE_USE 的引入是为了支持更加灵活的注解使用场景。它使得注解可以更广泛地应用于类型相关的地方,而不仅仅是限定在声明上。

以下是一个简单的例子,演示如何使用 ElementType.TYPE_USE:

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

@Target(ElementType.TYPE_USE)
public @interface TypeUseAnnotation {
    // 这里可以定义一些注解的属性
}

public class Example {
    public static void main(String[] args) {
        @TypeUseAnnotation String exampleString = "Hello, World!";
        System.out.println(exampleString);
    }
}

Android Studio如何支持java8特性 Android Studio对Java8特性的支持 Android Studio 3.0及以上版本支持所有Java7语言功能,以及部分Java8语言功能,这里要注意一下,不是所有Java8特性都支持。 Android官网罗列的:支持的Java 8语言功能和API 使用默认工具链 所谓默认工具链,就是Android studio官方自带的工具集,用于Java8特性编译处理,非第三方工具,当然兼容性和... 阅读详情

相关推荐

保姆级教程:在RK3588 Android12设备树(DTS)中配置MIPI 8 Lane双通道与DSC显示

本文详细介绍了在RK3588 Android12平台上配置MIPI 8 Lane双通道与DSC显示的实战指南。通过设备树(DTS)参数详解、DSC参数计算与PPS配置、双通道同步机制实现等内容,帮助开发者高效完成高分辨率屏幕驱动配置,解决嵌入式显示系统开发中的常见挑战。

weixin_30905133的博客 399

随记——java8新特性

尚硅谷_Java零基础教程-java入门必备-初学者基从入门到精通全套完整版(宋红康主讲) P666-665 文章目录1. Lambda表达式lambda表达式的使用:6种语法格式总结2. 函数式接口如何理解函数式接口java内置四大核心函数式接口测试 `Consumer `:测试 `Predicate`:3. 方法引用与构造器引用方法引用的使用情况一 对象 :: 实例方法情况二 类 :: 静态方法情况三 类 :: 非静态方法构造器引用无参构造器含参构造器数组 String[]::new4. Stre

488

别再为多相机标定头疼了!用VisionMaster统一坐标系的保姆级教程

本文详细介绍了使用VisionMaster平台解决多相机视觉系统中坐标系统一问题的完整流程。从标定板选择到N点标定,再到实战演练,提供了从原理到落地的全方位指导,帮助工程师高效解决多相机定位引导中的坐标偏差问题。

weixin_38168322的博客 635

java8 新特性学习随记

1. 接口的默认方法和静态方法 java8 以前的接口是不允许定义有方法体的方法,java8允许在接口中定义有方法体的方法, 默认方法,使用default关键字定义,语法如下: public interface Person{ // 和普通方法定义一致,只是使用了default关键字修饰 default String sayHello(String name){ ...

lixiufei_1028的博客 248

PLDM实战解析:传感器与效应器在智能监控系统中的应用

本文深入解析了PLDM(平台级数据模型)中传感器与效应器两大核心组件在智能监控系统中的应用。传感器负责感知硬件状态,分为数值型与状态型,提供精准的“体检报告”;效应器则负责执行控制指令,实现从监控到操作的闭环。文章通过实战案例,阐述了如何利用这些标准化组件构建高效、自动化的智能监控系统,并探讨了平台描述记录与事件机制等关键技术。

k6l7m8n9的博客 874

mcgs数据查表功能,用于大量数据对比查找对应数据,减少PLC代码

mcgs脚本实现数据查表功能

qq_24866535的博客 3271

【Java】从java8到java17各版本新特性详解

下面这张图是 Oracle 官方给出的 Oracle JDK 支持的时间线,可以看出,JDK 17的支持时间最长,可以延续到2029年9月。考虑到技术更新的速度,这次免费商用8年的时间可谓是经过精心考虑,旨在让用户放心地升级到JDK 17(不过JDK 8的支持时间更长,可以延续到2030年12月)。从JDK诞生到现在,仅有几个版本得到了长期支持,主要包括JDK 7、JDK 8、JDK 11以及即将发布的JDK 17,它将是继Java 8之后最重要的LTS版本,是Java社区八年努力的成果。

一个天蝎座的程序猿 5892

C++(Qt)软件调试---Windows下Qt使用dump定位崩溃位置(1)

在C++/Qt程序崩溃时,往往很难找到崩溃的原因,如果是稳定复现的问题还好,但是多数情况遇见的问题是随机出现的,这时想要快速找到问题并解决就需要通过dump文件定位崩溃位置。

mahuifa的博客 1万+

java8新特性详解

java8新特性详解随记概括小隐小故事——为什么要学习java8 随记 文骚人不骚的小隐又来整理小知识了。 最近把公司的jdk版本升级到了jdk8,也算抓住个尾巴。虽然之前已经深入学习了java8的新特性,不过为了方便交流学习还是把自己所了解的一些知识进行整理。防止以后自己忘记或者他人有需要了解的时候,可以查阅。 概括 这篇作为小隐整理java8的开篇,算是一个引子吧。主要列举一下要整理的内容,稍...

诡道的博客 1190

五万字解析【ROOT 入门指南】

本文是cern官方root入门指南的初步翻译版,还在进一步校对中....

荷塘阅色 208

Oracle EBS 寄销/VMI(1)-->基础设置

名词解释:     BPA:一揽子采购协议     BPR:一揽子发放     SR:来源补充规则     ASL:合格供应商列表     VMI: 供应商管理库存     寄售(Consignment)是把货物放在客户那里,客户要用的时候才付款的库存,一般是指卖方把

陈显平的专栏-Oracle EBS 1万+

【Java 8 新特性】Java 8 新特性大全

【Java 8 新特性】目录Java Util StreamJava Util FunctionJava Util ConcurrentJava UtilJava TimeJava MathJava Lang Java Util Stream 【Java 8 新特性】Java Stream中forEachOrdered()和forEach() 【Java 8 新特性】如何将Java流(Stream)转化成数组(Array) Java Util Function Java Util Concurrent

猫巳的博客 3035

多摄像头场景下 ISP 的同步与调度机制实战解析

在智能手机多摄系统中,主摄、广角、长焦、微距等摄像头的协同工作能力直接决定了影像系统的体验上限。而支撑这一能力的核心之一,正是 ISP 的同步与调度机制。ISP 需要处理多个 Sensor 的输入流、统一时序、资源仲裁、并发调度,并支持在不同模式间快速切换(如预览 → 拍照 → 视频)。本文将基于 Qualcomm、MTK、HiSilicon 平台的实际架构,系统性剖析 ISP 在多摄场景下的时序控制、Pipeline 配置、Buffer 管理与故障恢复机制,并分享实战中的典型问题与调试方案。

努力分享一些人工智能、计算机视觉、影像等相关的知识干货! 2351

Java 8 新特性

Java 8 新特性

YIYIYI 1573

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Java8新特性

Java8新特性 面试问到你Java8的新特性,你能答上来吗 Java现在更新到了很高的版本,不过不建议它一更新我们就去了解、就去学。因为很少概率能用的到,现在很多公司或企业使用的版本都是比较低的。新版本需要经过岁月的考验,才能知道哪些特性是好用的哪些是不好用的。 Java8可以看成自Java5以来最具有革命性的版本,**非常推荐**学习Java8的新特性。 在学习的时候,会遇到的非常多听着、看着都一头雾水的概念。不要被劝退,看代码,带着疑问去学习。怎么去实现?它能用来干嘛? 第一遍学习完过后,只是给自己了

qq_44769557的博客 2958

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

Java 8有哪些新特性

(1)Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。使用Lambda 表达式可以使代码变的更加简洁紧凑。 (2) 方法引用通过方法的名字来指向一个方法。方法引用可以使语言的构造更紧凑简洁,减少冗余代码。方法引用使用一对冒号 :: 。 (3) 函数式接口(FunctionalInterfac...

小靖靖的博客 8357

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

java7和java8特性

JDK 1.7部分新特性 1)switch支持String类型 本质上是对int类型的匹配, 实现原理为:通过case后面的str对象调用hashcode()方法,得到一个int类型的hash值,然后用这个hash值来唯一标识这个case.当匹配时,首先调用这个字符串的hashcode()方法,获得一个hash值,用这个hash值与case匹配,若没有则不存在,若有则接着调用equals()方...

柯惟的博客 7141

Java8+特性知识体系详解

作为当今使用最广泛的编程语言之一的 Java 在 2018 年 3 月 21 日发布了第十个大版本。为了更快地迭代、更好地跟进社区反馈,Java 语言版本发布周期调整为每隔 6 个月发布一次。Java 10 是这一新规则之后,采用新发布周期的第一个大版本。Java 10 版本带来了很多新特性,其中最备受广大开发者关注的莫过于局部变量类型推断。除此之外,还有其他包括垃圾收集器改善、GC 改进、性能提升、线程管控等一批新特性。

珍惜当下 1135

Java 8 升Java 11 重要特性必读

这里帮你梳理为何JDK 11会是一个极为重要的版本以及如何去理解它。

珍惜当下 1081

Java8到Java20都有那些新特性

以上是各个版本的一些关键特性。每个版本还包含了许多其他的改进、bug修复和安全更新。对于更具体的技术细节,建议查阅相应版本的官方文档或者相关技术资料。

m0_50742275的博客 1308

【java 新特性】java8新特性

在Java世界里面,面向对象还是主流思想,对于习惯了面向对象编程的开发者来说,抽象的概念并不陌生。面向对象编程是对数据进行抽象,而函数式编程是对行为进行抽象。现实世界中,数据和行为并存,程序也是如此,因此这两种编程方式我们都得学。这种新的抽象方式还有其他好处。很多人不总是在编写性能优先的代码,对于这些人来说,函数式编程带来的好处尤为明显。程序员能编写出更容易阅读的代码——这种代码更多地表达了业务逻辑,而不是从机制上如何实现。易读的代码也易于维护、更可靠、更不容易出错。在写回调函数和事件处理器时,程序员不必再

养猪少年日记的博客 2384

重学Java 8新特性 | 第1讲——我们为什么要学习Java 8新特性?

为什么我们一定要学习Java 8新特性?

李阿昀的博客 1723

Java8新特性详解

说明:新的专栏,本专栏专门讲Java8新特性,把平时遇到的问题与Java8的写法进行总结,需要注意的地方都标红了,一起加油。 本文是介绍Java8新特性与常用方法(此篇只做大体介绍了解,之后会把重要的部分写在新的博客中)

biyn9的博客 2021

Java 8 特性

Java 8 特性 文章目录Java 8 特性函数式编程函数式编程让代码更灵活1、初始需求:筛选出绿苹果2、 变更需求:根据颜色筛选苹果----->修改初版方法3、追加需求:根据重量筛选苹果----->追加方法4、追加需求:根据颜色和重量筛选苹果----->追加方法5、使用接口抽象筛选行为6、使用匿名类7、使用Lambda表达式8、将 List 类型抽象化Lambda 表达式简洁地表示可传递的匿名函数的一种方式在哪里以及如何使用 Lambda函数式接口把 Lambda 付诸实践:环绕执行模

weixin_46488959的博客 1156
上一篇: 前端复制与粘帖Demo
下一篇: html原生table动态值合并
strap
博客等级 码龄3年 60粉丝 53原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值