Programcıların% 99'u Lombok kullanıyor, prensip bu kadar basit mi?

Yazar | Pharaoh

Baş Editör | Guo Rui

Çoğu kişinin Lombok'a aşina olduğuna inanıyorum, ancak uygulama ilkeleri ve eksiklikleri hakkında çok az şey biliniyor.Bu makale Lombok'un ilkelerinden başlayacak, Lombok'un basit bir versiyonunu elle boyayacaktır, arkasındaki sıcak teknolojiyi anlamanıza izin verin Uygulama ilkesi ve avantajları ve dezavantajları.

Giriş

Prensipten bahsetmeden önce Lombok'u inceleyelim (eski sürücüler bu bölümü doğrudan atlayabilir).

Lombok çok popüler bir açık kaynak projesidir (https://github.com/rzwitserloot/lombok), bunu kullanarak Setter, Getter, toString, equals, hashCode ve non-empty gibi Java projelerindeki sıkıcı ve tekrarlayan kodu etkili bir şekilde çözebilir Yargılama vb. Lombok ile etkili bir şekilde çözülebilir.

kullanım

1. Lombok eklentisi ekleyin

Lombok tarafından normal olarak değiştirilen kodu çağırmak için Lombok eklentisi IDE'ye kurulmalıdır.İdea'yı örnek alırsak, eklenen adımlar aşağıdaki gibidir:

  • Dosyayı tıklayın > Ayarlar > Eklentiler, eklenti yönetim sayfasına girer

  • Kod depolarına gözat ... seçeneğini tıklayın.

  • Lombok Eklentisi Ara

  • Eklentiyi yüklemek için Eklentiyi yükle'yi tıklayın

  • IntelliJ IDEA'yı yeniden başlatın

Kurulum aşağıda gösterildiği gibi tamamlanmıştır:

2. Lombok kitaplığı ekleyin

Sonra, projeye en son Lombok kitaplığını eklememiz gerekiyor. Bu bir Maven projesiyse, aşağıdaki yapılandırmayı doğrudan pom.xml'ye ekleyin:

< bağımlılıklar > < ! - https://mvnrepository.com/artifact/org.projectlombok/lombok - > < bağımlılık > < Grup kimliği > org.projectlombok < /Grup kimliği > < artifactId > Lombok < / artifactId > < versiyon > 1.18.12 < / version > < dürbün > sağlanan < /dürbün > < /bağımlılık > < / bağımlılıklar >

JDK 9+ ise modül olarak eklenebilir ve yapılandırma aşağıdaki gibidir:

< annotationProcessorPaths > < yol > < Grup kimliği > org.projectlombok < /Grup kimliği > < artifactId > Lombok < / artifactId > < versiyon > 1.18.12 < / version > < / yol > < / annotationProcessorPaths >

3. Lombok'u kullanın

Sırada, ilk yarıda Lombok kullanmanın en önemli kısmı geliyor. Lombok kullanılmadan önce koda bakalım:

public class Kişi {özel Tamsayı kimliği; özel Dize adı; genel Tamsayı getId {dönüş kimliği;} public void setId (Tamsayı kimliği) {this.id = id;} public String getName {dönüş adı;} public void setName (Dize adı) {this.name = ad;}}

Bu, Lombok'u kullandıktan sonraki koddur:

@ Getter @ Setterpublic class Kişi {özel Tamsayı kimliği; özel Dize adı;}

Lombok'tan sonra, önceki tüm Getter / Setter kodunun bir açıklama ile tamamlandığı ve kodu bir anda çok daha zarif hale getirdiği görülebilir.

Tüm Lombok yorumları aşağıdaki gibidir:

  • val: yerel değişkenlerin önünde kullanılır, değişkeni nihai olarak bildirmeye eşdeğer;

  • @Non: Bu ek açıklamayı yöntem parametresine eklemek, parametrenin yöntemde boş olup olmadığını otomatik olarak kontrol eder.İş boşsa, bir NPE (PointerException) atılır;

  • @Cleanup: Kaynakları otomatik olarak yönetin, yerel değişkenleri kullanmadan önce, mevcut değişken kapsamında yürütme tamamlanmadan önce kaynaklar otomatik olarak temizlenir ve akışı kapatmak için try-final gibi kodlar otomatik olarak oluşturulur;

  • @ Getter / @ Setter: Özelliklerde kullanılır, artık ayarlayıcı ve alıcı yöntemlerini kendiniz yazmak zorunda değilsiniz, erişim aralığını da belirtebilirsiniz;

  • @ToString: Sınıfta toString yöntemini otomatik olarak geçersiz kılmak için kullanılabilir, elbette, id özniteliğini hariç tutmak için @ToString (exclude = "id") veya üst sınıfı çağırmak için @ToString (callSuper = true, includeFieldNames = true) gibi başka parametreler de ekleyebilirsiniz. ToString yöntemi tüm öznitelikleri içerir;

  • @EqualsAndHashCode: sınıfta eşittir yöntemini ve hashCode yöntemini otomatik olarak oluşturmak için kullanılır;

  • @NoArgsConstructor, @RequiredArgsConstructor ve @AllArgsConstructor: sınıfta kullanılır, tüm parametreleri kullanan bağımsız değişkenler ve yapıcılar ve parametre olarak tüm @Non özniteliklerini kullanan yapıcılar otomatik olarak oluşturur. StaticName = "of" parametresini belirtirseniz, bu da Bir sınıf nesnesi döndüren bir statik fabrika yöntemi oluşturmak, bir kurucu kullanmaktan çok daha uygundur;

  • @Data: Sınıftaki açıklama, @ToString, @EqualsAndHashCode, @Getter, @Setter ve @RequiredArgsConstrutor aynı anda kullanılmaya eşdeğerdir, bu POJO sınıfları için çok kullanışlıdır;

  • @Value: Sınıfta kullanılan, @Data'nın değişmez bir biçimidir, özelliğe bir son ifade eklemeye eşdeğerdir, ayarlayıcı yöntemleri değil, yalnızca alıcı yöntemleri sağlar;

  • @Builder: Person.builder.name ("xxx"). City ("xxx") çağırabilmeniz için size karmaşık oluşturucu API'leri sağlamak için sınıflarda, yapıcılarda ve yöntemlerde kullanılır.

  • @SneakyThrows: Yönteme atar ifadesini açıkça kullanmadan kontrol edilen istisnaları otomatik olarak at;

  • @Synchronized: Yöntemlerde kullanılır, yöntemin otomatik olarak senkronize edileceği ve kilitlendiği bildirilir ve kilit nesnesi özel bir özellik veya LOCK'dur ve Java kilit nesnesindeki senkronize edilmiş anahtar kelime, bu veya kendi sınıfında kilitlenmiştir. Nesneler üzerinde yan etkiler vardır, yani, kontrolsüz kodun bunu veya sınıf nesnelerini kilitlemesini önleyemezsiniz, bu da yarış koşullarına veya diğer iş parçacığı hatalarına neden olabilir;

  • @Getter (lazy = true): Klasik Double Check Lock standart kodunun yerini alabilir;

  • @Log: Farklı notlara göre farklı türde günlük nesneleri oluşturun, ancak örnek adlarının tümü günlüktür ve altı isteğe bağlı uygulama sınıfı vardır:

  • @CommonsLog Log = org.apache.commons.logging.LogFactory.getLog (LogExample.class) oluşturur;

  • @Log Oluşturur log = java.util.logging.Logger.getLogger (LogExample.class.getName);

  • @ Log4j log = org.apache.log4j.Logger.getLogger (LogExample.class) oluşturur;

  • @ Log4j2 log = org.apache.logging.log4j.LogManager.getLogger (LogExample.class) oluşturur;

  • @ Slf4j log = org.slf4j.LoggerFactory.getLogger (LogExample.class) oluşturur;

  • @ XSlf4j log = org.slf4j.ext.XLoggerFactory.getXLogger (LogExample.class) oluşturur;

Özel kullanımları aşağıdaki gibidir:

val kullanımı

val setleri = yeni HashSet < Dize > ; // Son Sete Eşdeğer < Dize > setler = yeni HashSet < > ;

Kullanılmama

public void notExample (@Non String string) {string.length;} // public void notExample (String string) {if (string! =) {string.length;} else {throw new PointerException ("");} }

Temizleme kullanımı

public static void main (String argümanları) {deneyin {@Cleanup InputStream inputStream = new FileInputStream (args);} catch (FileNotFoundException e) {e.printStackTrace;} // InputStream ile eşdeğerdir inputStream =; {inputStream = new FileInputStream (değiştirgeler );} catch (FileNotFoundException e) {e.printStackTrace;} sonunda {if (inputStream! =) {deneyin {inputStream.close;} catch (IOException e) {e.printStackTrace;}}}}

Getter / Setter Kullanımı

@Setter (AccessLevel.PUBLIC) @Getter (AccessLevel.PROTECTED) özel int id; özel String şekli;

ToString kullanımı

@ToString (exclude = "id", callSuper = true, includeFieldNames = true) public class LombokDemo {private int id; private String name; private int age; public static void main (String args) {// çıktı LombokDemo (super = LombokDemo @ 48524010, ad =, yaş = 0) System.out.println (yeni LombokDemo);}}

EqualsAndHashCode Kullanımı

@EqualsAndHashCode (exclude = {"id", "shape"}, callSuper = false) public class LombokDemo {private int id; private String şekli;}

NoArgsConstructor, RequiredArgsConstructor, AllArgsConstructor kullanımı

@ NoArgsConstructor @ RequiredArgsConstructor (staticName = "of") @ AllArgsConstructor public class LombokDemo {@Non private int id; @Non private String shape; private int age; public static void main (String args) {new LombokDemo (1, "Java") ; // Statik fabrika yöntemini kullanın LombokDemo.of (2, "Java"); // Parametreler olmadan yeni LombokDemo oluşturun; // tüm parametreleri dahil edin new LombokDemo (1, "Java", 2);}}

Oluşturucu kullanımı

@Builderpublic class BuilderExample {private String name; private int age; @Singular private Set < Dize > meslekler; public static void main (String argümanları) {BuilderExample test = BuilderExample.builder.age (11) .name ("Java"). build;}}

SneakyThrows kullanımı

public class ThrowsTest {@SneakyThrows public void read {InputStream inputStream = new FileInputStream ("");} @SneakyThrows public void write {throw new UnsupportedEncodingException;} // Genel void okuma için eşdeğerdir FileNotFoundException {InputStream inputStream = "FileInputStream =" );} genel void yazma, UnsupportedEncodingException {throw new UnsupportedEncodingException;}}

Senkronize kullanım

public class SynchronizedDemo {@Synchronized public static void hello {System.out.println ("world");} // Özel statik nihai Object $ LOCK = new Object ile eşdeğer; public static void hello {senkronize edildi ($ LOCK) {System. out.println ("dünya");}}}

Getter (tembel = doğru) kullanımı

public class GetterLazyExample {@Getter (lazy = true) private final double cached = pahalı; özel çift pahalı {double sonuç = new double; for (int i = 0; i < sonuç.uzunluk; i ++) {sonuç = Math.asin (i);} dönüş sonucu;}} // java.util.concurrent.atomic.AtomicReference; public class GetterLazyExample {private final AtomicReference < java.lang.Object > cached = new AtomicReference < > ; public double getCached {java.lang.Object value = this.cached.get; if (value ==) {senkronize edilmiş (this.cached) {value = this.cached.get; if (value ==) {final double gerçekValue = pahalı; değer = gerçekValue ==? this.cached: gerçekValue; this.cached.set (değer);}}} dönüş (çift) (değer == this.cached ?: değer);} özel çift pahalı {çift sonuç = yeni çift; for (int i = 0; i < sonuç.uzunluk; i ++) {sonuç = Math.asin (i);} dönüş sonucu;}}

İlke analizi

Java'nın derleme sürecinin kabaca üç aşamaya ayrılabileceğini biliyoruz:

  • Sembol tablosunu ayrıştır ve doldur

  • Ek açıklama işleme

  • Analiz ve bayt kodu oluşturma

Derleme süreci aşağıda gösterilmiştir:

Lombok, "açıklama işleme" adımı kullanılarak uygulanır. Lombok, derleme zamanında Lombok'un açıklama kodu olan JDK 6 tarafından uygulanan JSR 269: Eklenebilir Açıklama İşleme API'sini (derlenmiş açıklama işlemcisi) kullanır , Zarif programlama elde etmek için normal Java yöntemlerine dönüştürüldü.

Bu, bu makalenin başında @Data ile uygulanan kod gibi programda doğrulanabilir:

Derledikten sonra, Person sınıfının derlenmiş kaynak kodunu kontrol edin ve kodun aşağıdaki gibi çıktığını bulun:

Kişi sınıfının, derleme zamanında açıklama çevirmeni tarafından Getter, Setter, equals, hashCode ve diğer yöntemleri ekleyerek normal bir Java yöntemine dönüştürüldüğü görülebilir.

Lombok'un yürütme süreci şu şekildedir:

Derleme zamanı aşamasında, Java kaynak kodu bir sözdizimi ağacına (AST) soyutlandığında, Lombok'un AST'yi kendi açıklama işlemcisine göre dinamik olarak değiştireceği, yeni kodlar (düğümler) ekleyeceği ve tüm bunlar yürütüldükten sonra, Son bayt kodu (.class) dosyası, Lombok'un yürütme ilkesi olan analiz yoluyla oluşturulur.

El bir Lombok sopa

Getter yöntemini özelleştirmek için Lombok'un basit bir sürümünü uyguluyoruz, uygulama adımlarımız şunlardır:

  • Bir açıklama etiketi arayüzünü özelleştirin ve özel bir açıklama işlemcisi uygulayın;

  • AST'yi işlemek için tools.jar javac api'yi kullanın (Özet Sözdizimi Ağacı)

  • Özel bir açıklama işlemcisi kullanarak kodu derleyin.

Bu şekilde Lombok'un basit bir versiyonu gerçekleştirilebilir.

1. Özel ek açıklamaları ve açıklama işlemcilerini tanımlayın

İlk olarak bir ek açıklamayı özelleştirmek için bir MyGetter.java oluşturun, kod aşağıdaki gibidir:

import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention (RetentionPolicy.SOURCE) // Ek açıklamalar yalnızca kaynak kodunda saklanır @Target (ElementType.TYPE) // public @interface MyGetter sınıfını değiştirmek için kullanılır {// Getter'ı Tanımla }

Ardından özel bir açıklama işlemcisi uygulayın, kod aşağıdaki gibidir:

import com.sun.source.tree.Tree; import com.sun.tools.javac.api.JavacTrees; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Type; import com.sun.tools.javac.processing.JavacProcessingEnvironment; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.TreeMaker; import com.sun.tools.javac.tree. TreeTranslator; import com.sun.tools.javac.util. *; import javax.annotation.processing. *; içe javax.lang.model.SourceVersion; içe aktarma javax.lang.model.element.Element; içe aktarma javax.lang.model.element.TypeElement; javax.tools.Diagnostic içe aktarma; java içe aktarma. util.Set; @SupportedSourceVersion (SourceVersion.RELEASE_8) @SupportedAnnotationTypes ("com.example.lombok.MyGetter") genel sınıf MyGetterProcessor, AbstractProcessor'ı genişletir { private Messager messager; // derleme sırasında günlüğe girilen özel JavacTrees javacTrees; // soyut sözdizimi ağacının işlenmesini sağlar özel TreeMaker treeMaker; // AST düğümleri özel Adlar oluşturmanın bazı yöntemlerini içerir; // oluşturma tanımlayıcısını sağlar Yöntemler @Override public senkronize void init (ProcessingEnvironment processingEnv) {super.init (processingEnv); this.messager = processingEnv.getMessager; this.javacTrees = JavacTrees.instance (processingEnv); Bağlam bağlam = ((JavacProcessingEnvironment) processingEnv) .getContext; bu .treeMaker = TreeMaker.instance (bağlam); this.names = Names.instance (bağlam);} @ Genel boole sürecini geçersiz kıl (Set < ? TypeElement'i genişletir > ek açıklamalar, RoundEnvironment roundEnv) {Set < ? uzatır Eleman > elementsAnnotatedWith = roundEnv.getElementsAnnotatedWith (MyGetter.class); elementsAnnotatedWith.forEach (e- > {JCTree tree = javacTrees.getTree (e); tree.accept (new TreeTranslator {@Override public void visitClassDef (JCTree.JCClassDecl jcClassDecl) {List < JCTree.JCVariableDecl > jcVariableDeclList = List.nil; // (JCTree jcTree: jcClassDecl.defs) için özet ağacındaki tüm değişkenleri bulun {if (jcTree.getKind.equals (Tree.Kind.VARIABLE)) {JCTree.JCVariableDecl jcVariableDecl = (JCTree .JCVariableDecl) jcTree; jcVariableDeclList = jcVariableDeclList.append (jcVariableDecl);}} // Değişkenler için oluşturma yöntemi işlemi jcVariableDeclList.forEach (jcVariableDecl- > {messager.printMessage (Diagnostic.Kind.NOTE, jcVariableDecl.getName + "işlendi"); jcClassDecl.defs = jcClassDecl.defs.prepend (makeGetterMethodDecl (jcVariableDecl));}); super.visitClass}} );}); true döndür;} private JCTree.JCMethodDecl makeGetterMethodDecl (JCTree.JCVariableDecl jcVariableDecl) {ListBuffer < JCTree.JCStatement > ifadeler = yeni ListBuffer < > ; // this.a = a; JCTree.JCExpressionStatement aThis = makeAssignment (treeMaker.Select (treeMaker.Ident (names.fromString ("this")), jcVariableDecl.getName), treeMaker.Ident (jcVariableDecl.getName )); statement.append (aThis); JCTree.JCBlock blok = treeMaker.Block (0, deyimler.toList); // Giriş parametrelerini oluşturun JCTree.JCVariableDecl param = treeMaker.VarDef (treeMaker.Modifiers (Flags.PARAMETER), jcVariableDecl.getName, jcVariableDecl.vartype,); List < JCTree.JCVariableDecl > parametreler = List.of (param); // JCTree.JCExpression dönüş nesnesini oluştur methodType = treeMaker.Type (new Type.JCVoidType); return treeMaker.MethodDef (treeMaker.Modifiers (Flags.PUBLIC), getNewMethodName (jcVariableDecl.getName), methodType, List.nil, parametreler, List .nil, blok); } özel Ad getNewMethodName (Name name) {String s = name.toString; return names.fromString ("get" + s.substring (0, 1) .toUpperCase + s.substring (1, name.length));} private JCTree.JCExpressionStatement makeAssignment (JCTree.JCExpression lhs, JCTree.JCExpression rhs) {return treeMaker.Exec (treeMaker.Assign (lhs, rhs));}}

Özel açıklama işlemcisi, Lombok'un basitleştirilmiş sürümünün uygulanmasında en büyük önceliğimizdir. AbstractProcessor sınıfını miras almamız ve başlangıç ve işlem yöntemlerini yeniden yazmamız gerekir. İşlem yönteminde, önce tüm değişkenleri sorgulayıp değişkenlere karşılık gelen değişkenleri ekliyoruz. Yöntemler. Yukarıdaki kodda gösterildiği gibi AST'yi işlemek için TreeMaker nesnelerini ve Adlarını kullanıyoruz.

Bu kodlar yazıldıktan sonra özel @MyGetter fonksiyonumuzu denemek için bir Person sınıfı ekleyebiliriz, kod aşağıdaki gibidir:

@MyGetterpublic class Kişi {private String name;}

2. Kodu derlemek için özel açıklama işlemcisini kullanın

Yukarıdaki tüm işlemler yürütüldükten sonra, etkiyi test etmek için kodu derleyebiliriz. Öncelikle kodun kök dizinine girip aşağıdaki üç komutu uyguluyoruz.

Girilen kök dizin aşağıdaki gibidir:

Özel açıklayıcıları derlemek için tools.jar'ı kullanın

javac -cp $ JAVA_HOME / lib / tools.jar MyGetter * -d.

Not: Mevcut klasörü belirtmek için komutun sonunda bir "." Vardır.

Person sınıfını derlemek için özel bir açıklama kullanın

javac -processor com.example.lombok.MyGetterProcessor Person.java

Kişi kaynak kodunu görüntüleyin

javap -p Kişi.class

Kaynak kod dosyaları aşağıdaki gibidir:

Özel getName yöntemimizin başarıyla oluşturulduğunu ve artık Lombok'un basit sürümünün tamamlandığını görebilirsiniz.

Lombok avantajları ve dezavantajları

Lombok'un avantajları ortadadır, daha az kod yazmamızı sağlar, geliştirme süresinden tasarruf sağlar ve kodu daha zarif gösterir, dezavantajları aşağıdaki gibidir.

Dezavantaj 1: Azaltılmış hata ayıklama

Lombok bizim için otomatik olarak çok sayıda kod üretecektir, ancak bu kodlar derleme döneminde üretilir, bu nedenle bu kodlar geliştirme ve hata ayıklama aşamalarında "kaybolabilir", bu da kodun hata ayıklamasına büyük rahatsızlık verir.

Dezavantaj 2: Uyumluluk sorunları olabilir

Lombok koda çok müdahaleci. Buna ek olarak, JDK sürüm yükseltmeleri artık nispeten hızlı. Bir sürüm altı ayda bir yayınlanıyor. Lombok üçüncü taraf bir projeye aittir ve açık kaynak ekibi tarafından sürdürülür. Bu nedenle, sürüm uyumluluğunu ve yinelemeyi sağlamanın bir yolu yoktur. Hız, sürüm uyumsuzluğuna neden olabilir.

Dezavantaj 3: Takım arkadaşlarını çukurlaştırabilir

Özellikle gruba yeni gelenler için daha büyük bir etkisi olabilir, eğer bu daha önce Lombok'u kullanmadıysa, kodu aşağı çektiğinde, Lombok eklentisi kurulu olmadığı için projeyi derlerken bir yöntem bulamama gibi bir hata mesajı verecektir. , Proje derleme başarısızlığıyla sonuçlanan, bu da birlik üyeleri arasındaki işbirliğini etkiledi.

Dezavantaj 4: Kapsüllemeyi yok eder

Nesne yönelimli kapsüllemenin tanımı, erişim kontrolü yoluyla dahili verileri gizlemektir ve harici, yalnızca sınıf tarafından sağlanan sınırlı arabirim aracılığıyla dahili verilere erişebilir ve bunları değiştirebilir.

Başka bir deyişle, alışveriş sepetindeki ürün sayısı gibi bazı durumlarda doğrudan alışverişe etki eden bazı alanların doğrudan değiştirilmesine izin verilmediğinden, Lombok'un tüm alanları düşünmeden dışarıya maruz bırakan Getter / Setter yöntemini kullanmamalıyız. Ayrıntılar ve toplam fiyat, bu nedenle değiştirirken, her alana erişim ve değiştirme yöntemleri eklemek yerine, ilişkili değişiklikleri yapmak için birleşik bir yöntem sağlanmalıdır.

özet

Bu makalede, Lombok'un kullanım ve yürütme ilkesini tanıtıyoruz.Bu, Lombok'un notlarını derleme zamanında Java'nın geleneksel yöntemlerine dönüştüren JDK 6 JSR 269: Pluggable Annotation Processing API (derlenmiş açıklama işlemcisi) tarafından uygulanmaktadır. AbstractProcessor sınıfını miras alarak ve init ve process yöntemlerini yeniden yazarak Lombok'un basit bir sürümünü uygulayabiliriz. Ancak aynı zamanda, Lombok'un kullanımda bazı eksiklikleri de vardır, örneğin: azaltılmış hata ayıklama, uyumluluk ve diğer sorunlar, bu nedenle Lombok'u kullanırken iş senaryolarımıza ve gerçek koşullara göre kullanıp kullanmamayı seçmeliyiz. Ve Lombok'un nasıl kullanılacağı.

Son olarak, bir hatırlatma, teknoloji ne kadar iyi olursa olsun, her derde deva değil, tıpkı ayağınıza ne kadar iyi bir ayakkabı sığdırmanız gerektiği gibi!

Feragatname: Bu makale yazar tarafından sunulmuştur ve telif hakkı kendisine aittir.

Sıcak makale önerisi

"Hey Siri" nin arkasındaki siyah teknoloji ortaya çıktı!

Terminal öykünücüsü büyük bir PK, kimi seçersiniz?

Programcının tekerlekleri yapması için doğru duruş

Temel programlama bilgisi gerçekten mucizevi bir beceri mi?

Kubernetes'te PaaS benzeri basit bir platform kurmak çok kolay!

Megvii ikili şube ağı BBN'den bahsediyor: Uzun kuyruklu gerçek dünya görevinin üstesinden gelmek | CVPR 2020 Oral

2020'de herkesin bildiği bu 20 kripto borsası nasıl gidiyor?

Ön uç makine öğrenimi: İnsan yüzlerini tanıyın ve yanaklara çilek çizin
önceki
Geçtiğimiz 15 yılda, bulut bilişim devrimini gerçekte ne tetikledi?
Sonraki
Python ne zaman değiştirilecek?
"Hey Siri" nin arkasındaki siyah teknoloji ortaya çıktı
Terminal öykünücüsü büyük PK, kimi seçersiniz?
Endüstriyel İnterneti iyice anlamanıza yardımcı olacak 11 soru
Bilgisayar korsanları "öldürmek için bıçak ödünç alırlar", Alibaba'nın 14 yıllık deneyimi size DDoS saldırılarına karşı nasıl savunma yapacağınızı öğretecek
C dili en ciddi güvenlik açıklarına sahiptir ve PHP en savunmasız olanıdır.Programcılar nasıl kod yazmalıdır?
Alibaba Cloud uzmanları size BT mimarisini nasıl yeniden şekillendireceğinizi öğretiyor
Luckin Coffee 2,2 milyarlık sahte işlemi açığa çıkarıyor ve Uygulama İLK 1'i geri alıyor
Programcıların bilmesi gereken 89 temel işletim sistemi kavramı
Yazdığım kod değil, ama ...
İnternetin babasına yeni bir taç teşhisi kondu, bir efsane: Google'ın başkan yardımcısı ve NASA'da misafir bilim insanı olarak görev yaptı
Google, Büyük Ölçekli Ölçeklendirilebilir Kapsamlı Güçlendirmeli Öğrenim için Yeni Bir Mimari olan SEED RL Kaynaklarını Açıyor
To Top