0% found this document useful (0 votes)
680 views1,260 pages

Java Language Ru

Uploaded by

bullfinch2
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
680 views1,260 pages

Java Language Ru

Uploaded by

bullfinch2
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 1260

Java Language

#java
1

1: Java Language 2

Java- 2

Java 3

Java- 3

? 3

Examples 4

Java 5

Hello World 7

2: 2D- Java 11

11

Examples 11

1: Java 11

2: 13

3: Apache Commons Lang 15

Examples 15

equals () 15

hashCode () 15

toString () 16

4: API Reflection 19

19

19

19

Examples 19

19

21
21

23

- 23

«» 23

23

() 25

25

API Reflection 26

27

28

Java- 29

5: API 32

32

Examples 32

32

33

33

6: AppDynamics TIBCO BusinessWorks 35

35

Examples 35

BW Appdynamics 35

*** . . *** 35

7: Autoboxing 37

37

37

Examples 37

int Integer 37

Boolean if 39

NullPointerException 39

39

Integer int 41

8: BigDecimal 43
43

Examples 43

BigDecimal 43

BigDecimals 43

BigDecimal 43

1.Addition 43

2.Subtraction 44

3.Multiplication 44

4.Division 45

5.Remainder 45

6.Power 46

7.Max 46

8.Min 46

9. 46

10. 46

BigDecimal float 47

BigDecimal.valueOf () 48

BigDecimals , 48

9: BigInteger 49

49

49

49

Examples 50

50

BigIntegers 51

BigInteger 52

BigInteger 54

BigIntegers 55

10: BufferedWriter 57

57

57
Examples 57

57

11: ByteBuffer 59

59

59

Examples 59

- ByteBuffer 59

- 60

- DirectByteBuffer 60

12: CompletableFuture 62

62

Examples 62

62

CompletingFuture 63

13: Enum, 65

65

Examples 65

Enum 65

14: FileUpload AWS 66

66

Examples 66

s3 66

15: FTP ( ) 69

69

69

Examples 69

FTP- 69

16: HttpURLConnection 75

75

Examples 75

URL- 75
POST 76

77

77

78

, 78

: 78

: 78

17: InputStreams OutputStreams 80

80

80

Examples 80

InputStream 80

OutputStream 80

81

82

/ 82

82

/ 83

DataInputStream 84

18: Java Pitfalls - 85

85

Examples 85

Pitfall - 85

Pitfall - Catching Throwable, Exception, Error RuntimeException 86

Pitfall - Throwable, Exception, Error RuntimeException 88

Throwable Exception «» . 88

Pitfall - Catching InterruptedException 89

Pitfall - 91

Pitfall - 92

Pitfall - «Throwable» 93

19: Java Pitfalls - 94


94

94

Examples 94

Pitfall - 94

Pitfall - «» «» 94

Pitfall - 95

Pitfall - : «, » «» 97

Pitfall - 99

Pitfall - 100

Pitfall - , 100

Pitfall - '==' 101

Pitfall - 102

Pitfall: 'assert' 103

Pitfall - 104

20: JavaBean 106

106

106

107

Examples 107

Java- 107

21: Java- 108

Examples 108

108

109

109

22: Java-, , 111

Examples 111

Java SE JRE Java SE JDK 111

Java Runtime Environment 111

Java Development Kit 111

Oracle Hotspot OpenJDK 112

Java EE, Java SE, Java ME JavaFX 113


Java 113

Java SE 113

Java EE 114

Java ME 114

Java FX 114

Java SE 114

Java SE 114

Java SE 116

23: JAXB 118

118

118

118

118

Examples 118

XML- ( ) 118

XML- (unmarshalling) 119

XmlAdapter XML 120

XML / XML (@XmlAccessorType) 121

XML / 123

XmlAdapter () 124

124

124

125

XML 126

126

XML Java. 127

XmlAdapter . 127

24: JAX-WS 129

Examples 129

129

25: JMX 130


130

Examples 130

MBean Server 130

26: JNDI 135

Examples 135

RMI JNDI 135

27: JShell 140

140

140

140

140

Examples 141

JShell 141

JShell 141

JShell 141

141

141

142

142

28: JSON Java 145

145

145

Examples 145

JSON 145

JSON 146

optXXX vs getXXX 146

JSON ( Gson) 147

JSON To Object ( Gson) 147

JSON 148

Mapper Jackson 148

148

ObjectMapper 148
: 149

: 149

JSON 149

JSON Builder - 150

JSONObject.NULL 150

JsonArray Java (Gson Library) 150

JSON , Jackson 151

JSON 152

TypeFactory 152

Type 152

JSON 152

TypeFactory 152

Type 152

153

153

29: LinkedHashMap 154

154

Examples 154

Java LinkedHashMap 154

30: log4j / log4j2 156

156

156

156

Log4j 1 156

Examples 157

Log4j 157

Log4j Java- 158

158

log4j2.xml 159

log4j 1.x 2.x 159

- 161
(log4j 1.x) 161

31: NIO - 163

163

Examples 163

Selector ( OP_CONNECT) 163

32: NumberFormat 165

Examples 165

NumberFormat 165

33: ServiceLoader 166

166

Examples 166

166

166

166

META-INF / / servicetest.Logger 167

167

ServiceLoader 168

34: SortedMap 170

170

Examples 170

. 170

35: Streams 172

172

172

Examples 172

172

174

174

( ) 175

175

toList() toSet() 175


List Set 176

- 178

179

179

h21 181

181

182

182

182

183

184

185

185

IntStream to String 186

186

187

187

, 187

IntStream 188

flatMap () 188

189

191

191

192

Map.Entry 193

193

: 193

194

194

194

195

195
198

36: StringBuffer 200

200

Examples 200

String 200

37: StringBuilder 202

202

202

202

Examples 202

n 202

StringBuffer, StringBuilder, Formatter StringJoiner 203

38: sun.misc.Unsafe 206

206

Examples 206

sun.misc.Unsafe 206

sun.misc.Unsafe bootclasspath 206

207

207

39: ThreadLocal 209

209

Examples 209

ThreadLocal Java 8 209

ThreadLocal 209

211

40: TreeMap TreeSet 214

214

Examples 214

TreeMap Java 214

TreeSet Java 215

TreeMap / TreeSet Java 216

TreeMap TreeSet 217


41: Varargs ( ) 220

220

Examples 220

varargs 220

Varargs 220

42: WeakHashMap 222

222

Examples 222

WeakHashmap 222

43: XJC 224

224

224

224

224

Examples 224

Java- XSD- 224

XSD (schema.xsd) 224

xjc 225

225

package-info.java 227

44: XOM - XML 228

Examples 228

XML- 228

XML 230

45: 234

234

Examples 234

Apache HashBag, Guava HashMultiset Eclipse HashBag 234

1. SynchronizedSortedBag Apache : 234

2. TreeBag Eclipse (GC) : 235

3. LinkedHashMultiset Guava : 235


: 236

Guava, Apache Eclipse 236

Nore: 239

- 239

- 239

46: XML API JAXP 245

245

DOM 245

SAX 245

StAX 246

Examples 246

DOM API 246

API StAX 247

47: 250

250

250

250

250

Examples 250

250

254

255

255

- 255

@Target 255

255

@Retention 257

257

@Documented 257

@Inherited 257

@Repeatable 258
258

259

260

260

261

261

262

263

264

javac 264

IDE 265

Netbeans 265

265

265

«» 266

267

48: 269

269

269

Examples 269

269

270

271

, 271

272

272

273

49: 274

274

274

274
Examples 274

274

275

Atomic Types? 276

Atomic Types? 277

50: 279

279

Examples 279

279

MIDI- 279

281

282

51: 283

Examples 283

283

283

/ 284

284

/ 285

52: 287

287

287

Examples 287

JCE 287

287

Java 288

288

288

288

53: - 290

290

Examples 290
/ 290

,, . 291

2 292

, 2 292

java.util.BitSet 294

295

54: 297

Examples 297

297

55: (java.util.logging) 298

Examples 298

298

298

() 299

56: ( ) 302

302

302

Examples 303

303

303

304

304

305

305

57: Java (JVM) 307

Examples 307

. 307

58: Java 308

Examples 308

JNA 308

JNA? 308

? 308
? 309

59: 310

310

310

310

310

311

Examples 312

312

312

314

315

316

317

317

318

60: Java SE 7 320

320

320

Examples 320

Java SE 7 320

321

try-with-resources 321

321

322

322

61: Java SE 8 324

324

324

Examples 324

Java SE 8 324

62: 326
326

Examples 326

- Java Collections 326

63: 327

327

327

Examples 327

327

329

329

330

330

, 331

331

332

333

333

64: 334

334

Examples 334

- 334

334

335

336

337

apache-common lang3 338

65: 339

339

Examples 339

339

340

Getters Setters? 340


66: (java.time. *) 343

Examples 343

343

343

344

344

API Date Time 344

346

2 347

67: JavaScript Nashorn 349

349

349

349

Examples 349

349

, 350

JavaScript 350

351

351

Java JavaScript 351

353

353

68: 355

355

355

355

Examples 355

355

356

358

359

359
(« A & B») 360

361

`T`,`? T` `? T` 362

364

364

364

364

1 365

: 365

366

366

366

Generics 368

( ) 369

Generics 371

, 372

69: Java 374

374

374

375

Examples 375

375

376

377

377

378

Javadocs 379

379

380

70: 382

382

Examples 382
382

Loader 382

.class 384

71: 386

386

Examples 386

SealedObject (javax.crypto.SealedObject) 386

SignedObject (java.security.SignedObject) 387

72: 388

Examples 388

Bytecode? 388

? 388

, ,? 388

/ -? 388

! 389

jar ASM 389

ClassNode 392

jar 392

Javassist Basic 393

73: 395

395

395

Examples 395

395

396

74: Dequeue 398

398

398

Examples 398

Deque 398

Deque 399
399

Deque 399

75: Java Native 400

400

400

Examples 400

C ++ Java 400

Java 401

C ++ 401

402

Java C ++ (callback) 402

Java 403

C ++ 403

403

404

404

405

76: JVM 406

406

Examples 406

, (Heap 1.0) 406

JVMTI 408

Agent_OnLoad 409

77: 410

410

410

Examples 410

410

411

412

413

415
417

418

418

419

419

420

420

421

421

78: 423

423

423

Examples 423

try-catch 423

catch 424

424

425

426

427

428

try-with-resources 429

? 429

try-with-resource 430

try-with-resource 430

431

try-with-resource try-catch-finally 431

- 433

- 433

stacktrace 434

435

stacktrace 436
InterruptedException 437

Java - 438

439

440

442

try catch 444

445

445

446

446

446

try-finally try-catch-finally 447

447

,, 448

'throws' 449

? 449

450

79: , 451

451

451

Examples 451

- 451

ThreadPoolExecutor 452

- Callable 453

, 454

454

455

455

455

() vs execute () 456

458

ExecutorService 460
ExecutorService 462

464

80: ThreadPoolExecutor MultiThreaded. 466

466

Examples 466

, 466

, 468

Inline Lambdas 471

81: Java 473

473

473

Examples 473

javascript -scripting nashorn 473

82: static 476

476

Examples 476

static 476

static 477

477

83: 479

479

479

Examples 479

Iterable in for 479

479

Iterable. 480

481

84: 483

483

Examples 483

483

/ 483
AM / PM 484

484

85: Enum 485

485

Examples 485

Enum 485

86: 487

487

487

Examples 488

488

488

Java 8 489

492

492

, 493

<X, Y> <Y, Z> <X, Z> 494

, 494

495

495

498

HashMap 499

500

500

87: - Java 503

503

Examples 503

getClass () Object 503

88: EnumSet 504

504

Examples 504
Enum 504

89: java.util.Objects 505

Examples 505

505

505

505

Objects.nonNull () api 505

90: 506

506

506

506

Examples 507

Date 507

Date 508

, 508

, , compareTo equals 508

isBefore, isAfter, compareTo equals 509

Java 8 510

Java 8 510

String 511

512

512

date to Date 513

513

Java 8 LocalDate LocalDateTime 514

java.util.Date 515

java.util.Date java.sql.Date 516

516

91: 518

518

518
518

Examples 519

519

: 519

XML 522

92: 524

524

524

Examples 524

524

524

525

526

529

530

, . 530

93: 535

535

Examples 535

535

Clonable 536

536

, 537

538

94: 540

Examples 540

, UTF-8 540

UTF-8 540

UTF-8 541

95: 542

542

542
Examples 543

ArrayList 543

544

544

Java 544

Google Guava 544

545

Java 545

545

Google Guava 545

546

546

547

for «»: 547

for Throws Exception: 547

547

Iterator 547

549

, 549

« » 549

549

removeIf 550

550

551

551

552

552

553

553

Iterator. 554

Iterable Iterator for-each. 555


Pitfall: 557

557

subList (int fromIndex, int toIndex) 557

subSet (fromIndex, toIndex) 558

MapMapMap (fromKey, toKey) 558

96: Java - «java» «javaw» 559

559

559

Examples 559

JAR 559

Java «» 560

HelloWorld 560

560

561

JavaFX 561

«java» 562

" " 562

« » 562

« <>" 563

564

Java 564

565

, POSIX 566

Windows 567

Java 567

-D 568

, 568

568

568

97: 570

Examples 570
- 570

98: Java - «javac» 571

571

Examples 571

«javac» - 571

571

572

javac. 573

«javac» 574

574

Java 574

Java 575

575

99: Just in Time (JIT) 577

577

577

Examples 577

577

100: - 581

Examples 581

581

BufferedReader : 581

Scanner : 581

System.console : 582

583

584

585

101: 586

586

586

Examples 586
586

587

588

102: 590

590

Examples 590

, 590

590

591

592

593

593

593

593

594

594

595

595

595

596

596

597

597

598

598

598

103: 599

599

599

Java 599

Examples 600

«locale» 600
Java 600

600

601

601

601

Java ResourceBundle 601

602

104: - 603

603

603

Examples 603

603

603

604

Java lambdas 605

605

- 606

607

() 608

Lambdas 608

608

609

( ) 610

( ) 610

610

610

- 611

611

612

613
`return` , 613

Java -. 615

- 617

617

Lambdas 618

- (-) 619

105: 621

621

621

621

Examples 621

622

622

, 622

623

624

625

Java 626

627

627

628

629

629

630

631

632

, Arrays.asList () 633

634

Java 635

ArrayIndexOutOfBoundsException 636

637
638

638

639

642

642

Object.clone () 642

Arrays.copyOf () 642

System.arraycopy () 643

Arrays.copyOfRange () 643

643

644

ArrayList 644

System.arraycopy 644

Apache Commons Lang 645

645

? 646

647

647

Arrays.binarySearch ( ) 647

Arrays.asList ( ) 648

Stream 648

648

, org.apache.commons 648

, 648

649

651

106: 652

Examples 652

SecurityManager 652

Sandboxing, ClassLoader 652

653
DeniedPermission 654

DenyingPolicy 658

660

107: 662

662

662

662

Examples 662

662

663

LocalTime 663

664

108: 666

666

Examples 666

666

109: 667

667

667

Examples 667

toString () 667

equals () 668

670

hashCode () 671

Arrays.hashCode () 673

- 673

wait () notify () 674

getClass () 676

clone () 677

finalize () 678

679

110: 682
682

682

682

682

682

: 683

Examples 683

683

684

685

? 686

, 686

688

111: 690

690

690

690

Examples 691

691

691

691

112: Java 692

692

Examples 692

692

693

694

694

694

695

695

696
- 696

- 697

697

«volatile» 2 698

699

700

113: 701

701

Examples 701

701

703

703

705

705

706

strictfp 706

114: 708

708

708

Examples 708

708

115: 710

Examples 710

HashSet 710

710

HashSet - 710

LinkedHashSet - 710

TreeSet - compareTo() Comparator 711

711

712

713
Set 714

116: 715

715

715

715

Examples 715

715

717

«final» 718

718

719

720

720

721

722

723

724

725

: «Is-a» vs «Has-a» 728

731

117: Java 733

Examples 733

733

733

Java 734

118: 737

737

Examples 737

. 737

738

, , 739

119: 743
743

743

Examples 743

743

744

mutable refs 744

? 745

120: 746

746

746

Examples 746

, 746

747

, 748

748

749

, 749

749

FlatMap 750

121: - 752

752

Examples 752

752

752

753

753

753

753

754

, 754

754
MIME 755

755

755

122: 757

757

757

757

Examples 757

GWT ToolBase 757

758

759

759

«» , , 759

123: Java 761

761

Examples 761

Pitfall: == , Integer 761

Pitfall: 762

Pitfall: 763

Pitfall: == 765

Pitfall: . 766

Pitfall: 768

768

769

, 770

771

Pitfall: 771

Pitfall: , String 772

124: 774

774

Examples 774
Enum Singleton 774

774

Singleton Enum ( ) 775

| 776

(singleton ) 776

125: 780

780

780

Examples 780

(+) 780

781

(+, -, *, /,%) 782

, 783

784

785

785

INF NAN 786

(==,! =) 786

Numeric == != 787

Boolean == != 787

Reference == != 788

NaN 789

Increment / Decrement (++ / -) 789

(? :) 790

790

791

(~, &, |, ^) 792

. 792

793

(=, + =, - =, * =, / =,% =, << =, >> =, >>> =, & =, | = ^ =) 794

(&& ||) 796

- && 797
. &&, 797

(<<, >> >>>) 798

(->) 799

(<, <=,>,> =) 799

126: Java 801

801

Examples 801

801

OverFlow UnderFlow 803

804

IEEE 805

127: 807

807

Examples 807

JMH 807

128: 810

810

Examples 810

/ Else If / Else Control 810

811

812

do ... while Loop 812

813

814

switch 814

816

817

... ... 817

/ 818

Java 818

129: 820

820
820

Examples 820

- 820

130: XML XPath 823

823

Examples 823

NodeList XML- 823

XPath XML 824

XPath XML 824

131: Deques 826

Examples 826

PriorityQueue 826

LinkedList FIFO 826

827

? 827

API 827

827

BlockingQueue 828

830

Deque 830

831

831

132: Java - Nulls NullPointerException 833

833

Examples 834

Pitfall - NullPointerException 834

Pitfall - null 835

Pitfall - « » 836

«a» «b» ? 836

null ? 836

« » «»? 837
( ), « »? 837

/ ? 837

837

Pitfall - null 837

Pitfall - , - 838

Pitfall - « Yoda», NullPointerException 839

133: Java - 841

Examples 841

Pitfall: wait () / notify () 841

«» 841

« » 841

/ 842

Pitfall - 'java.lang.Thread' 842

Pitfall - . 843

Pitfall - 844

Pitfall: . 846

? 846

? 847

? 848

? 848

? 849

134: Java - 851

851

851

Examples 851

Pitfall - 851

851

Pitfall - 852

Pitfall - «» 853

Pitfall - (String) 854

Pitfall - Calling System.gc () 854

Pitfall - 856
Pitfall - 857

Pitfall - size () , , 857

Pitfall - 858

858

match (), find () 859

860

860

Pitfall - , ==, - 862

862

«intern ()» 862

863

- 863

863

Pitfall - / 864

, ? 865

? 865

? 866

Java? 867

135: 868

868

868

Examples 868

868

868

136: () 870

870

870

Examples 870

870

- 871

ThreadLocal 873

CountDownLatch 873
875

877

878

880

/ / 880

java.lang.Thread 882

/ 884

/ 887

/ 889

890

891

`int`, Threadpool 892

, , 893

894

896

137: Fork / Join 898

Examples 898

/ Java 898

138: 900

900

Examples 900

900

900

, 902

ConcurrentHashMap 902

139: 904

904

904

904

904

904

Examples 905
905

908

910

911

Enum 912

913

914

915

Enum 915

915

Singleton 916

Enum () 917

917

name() 917

toString() 918

: 918

918

Enum 918

920

921

Enum 922

140: 924

924

924

Examples 924

924

926

927

928

930

141: 934

Examples 934
934

PreferenceChangeEvent 934

NodeChangeEvent 934

935

936

936

937

938

939

939

939

142: 941

Examples 941

String 941

/ 941

/ Base64 942

943

`String` ` InputStream` 944

String . 944

143: 946

946

Examples 946

946

946

946

947

, instanceof 947

144: 948

948

948

948

Examples 949
Int 949

949

950

951

- 951

951

953

953

954

- 955

956

956

957

145: 959

959

Examples 959

( Java <1.5) 959

ProcessBuilder 959

960

ch.vorburger.exec 960

Pitfall: Runtime.exec, Process ProcessBuilder 961

961

, 962

962

146: 964

964

964

Examples 964

964

JAR 965

965

966
966

966

classpath: 967

967

147: 969

969

969

Examples 970

- javap 970

148: Java 977

977

977

Examples 977

JAR 977

JAR, WAR EAR 978

JAR WAR Maven 978

JAR, WAR EAR Ant 978

JAR, WAR EAR IDE 979

JAR, WAR EAR jar . 979

Java Web Start 979

979

JNLP 980

- 980

- 980

Web Start 981

UberJAR 981

UberJAR «jar» 981

UberJAR Maven 981

UberJARs 982

149: 983

983
Examples 983

983

983

150: Java- 984

984

Examples 984

URLClassLoader 984

151: 988

988

988

988

988

988

988

988

Examples 989

989

990

990

. 991

991

991

152: 993

993

993

993

993

Java Tail-call 993

Examples 993

993

N- 994
1 N 994

N- 995

995

995

996

StackOverflowError & recursion to loop 997

997

997

997

Java 999

Java () 1000

153: ( ) 1001

1001

1001

Examples 1002

1002

1002

JAR 1003

1003

1003

1003

get 1004

154: 1005

1005

Examples 1005

1005

155: 1006

1006

Examples 1006

- 1006

1006

156: 1009
1009

Examples 1009

Java 1009

Gson 1011

Jackson 2 1011

1012

serialVersionUID 1015

1015

1016

JSON 1016

157: 1019

1019

Examples 1019

1019

: 1019

: 1019

: 1019

1020

- 1020

TrustStore KeyStore InputStream 1021

- - 1022

/ UDP () 1023

Multicasting 1024

SSL ( ) 1026

1026

1027

158: 1028

1028

1028

1028

Examples 1028

1028
1028

1029

1029

, 1030

int 1032

1032

159: Java 1033

1033

Examples 1033

1033

1033

1034

, 1034

1035

1035

PrintJobEvent pje 1036

1036

160: 1038

1038

Examples 1038

1038

1039

1039

BufferedImage 1041

BufferedImage 1042

BufferedImage 1043

BufferedImage 1043

161: Java 1045

Examples 1045

POJO JSON 1045

162: Java 1046

1046
1046

Examples 1046

- TCP 1046

163: 1050

1050

1050

1050

Examples 1050

1050

1052

1053

1055

B, A 1055

1056

1056

, ArrayList 1056

1057

1058

1058

, - 1058

, List 1059

1059

ArrayList 1059

AttributeList 1060

CopyOnWriteArrayList 1060

LinkedList 1060

RoleList 1060

RoleUnresolvedList 1060

1060

1060

164: SET 1062

1062
Examples 1062

1062

165: C ++ 1063

1063

1063

, # 1063

1063

C ++ 1063

1063

1063

C ++ 1063

1063

1064

C ++ 1064

1064

1064

1064

/ 1064

1064

1065

1065

C ++ 1066

1066

java.lang.Object 1066

Java C ++ 1066

- Java Collections 1066

- C ++ 1066

1066

Examples 1067

1067
C ++ 1067

Java 1067

, 1067

1067

C ++ 1068

1068

1068

C ++ 1068

1068

1068

C ++ 1068

1069

1069

C ++ ( ) 1069

Java ( ) 1069

1070

1070

C ++ 1070

Java 1070

1070

1070

C ++ 1070

1071

1071

C ++ 1071

1071

1071

C ++ 1071

1071

166: 1072
1072

1072

Examples 1072

Comparable 1072

Lambda 1075

1076

1076

1076

() () 1076

1078

1078

167: 1079

1079

Examples 1079

1079

168: Oracle 1082

1082

1082

Examples 1082

1082

1082

, 1082

1082

1083

1083

1083

1083

Java 1083

1084

1084
1084

1084

1084

1085

1085

1085

1086

1086

1087

1088

1088

1088

1088

1088

1089

- 1089

1090

1090

1090

1091

169: 1092

1092

Examples 1092

StringTokenizer 1092

StringTokenizer Split by comma ',' 1092

170: 1093

1093

1093

Examples 1094

1094

== 1094
switch 1095

1095

1095

1095

1096

1098

1098

1099

n- 1099

1100

toString () 1100

1101

1103

1104

1104

StringBuilders 1105

1106

1107

: 1107

: 1107

Regex 1107

: 1107

: 1107

1108

1108

1110

171: 1111

Examples 1111

Super 1111

1111

1112
1112

172: 1114

1114

1114

1114

1114

Examples 1114

Unit Testing? 1114

1116

1116

1116

173: 1117

Examples 1117

1117

174: 1119

Examples 1119

1119

1119

175: (RMI) 1120

1120

Examples 1120

Client-Server: JVM 1120

: «» 1122

1122

1122

1123

RMI Client Server 1126

1126

1127

1128

176: Java 1129


1129

Examples 1129

1129

1129

GC 1130

1130

C ++ - 1130

Java - 1130

, 1131

1131

, 1132

Java 1133

1133

1134

177: Java ( ) 1135

1135

Examples 1135

% PATH% % JAVA_HOME% Windows 1135

: 1135

1135

1136

Java SE 1136

Java 1136

Java 1137

Java JDK Linux 1138

1138

RPM Oracle Java. 1139

Java JDK JRE Windows 1139

Java JDK macOS 1140

Java Linux 1141

1141

Arch 1142
1142

1142

Linux 1142

oracle java Linux tar 1144

: 1144

178: 1145

1145

1145

1145

Examples 1145

1145

179: - 1146

1146

Examples 1146

[] 1146

1146

[] 1146

Stream vs Writer / Reader API 1147

1148

1148

1149

java.io.File Java 7 NIO (java.nio.file.Path) 1149

1149

1150

/ 1150

, , 1150

OutputStream 1150

1151

1151

/ FileInputStream / FileOutputStream 1152

1153
1153

InputStream OutputStream 1154

1154

1155

BufferedInputStream 1156

Channel Buffer 1157

PrintStream 1157

, 1158

1158

/ 1158

ZIP- 1159

1159

1159

180: JAR 1161

1161

Examples 1161

Jar 1161

1161

URL Jar 1162

181: JVM 1164

1164

Examples 1164

-XXaggressive 1164

-XXallocClearChunks 1164

-XXallocClearChunkSize 1164

-XXcallProfiling 1165

-XXdisableFatSpin 1165

-XXdisableGCHeuristics 1165

-XXdumpSize 1165

-XXexitOnOutOfMemory 1166

182: 1167

1167
Examples 1167

Java Runtime Library 1167

183: - 1170

1170

Examples 1170

- 1170

184: 1171

1171

Examples 1171

BufferedReader 1171

1171

BufferedReader 1171

BufferedReader 1171

BufferedReader.readLine () 1171

: 1172

StringWriter 1172

185: RSA 1174

Examples 1174

, OAEP GCM 1174

1179
Около
You can share this PDF with anyone you feel could benefit from it, downloaded the latest version
from: java-language

It is an unofficial and free Java Language ebook created for educational purposes. All the content
is extracted from Stack Overflow Documentation, which is written by many hardworking individuals
at Stack Overflow. It is neither affiliated with Stack Overflow nor official Java Language.

The content is released under Creative Commons BY-SA, and the list of contributors to each
chapter are provided in the credits section at the end of this book. Images may be copyright of
their respective owners unless otherwise specified. All trademarks and registered trademarks are
the property of their respective company owners.

Use the content presented in this book at your own risk; it is not guaranteed to be correct nor
accurate, please send your feedback and corrections to [email protected]

https://riptutorial.com/ru/home 1
глава 1: Начало работы с Java Language
замечания
Язык программирования Java ...

• Универсальный : он предназначен для использования для написания программного


обеспечения в самых разных областях приложений и не имеет специализированных
функций для любого конкретного домена.

• Class-based : его структура объектов определена в классах. У экземпляров классов


всегда есть те поля и методы, которые указаны в их определениях классов (см.
Классы и объекты ). Это противоречит неклассическим языкам, таким как JavaScript.

• Статически типизированный : компилятор проверяет во время компиляции, что типы


переменных соблюдаются. Например, если метод ожидает аргумент типа String , этот
аргумент на самом деле должен быть строкой при вызове метода.

• Объектно-ориентированная : большинство вещей в программе Java являются


экземплярами класса, то есть пучками состояний (полей) и поведения (методы,
которые работают с данными и образуют интерфейс объекта для внешнего мира).

• Portable : он может быть скомпилирован на любой платформе с помощью javac и


полученные файлы классов могут запускаться на любой платформе с JVM.

Java предназначен для того, чтобы позволить разработчикам приложений «писать один
раз, работать где угодно» (WORA), что означает, что скомпилированный Java-код может
работать на всех платформах, поддерживающих Java, без необходимости
перекомпиляции.

Java-код скомпилирован в байт-код ( .class ), которые, в свою очередь, интерпретируются


виртуальной машиной Java (JVM). Теоретически байт-код, созданный одним компилятором
Java, должен работать одинаково на любом JVM, даже на другом компьютере. JVM может
(и в реальных программах) выбирать для компиляции в собственные машинные команды
части байт-кода, которые выполняются часто. Это называется компиляцией «точно в срок»
(JIT) ».

Java-версии и версии
Существует три «издания» Java, определенные Sun / Oracle:

• Java Standard Edition (SE) - это издание, предназначенное для общего использования.
• Java Enterprise Edition (EE) добавляет ряд возможностей для создания сервисов

https://riptutorial.com/ru/home 2
уровня предприятия на Java. Java EE рассматривается отдельно .
• Java Micro Edition (ME) основана на подмножестве Java SE и предназначена для
использования на небольших устройствах с ограниченными ресурсами.

Существует отдельная тема для выпусков Java SE / EE / ME .

Каждое издание имеет несколько версий. Ниже перечислены версии Java SE.

Установка Java
Существует отдельная тема по установке Java (стандартная версия) .

Компиляция и запуск Java-программ


Существуют отдельные темы:

• Компиляция исходного кода Java


• Развертывание Java, включая создание JAR-файлов
• Запуск приложений Java
• Путь Класса

Что дальше?
Вот ссылки на темы, чтобы продолжить изучение и понимание языка программирования
Java. Эти темы - основы программирования Java, чтобы вы начали.

• Примитивные типы данных в Java


• Операторы в Java
• Строки в Java
• Основные элементы управления в Java
• Классы и объекты в Java
• Массивы в Java
• Стандарты кода Java

тестирование
Хотя Java не имеет поддержки для тестирования в стандартной библиотеке, существуют
сторонние библиотеки, которые предназначены для поддержки тестирования. Две
наиболее популярные библиотеки для тестирования модулей:

https://riptutorial.com/ru/home 3
• JUnit ( официальный сайт )
• TestNG ( официальный сайт )

Другой
• Шаблоны проектирования для Java описаны в шаблонах проектирования .
• Программирование для Android распространяется на Android .
• Технологии Java Enterprise Edition описаны в Java EE .
• Технологии Oracle JavaFX рассматриваются в JavaFX .
1. В разделе « Версии » дата окончания срока службы (бесплатно) заключается в том, что Oracle перестанет
публиковать дальнейшие обновления Java SE на своих общедоступных сайтах загрузки. Клиенты, которым
требуется постоянный доступ к критическим исправлениям ошибок и исправлениям безопасности, а также
общее обслуживание Java SE, могут получить долгосрочную поддержку через поддержку Oracle Java SE .

Версии

Окончание срока службы Дата


Версия Java SE Кодовое имя
(бесплатно 1 ) выхода

Java SE 9 (ранний
Никто будущее 2017-07-27
доступ)

Java SE 8 паук будущее 2014-03-18

Java SE 7 дельфин 2015-04-14 2011-07-28

Java SE 6 мустанг 2013-04-16 2006-12-23

Java SE 5 тигр 2009-11-04 2004-10-04

Java SE 1.4 Мерлин до 2009-11-04 2002-02-06

Java SE 1.3 Пустельга до 2009-11-04 2000-05-08

Детская
Java SE 1.2 до 2009-11-04 1998-12-08
площадка

Java SE 1.1 Никто до 2009-11-04 1997-02-19

Java SE 1.0 дуб до 2009-11-04 1996-01-21

Examples

https://riptutorial.com/ru/home 4
Создание первой программы Java

Создайте новый файл в текстовом редакторе или в IDE с именем HelloWorld.java . Затем
вставьте этот блок кода в файл и сохраните:

public class HelloWorld {


public static void main(String[] args) {
System.out.println("Hello, World!");
}
}

Запуск в прямом эфире на Ideone

Примечание. Если Java распознает это как public class (а не выдает ошибку времени
компиляции ), имя файла должно совпадать с именем класса ( HelloWorld в этом примере) с
расширением .java . Перед этим также должен быть модификатор public доступа.

Соглашения об именах рекомендуют, чтобы классы Java начинались с символа верхнего


регистра и находились в формате case camel (в котором первая буква каждого слова
заглавная). Эти соглашения рекомендуются против знаков подчеркивания ( _ ) и доллара (
$ ).

Чтобы скомпилировать, откройте окно терминала и перейдите в каталог HelloWorld.java :

cd /path/to/containing/folder/

Примечание: cd - это команда терминала для изменения каталога.

Введите javac а затем имя файла и расширение следующим образом:

$ javac HelloWorld.java

Общеизвестно, что ошибка 'javac' is not recognized as an internal or external command,


operable program or batch file. даже если вы установили JDK и сможете запускать программу
из IDE ex. eclipse и т. д. Так как путь по умолчанию не добавляется в среду.

В случае, если вы получите это на окнах, чтобы решить проблему, сначала попробуйте
перейти на ваш путь javac.exe , скорее всего, это ваш C:\Program Files\Java\jdk(version
number)\bin . Затем попробуйте запустить его ниже.

$ C:\Program Files\Java\jdk(version number)\bin\javac HelloWorld.java

Раньше, когда мы javac он был таким же, как и команда выше. Только в этом случае ваша OS
знала, где находится javac . Итак, давайте расскажем об этом сейчас, поэтому вам не
нужно вводить весь путь каждый раз. Нам нужно добавить это к нашей PATH

Чтобы изменить PATH среды PATH в Windows XP / Vista / 7/8/10:

https://riptutorial.com/ru/home 5
• Панель управления ⇒ Система ⇒ Расширенные настройки системы
• Переключиться на вкладку «Дополнительно» ⇒ Переменные среды
• В «Системные переменные» прокрутите вниз, чтобы выбрать «ПУТЬ» ⇒ Изменить

Вы не можете отменить это, поэтому будьте осторожны. Сначала скопируйте


существующий путь в блокнот. Затем, чтобы получить точную PATH для вашего javac
просмотрите вручную папку, в которой находится javac и щелкните по адресной строке, а
затем скопируйте ее. Он должен выглядеть примерно так c:\Program
Files\Java\jdk1.8.0_xx\bin

В поле «Variable value» вставьте этот IN FRONT из всех существующих каталогов, за


которым следует точка с запятой (;). НЕ УДАЛЯЙТЕ любые существующие записи.

Variable name : PATH


Variable value : c:\Program Files\Java\jdk1.8.0_xx\bin;[Existing Entries...]

Теперь это должно решить.

Для Linux-систем попробуйте здесь .

Примечание. Команда javac вызывает компилятор Java.

Затем компилятор сгенерирует файл байт-кода HelloWorld.class который может быть


запущен на виртуальной машине Java (JVM) . Компилятор языка программирования Java,
javac , читает исходные файлы, написанные на языке программирования Java, и
компилирует их в файлы классов bytecode . При желании компилятор также может
обрабатывать аннотации, найденные в исходных и классных файлах, с помощью API
Pluggable Annotation Processing. Компилятор является инструментом командной строки, но
также может быть вызван с использованием Java Compiler API.

Чтобы запустить вашу программу, введите java а затем имя класса, которое содержит main
метод ( HelloWorld в нашем примере). Обратите внимание, что .class опущен:

$ java HelloWorld

Примечание. Команда java запускает приложение Java.

Это будет выводиться на консоль:

Привет, мир!

Вы успешно закодировали и создали свою первую Java-программу!

Примечание. Чтобы распознавать Java-команды ( java , javac и т. Д.), Вам необходимо


убедиться:

• Установлен JDK (например, Oracle , OpenJDK и другие источники)

https://riptutorial.com/ru/home 6
• Ваши переменные среды правильно настроены

Вам нужно будет использовать компилятор ( javac ) и исполнитель ( java ),


предоставленный вашей JVM. Чтобы узнать, какие версии вы установили, введите java -
version и javac -version в командной строке. Номер версии вашей программы будет
напечатан в терминале (например, 1.8.0_73 ).

Более пристальный взгляд на программу


Hello World
Программа Hello World содержит один файл, который состоит из определения класса
HelloWorld , main метода и оператора внутри main метода.

public class HelloWorld {

Ключевое слово class начинает определение класса для класса с именем HelloWorld .
Каждое приложение Java содержит хотя бы одно определение класса ( дополнительная
информация о классах ).

public static void main(String[] args) {

Это метод точки входа (определяемый его именем и сигнатурой public static void
main(String[]) ), из которого JVM может запускать вашу программу. Каждая программа Java
должна иметь один. Это:

• public: это означает, что метод может быть вызван из любой точки мира извне
программы. См. « Видимость» для получения дополнительной информации об этом.
• static : означает, что он существует и может выполняться сам по себе (на уровне
класса без создания объекта).
• void : означает, что он не возвращает значение. Примечание. Это не похоже на C и C
++, где ожидается код возврата, такой как int (путь Java - System.exit() ).

Этот основной метод позволяет:

• Массив (обычно называемый args ) String s передается как аргументы основной


функции (например, из аргументов командной строки ).

Почти все это требуется для метода точки входа Java.

Необязательные детали:

• Имя args - это имя переменной, поэтому его можно назвать чем угодно, хотя обычно
его называют args .

https://riptutorial.com/ru/home 7
• Является ли его тип параметра массивом ( String[] args ) или Varargs ( String... args ),
не имеет значения, потому что массивы могут быть переданы в varargs.

Примечание. В одном приложении может быть несколько классов, содержащих метод


точки входа ( main ). Точка входа приложения определяется именем класса, переданным в
качестве аргумента в команду java .

Внутри основного метода мы видим следующее утверждение:

System.out.println("Hello, World!");

Давайте разберем эту инструкцию по элементам:

Элемент Цель

это означает, что последующее выражение вызовет класс System из пакета


System
java.lang .

это «точечный оператор». Операторы точек предоставляют вам доступ к


членам классов 1 ; т.е. его поля (переменные) и его методы. В этом случае
.
этот оператор точки позволяет ссылаться на out статического поля в
System класса.

это имя статического поля типа PrintStream внутри класса System


out
содержащего стандартные функции вывода.

это еще один оператор точки. Этот оператор точки обеспечивает доступ к
.
методу println в переменной out .

это имя метода в классе PrintStream. Этот метод, в частности, печатает


println
содержимое параметров в консоли и вставляет новую строку после.

эта скобка указывает, что к способу обращается (а не к полю) и начинает


(
параметры передаются в метод println .

"Hello, это строковый литерал, который передается как параметр, в метод println
World!"
. Двойные кавычки на каждом конце ограничивают текст как String.

) эта скобка означает закрытие параметров, передаваемых в метод println .

; эта точка с запятой знаменует конец утверждения.

Примечание. Каждый оператор в Java должен заканчиваться точкой с запятой ( ; ).

Тело метода и тело класса затем закрываются.

https://riptutorial.com/ru/home 8
} // end of main function scope
} // end of class HelloWorld scope

Вот еще один пример, демонстрирующий парадигму ОО. Давайте моделируем футбольную
команду с одним (да, одним!) Участником. Их может быть больше, но мы обсудим это, когда
мы перейдем к массивам.

Сначала давайте определим наш класс Team :

public class Team {


Member member;
public Team(Member member) { // who is in this Team?
this.member = member; // one 'member' is in this Team!
}
}

Теперь давайте определим наш Member класса:

class Member {
private String name;
private String type;
private int level; // note the data type here
private int rank; // note the data type here as well

public Member(String name, String type, int level, int rank) {


this.name = name;
this.type = type;
this.level = level;
this.rank = rank;
}
}

Почему мы здесь используем private ? Ну, если кто-то хочет узнать ваше имя, они должны
попросить вас прямо, вместо того, чтобы влезть в карман и вытащить карту социального
страхования. Это private делает что-то вроде этого: оно предотвращает доступ внешних
объектов к вашим переменным. Вы можете возвращать только private членов через
функции getter (показано ниже).

Положив все это вместе и добавив геттеры и основной метод, как обсуждалось ранее, мы
имеем:

public class Team {


Member member;
public Team(Member member) {
this.member = member;
}

// here's our main method


public static void main(String[] args) {
Member myMember = new Member("Aurieel", "light", 10, 1);
Team myTeam = new Team(myMember);
System.out.println(myTeam.member.getName());

https://riptutorial.com/ru/home 9
System.out.println(myTeam.member.getType());
System.out.println(myTeam.member.getLevel());
System.out.println(myTeam.member.getRank());
}
}

class Member {
private String name;
private String type;
private int level;
private int rank;

public Member(String name, String type, int level, int rank) {


this.name = name;
this.type = type;
this.level = level;
this.rank = rank;
}

/* let's define our getter functions here */


public String getName() { // what is your name?
return this.name; // my name is ...
}

public String getType() { // what is your type?


return this.type; // my type is ...
}

public int getLevel() { // what is your level?


return this.level; // my level is ...
}

public int getRank() { // what is your rank?


return this.rank; // my rank is
}
}

Выход:

Aurieel
light
10
1

Запуск на идеон

Еще раз, main метод внутри класса Test является точкой входа в нашу программу. Без main
метода мы не можем сообщить виртуальной машине Java (JVM), откуда начать выполнение
программы.

1 - Поскольку класс HelloWorld мало HelloWorld классом System , он может получать доступ только к public
данным.

Прочитайте Начало работы с Java Language онлайн: https://riptutorial.com/ru/java/topic/84/


начало-работы-с-java-language

https://riptutorial.com/ru/home 10
глава 2: 2D-графика в Java
Вступление
Графика - это визуальные изображения или рисунки на какой-либо поверхности, такие как
стена, холст, экран, бумага или камень, чтобы сообщать, иллюстрировать или развлекать.
Он включает в себя: графическое представление данных, как при автоматизированном
проектировании и производстве, в наборе и графике, а также в учебном и
развлекательном программном обеспечении. Изображения, созданные компьютером,
называются компьютерной графикой.

Java 2D API является мощным и сложным. Существует несколько способов сделать 2D-
графику на Java.

Examples

Пример 1: Рисование и заливка прямоугольника с использованием Java

Это пример, который печатает прямоугольник и заполняет цвет в прямоугольнике.

https://i.stack.imgur.com/dlC5v.jpg

Большинство методов класса Graphics можно разделить на две основные группы:

1. Методы рисования и заполнения, позволяющие отображать основные фигуры, текст


и изображения

https://riptutorial.com/ru/home 11
2. Методы настройки атрибутов, которые влияют на то, как отображается этот рисунок
и заполнение

Пример кода. Давайте начнем с небольшого примера рисования прямоугольника и


заполнения цвета в нем. Там мы объявляем два класса, один класс - MyPanel, а другой -
Test. В классе MyPanel мы используем drawRect () и fillRect () mathods для рисования
прямоугольника и заполнения цвета в нем. Мы устанавливаем цвет методом setColor
(Color.blue). Во втором классе мы тестируем нашу графику, которая является тестовым
классом, мы создаем фрейм и помещаем MyPanel с p = новым объектом MyPanel () в нем.
При запуске Test Class мы видим прямоугольник и синий цветный прямоугольник.

Первый класс: MyPanel

import javax.swing.*;
import java.awt.*;
// MyPanel extends JPanel, which will eventually be placed in a JFrame
public class MyPanel extends JPanel {
// custom painting is performed by the paintComponent method
@Override
public void paintComponent(Graphics g){
// clear the previous painting
super.paintComponent(g);
// cast Graphics to Graphics2D
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.red); // sets Graphics2D color
// draw the rectangle
g2.drawRect(0,0,100,100); // drawRect(x-position, y-position, width, height)
g2.setColor(Color.blue);
g2.fillRect(200,0,100,100); // fill new rectangle with color blue
}
}

Второй класс: тест

import javax.swing.;
import java.awt.;
public class Test { //the Class by which we display our rectangle
JFrame f;
MyPanel p;
public Test(){
f = new JFrame();
// get the content area of Panel.
Container c = f.getContentPane();
// set the LayoutManager
c.setLayout(new BorderLayout());
p = new MyPanel();
// add MyPanel object into container
c.add(p);
// set the size of the JFrame
f.setSize(400,400);
// make the JFrame visible
f.setVisible(true);
// sets close behavior; EXIT_ON_CLOSE invokes System.exit(0) on closing the JFrame
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

https://riptutorial.com/ru/home 12
public static void main(String args[ ]){
Test t = new Test();
}
}

Дополнительные пояснения относительно макета границы:


https://docs.oracle.com/javase/tutorial/uiswing/layout/border.html

paintComponent ()

• Это основной метод рисования


• По умолчанию он сначала рисует фон
• После этого он выполняет обычную роспись (круг рисования, прямоугольники и т. Д.),

Graphic2D относится к классу Graphic2D

Примечание . Java 2D API позволяет вам легко выполнять следующие задачи:

• Рисуйте линии, прямоугольники и любую другую геометрическую форму.


• Заполните эти фигуры сплошными цветами или градиентами и текстурами.
• Нарисуйте текст с опциями для тонкого контроля над шрифтом и процессом
рендеринга.
• Нарисуйте изображения, опционально применяя операции фильтрации.
• Применяйте операции, такие как компоновка и преобразование во время любой из
вышеперечисленных операций рендеринга.

Пример 2: Обивка для рисования и наполнения

import javax.swing.*;
import java.awt.*;

public class MyPanel extends JPanel {


@Override
public void paintComponent(Graphics g){
// clear the previous painting
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setColor(Color.blue);
g2.drawOval(0, 0, 20,20);
g2.fillOval(50,50,20,20);
}
}

g2.drawOval (int x, int y, int height, int width);


Этот метод будет рисовать овал в указанных положениях x и y с заданной высотой и
шириной.

g2.fillOval (int x, int y, int height, int width); Этот метод будет заполнять овал в указанных
положениях x и y с заданной высотой и шириной.

https://riptutorial.com/ru/home 13
Прочитайте 2D-графика в Java онлайн: https://riptutorial.com/ru/java/topic/10127/2d-графика-
в-java

https://riptutorial.com/ru/home 14
глава 3: Apache Commons Lang
Examples

Внедрить метод equals ()

Чтобы реализовать метод equals объекта легко, вы можете использовать класс


EqualsBuilder .

Выбор полей:

@Override
public boolean equals(Object obj) {

if(!(obj instanceof MyClass)) {


return false;
}
MyClass theOther = (MyClass) obj;

EqualsBuilder builder = new EqualsBuilder();


builder.append(field1, theOther.field1);
builder.append(field2, theOther.field2);
builder.append(field3, theOther.field3);

return builder.isEquals();
}

Использование отражения:

@Override
public boolean equals(Object obj) {
return EqualsBuilder.reflectionEquals(this, obj, false);
}

логический параметр указывает, должны ли равны проверять переходные поля.

Используя отражение, избегая некоторых полей:

@Override
public boolean equals(Object obj) {
return EqualsBuilder.reflectionEquals(this, obj, "field1", "field2");
}

Внедрить метод hashCode ()

Чтобы реализовать метод hashCode объекта легко, вы можете использовать класс


HashCodeBuilder .

Выбор полей:

https://riptutorial.com/ru/home 15
@Override
public int hashCode() {

HashCodeBuilder builder = new HashCodeBuilder();


builder.append(field1);
builder.append(field2);
builder.append(field3);

return builder.hashCode();
}

Использование отражения:

@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this, false);
}

boolean указывает, следует ли использовать преходящие поля.

Используя отражение, избегая некоторых полей:

@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this, "field1", "field2");
}

Внедрить метод toString ()

Чтобы реализовать метод toString объекта легко, вы можете использовать класс


ToStringBuilder .

Выбор полей:

@Override
public String toString() {

ToStringBuilder builder = new ToStringBuilder(this);


builder.append(field1);
builder.append(field2);
builder.append(field3);

return builder.toString();
}

Пример результата:

ar.com.jonat.lang.MyClass@dd7123[<null>,0,false]

Явное указание имен для полей:

@Override

https://riptutorial.com/ru/home 16
public String toString() {

ToStringBuilder builder = new ToStringBuilder(this);


builder.append("field1",field1);
builder.append("field2",field2);
builder.append("field3",field3);

return builder.toString();
}

Пример результата:

ar.com.jonat.lang.MyClass@dd7404[field1=<null>,field2=0,field3=false]

Вы можете изменить стиль с помощью параметра:

@Override
public String toString() {

ToStringBuilder builder = new ToStringBuilder(this,


ToStringStyle.MULTI_LINE_STYLE);
builder.append("field1", field1);
builder.append("field2", field2);
builder.append("field3", field3);

return builder.toString();
}

Пример результата:

ar.com.bna.lang.MyClass@ebbf5c[
field1=<null>
field2=0
field3=false
]

Есть несколько стилей, например JSON, no Classname, short и т. Д. ...

Через отражение:

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}

Вы также можете указать стиль:

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
}

Прочитайте Apache Commons Lang онлайн: https://riptutorial.com/ru/java/topic/3338/apache-

https://riptutorial.com/ru/home 17
commons-lang

https://riptutorial.com/ru/home 18
глава 4: API Reflection
Вступление
Отражение обычно используется программами, которые требуют возможности
исследовать или модифицировать поведение среды выполнения приложений, запущенных
в JVM. Java Reflection API используется для этой цели, где он позволяет проверять классы,
интерфейсы, поля и методы во время выполнения, не зная их имена во время компиляции.
А также позволяет создавать новые объекты и вызывать методы с использованием
отражения.

замечания

Спектакль
Имейте в виду, что отражение может снизить производительность, использовать его
только тогда, когда ваша задача не может быть выполнена без отражения.

Из учебника Java API Reflection :

Поскольку отражение включает типы, которые динамически разрешены,


некоторые оптимизации виртуальной машины Java не могут быть выполнены.
Следовательно, рефлексивные операции имеют более низкую
производительность, чем их неотражающие аналоги, и их следует избегать в
разделах кода, которые часто называются приложениями, чувствительными к
характеристикам.

Examples

Вступление

основы

API Reflection позволяет проверять структуру класса кода во время выполнения и


динамически вызывать код. Это очень мощно, но это также опасно, поскольку компилятор
не может статически определять, действительны ли динамические вызовы.

Простым примером могло бы стать создание публичных конструкторов и методов данного


класса:

import java.lang.reflect.Constructor;

https://riptutorial.com/ru/home 19
import java.lang.reflect.Method;

// This is a object representing the String class (not an instance of String!)


Class<String> clazz = String.class;

Constructor<?>[] constructors = clazz.getConstructors(); // returns all public constructors of


String
Method[] methods = clazz.getMethods(); // returns all public methods from String and parents

С помощью этой информации можно указать объект и динамически вызвать разные


методы.

Отражение и общие типы

Информация общего типа доступна для:

• параметры метода, используя getGenericParameterTypes() .


• методы возвращают типы, используя getGenericReturnType() .
• публичные поля, используя getGenericType .

В следующем примере показано, как извлечь информацию об общем типе во всех трех
случаях:

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

public class GenericTest {

public static void main(final String[] args) throws Exception {


final Method method = GenericTest.class.getMethod("testMethod", Map.class);
final Field field = GenericTest.class.getField("testField");

System.out.println("Method parameter:");
final Type parameterType = method.getGenericParameterTypes()[0];
displayGenericType(parameterType, "\t");

System.out.println("Method return type:");


final Type returnType = method.getGenericReturnType();
displayGenericType(returnType, "\t");

System.out.println("Field type:");
final Type fieldType = field.getGenericType();
displayGenericType(fieldType, "\t");

private static void displayGenericType(final Type type, final String prefix) {


System.out.println(prefix + type.getTypeName());
if (type instanceof ParameterizedType) {
for (final Type subtype : ((ParameterizedType) type).getActualTypeArguments()) {
displayGenericType(subtype, prefix + "\t");
}

https://riptutorial.com/ru/home 20
}

public Map<String, Map<Integer, List<String>>> testField;

public List<Number> testMethod(final Map<String, Double> arg) {


return null;
}

Это приводит к следующему результату:

Method parameter:
java.util.Map<java.lang.String, java.lang.Double>
java.lang.String
java.lang.Double
Method return type:
java.util.List<java.lang.Number>
java.lang.Number
Field type:
java.util.Map<java.lang.String, java.util.Map<java.lang.Integer,
java.util.List<java.lang.String>>>
java.lang.String
java.util.Map<java.lang.Integer, java.util.List<java.lang.String>>
java.lang.Integer
java.util.List<java.lang.String>
java.lang.String

Вызов метода

Используя отражение, метод объекта может быть вызван во время выполнения.

В этом примере показано, как вызвать методы объекта String .

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

String s = "Hello World!";

// method without parameters


// invoke s.length()
Method method1 = String.class.getMethod("length");
int length = (int) method1.invoke(s); // variable length contains "12"

// method with parameters


// invoke s.substring(6)
Method method2 = String.class.getMethod("substring", int.class);
String substring = (String) method2.invoke(s, 6); // variable substring contains "World!"

Получение и настройка полей

Используя Reflection API, можно изменить или получить значение поля во время
выполнения. Например, вы можете использовать его в API для извлечения разных полей

https://riptutorial.com/ru/home 21
на основе фактора, например ОС. Вы также можете удалить модификаторы, такие как
final чтобы поля модификации были окончательными.

Для этого вам нужно будет использовать метод Class # getField () таким образом, который
показан ниже:

// Get the field in class SomeClass "NAME".


Field nameField = SomeClass.class.getDeclaredField("NAME");

// Get the field in class Field "modifiers". Note that it does not
// need to be static
Field modifiersField = Field.class.getDeclaredField("modifiers");

// Allow access from anyone even if it's declared private


modifiersField.setAccessible(true);

// Get the modifiers on the "NAME" field as an int.


int existingModifiersOnNameField = nameField.getModifiers();

// Bitwise AND NOT Modifier.FINAL (16) on the existing modifiers


// Readup here https://en.wikipedia.org/wiki/Bitwise_operations_in_C
// if you're unsure what bitwise operations are.
int newModifiersOnNameField = existingModifiersOnNameField & ~Modifier.FINAL;

// Set the value of the modifiers field under an object for non-static fields
modifiersField.setInt(nameField, newModifiersOnNameField);

// Set it to be accessible. This overrides normal Java


// private/protected/package/etc access control checks.
nameField.setAccessible(true);

// Set the value of "NAME" here. Note the null argument.


// Pass null when modifying static fields, as there is no instance object
nameField.set(null, "Hacked by reflection...");

// Here I can directly access it. If needed, use reflection to get it. (Below)
System.out.println(SomeClass.NAME);

Получение полей намного проще. Мы можем использовать Field # get () и его варианты,
чтобы получить его значение:

// Get the field in class SomeClass "NAME".


Field nameField = SomeClass.class.getDeclaredField("NAME");

// Set accessible for private fields


nameField.setAccessible(true);

// Pass null as there is no instance, remember?


String name = (String) nameField.get(null);

Обратите внимание:

При использовании класса # getDeclaredField используйте его для получения поля в самом
классе:

https://riptutorial.com/ru/home 22
class HackMe extends Hacked {
public String iAmDeclared;
}

class Hacked {
public String someState;
}

Здесь HackMe#iAmDeclared является объявленным полем. Однако HackMe#someState не является


объявленным полем, поскольку он унаследован от своего суперкласса Hacked.

Конструктор вызовов

Получение объекта-конструктора
Класс Constructor можно получить из объекта Class следующим образом:

Class myClass = ... // get a class object


Constructor[] constructors = myClass.getConstructors();

Если переменная constructors будет иметь один экземпляр Constructor для каждого
публичного конструктора, объявленного в классе.

Если вы знаете точные типы параметров конструктора, к которому хотите получить доступ,
вы можете отфильтровать конкретный конструктор. Следующий пример возвращает
публичный конструктор данного класса, который принимает параметр Integer as:

Class myClass = ... // get a class object


Constructor constructor = myClass.getConstructor(new Class[]{Integer.class});

Если конструктор не соответствует заданным аргументам конструктора,


NoSuchMethodException .

Новый экземпляр с использованием объекта


«Конструктор»

Class myClass = MyObj.class // get a class object


Constructor constructor = myClass.getConstructor(Integer.class);
MyObj myObj = (MyObj) constructor.newInstance(Integer.valueOf(123));

Получение констант перечисления

Предоставление этого перечисления в качестве примера:

enum Compass {
NORTH(0),

https://riptutorial.com/ru/home 23
EAST(90),
SOUTH(180),
WEST(270);
private int degree;
Compass(int deg){
degree = deg;
}
public int getDegree(){
return degree;
}
}

В Java класс enum похож на любой другой класс, но имеет определенные определенные
константы для значений enum. Кроме того, у него есть поле, которое представляет собой
массив, который содержит все значения и два статических метода с именами values() и
valueOf(String) .
Мы можем это увидеть, если мы используем Reflection для печати всех полей этого класса

for(Field f : Compass.class.getDeclaredFields())
System.out.println(f.getName());

выход будет:

К СЕВЕРУ
ВОСТОК
ЮЖНЫЙ
WEST
степень
ENUM $ ЗНАЧЕНИЯ

Поэтому мы могли бы изучить классы enum с Reflection, как и любой другой класс. Но API
Reflection предлагает три метода enum-specific.

проверка перечислений

Compass.class.isEnum();

Возвращает true для классов, представляющих тип перечисления.

получение значений

Object[] values = Compass.class.getEnumConstants();

Возвращает массив всех значений перечисления, таких как Compass.values (), но без
необходимости экземпляра.

постоянная проверка enum

for(Field f : Compass.class.getDeclaredFields()){

https://riptutorial.com/ru/home 24
if(f.isEnumConstant())
System.out.println(f.getName());
}

Выводит список всех полей класса, которые являются значениями перечисления.

Получить класс с его (полностью квалифицированным) именем

Учитывая String содержащую имя класса, к объекту Class можно получить доступ с
помощью Class.forName :

Class clazz = null;


try {
clazz = Class.forName("java.lang.Integer");
} catch (ClassNotFoundException ex) {
throw new IllegalStateException(ex);
}

Java SE 1.2

Он может быть указан, если класс должен быть инициализирован (второй параметр forName
) и какой ClassLoader должен использоваться (третий параметр):

ClassLoader classLoader = ...


boolean initialize = ...
Class clazz = null;
try {
clazz = Class.forName("java.lang.Integer", initialize, classLoader);
} catch (ClassNotFoundException ex) {
throw new IllegalStateException(ex);
}

Вызов перегруженных конструкторов с использованием отражения

Пример: вызывать разные конструкторы путем передачи соответствующих параметров

import java.lang.reflect.*;

class NewInstanceWithReflection{
public NewInstanceWithReflection(){
System.out.println("Default constructor");
}
public NewInstanceWithReflection( String a){
System.out.println("Constructor :String => "+a);
}
public static void main(String args[]) throws Exception {

NewInstanceWithReflection object =
(NewInstanceWithReflection)Class.forName("NewInstanceWithReflection").newInstance();
Constructor constructor = NewInstanceWithReflection.class.getDeclaredConstructor( new
Class[] {String.class});
NewInstanceWithReflection object1 =
(NewInstanceWithReflection)constructor.newInstance(new Object[]{"StackOverFlow"});

https://riptutorial.com/ru/home 25
}
}

выход:

Default constructor
Constructor :String => StackOverFlow

Объяснение:

1. Создать экземпляр класса с использованием Class.forName : он вызывает конструктор


по умолчанию
2. Вызывать getDeclaredConstructor класса, передавая тип параметров как Class array
3. После получения конструктора создайте newInstance , передав значение параметра как
Object array

Неправильное использование API Reflection для изменения частных и


конечных переменных

Отражение полезно, когда оно правильно используется для правильной цели. Используя
отражение, вы можете получить доступ к закрытым переменным и повторно
инициализировать конечные переменные.

Ниже приведен фрагмент кода, который не рекомендуется.

import java.lang.reflect.*;

public class ReflectionDemo{


public static void main(String args[]){
try{
Field[] fields = A.class.getDeclaredFields();
A a = new A();
for ( Field field:fields ) {
if(field.getName().equalsIgnoreCase("name")){
field.setAccessible(true);
field.set(a, "StackOverFlow");
System.out.println("A.name="+field.get(a));
}
if(field.getName().equalsIgnoreCase("age")){
field.set(a, 20);
System.out.println("A.age="+field.get(a));
}
if(field.getName().equalsIgnoreCase("rep")){
field.setAccessible(true);
field.set(a,"New Reputation");
System.out.println("A.rep="+field.get(a));
}
if(field.getName().equalsIgnoreCase("count")){
field.set(a,25);
System.out.println("A.count="+field.get(a));
}
}

https://riptutorial.com/ru/home 26
}catch(Exception err){
err.printStackTrace();
}
}
}

class A {
private String name;
public int age;
public final String rep;
public static int count=0;

public A(){
name = "Unset";
age = 0;
rep = "Reputation";
count++;
}
}

Выход:

A.name=StackOverFlow
A.age=20
A.rep=New Reputation
A.count=25

Объяснение:

В обычном сценарии private переменные не могут быть доступны за пределами


объявленного класса (без методов getter и setter). final переменные не могут быть
повторно назначены после инициализации.

Reflectionразрывов обоих барьеров можно злоупотреблять, чтобы изменить как частные,


так и конечные переменные, как описано выше.

field.setAccessible(true) - ключ к достижению желаемой функциональности.

Конструктор вызовов вложенного класса

Если вы хотите создать экземпляр внутреннего вложенного класса, вам необходимо


предоставить объект класса охватывающего класса в качестве дополнительного
параметра с классом getDeclaredConstructor .

public class Enclosing{


public class Nested{
public Nested(String a){
System.out.println("Constructor :String => "+a);
}
}
public static void main(String args[]) throws Exception {
Class<?> clazzEnclosing = Class.forName("Enclosing");
Class<?> clazzNested = Class.forName("Enclosing$Nested");

https://riptutorial.com/ru/home 27
Enclosing objEnclosing = (Enclosing)clazzEnclosing.newInstance();
Constructor<?> constructor = clazzNested.getDeclaredConstructor(new
Class[]{Enclosing.class, String.class});
Nested objInner = (Nested)constructor.newInstance(new Object[]{objEnclosing,
"StackOverFlow"});
}
}

Если вложенный класс является статическим, вам не понадобится этот закрытый


экземпляр.

Динамические прокси

Динамические прокси-серверы не имеют особого отношения к Reflection, но они являются


частью API. Это в основном способ создания динамической реализации интерфейса. Это
может быть полезно при создании макетов.
Динамический прокси - это экземпляр интерфейса, который создается с помощью так
называемого обработчика вызовов, который перехватывает все вызовы методов и
позволяет обрабатывать их вызов вручную.

public class DynamicProxyTest {

public interface MyInterface1{


public void someMethod1();
public int someMethod2(String s);
}

public interface MyInterface2{


public void anotherMethod();
}

public static void main(String args[]) throws Exception {


// the dynamic proxy class
Class<?> proxyClass = Proxy.getProxyClass(
ClassLoader.getSystemClassLoader(),
new Class[] {MyInterface1.class, MyInterface2.class});
// the dynamic proxy class constructor
Constructor<?> proxyConstructor =
proxyClass.getConstructor(InvocationHandler.class);

// the invocation handler


InvocationHandler handler = new InvocationHandler(){
// this method is invoked for every proxy method call
// method is the invoked method, args holds the method parameters
// it must return the method result
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
String methodName = method.getName();

if(methodName.equals("someMethod1")){
System.out.println("someMethod1 was invoked!");
return null;
}
if(methodName.equals("someMethod2")){
System.out.println("someMethod2 was invoked!");

https://riptutorial.com/ru/home 28
System.out.println("Parameter: " + args[0]);
return 42;
}
if(methodName.equals("anotherMethod")){
System.out.println("anotherMethod was invoked!");
return null;
}
System.out.println("Unkown method!");
return null;
}
};

// create the dynamic proxy instances


MyInterface1 i1 = (MyInterface1) proxyConstructor.newInstance(handler);
MyInterface2 i2 = (MyInterface2) proxyConstructor.newInstance(handler);

// and invoke some methods


i1.someMethod1();
i1.someMethod2("stackoverflow");
i2.anotherMethod();
}
}

Результатом этого кода является следующее:

someMethod1 was invoked!


someMethod2 was invoked!
Parameter: stackoverflow
anotherMethod was invoked!

Злые Java-хаки с отражением

API Reflection можно использовать для изменения значений частных и конечных полей
даже в библиотеке по умолчанию JDK. Это можно использовать для управления
поведением некоторых известных классов, как мы увидим.

Что не возможно

Давайте сначала начнем с единственного ограничения, это единственное поле, которое мы


не можем изменить с помощью Reflection. Это Java SecurityManager . Он объявлен в
java.lang.System как

private static volatile SecurityManager security = null;

Но он не будет указан в классе System, если мы запустим этот код

for(Field f : System.class.getDeclaredFields())
System.out.println(f);

Thats из-за fieldFilterMap в sun.reflect.Reflection который содержит карту и поле


безопасности в System.class и защищает их от любого доступа с помощью Reflection.
Поэтому мы не смогли деактивировать SecurityManager .

https://riptutorial.com/ru/home 29
Сумасшедшие струны

Каждая строка Java представлена JVM как экземпляр класса String . Однако в некоторых
ситуациях JVM экономит кучу пространства, используя тот же экземпляр для строк. Это
происходит для строковых литералов, а также для строк, которые были «интернированы»,
вызывая String.intern() . Поэтому, если у вас есть "hello" в вашем коде несколько раз, это
всегда один и тот же экземпляр объекта.

Строки должны быть неизменными, но можно использовать «злобное» отражение, чтобы


изменить их. Пример ниже показывает, как мы можем изменить символы в String, заменив
его поле value .

public class CrazyStrings {


static {
try {
Field f = String.class.getDeclaredField("value");
f.setAccessible(true);
f.set("hello", "you stink!".toCharArray());
} catch (Exception e) {
}
}
public static void main(String args[]) {
System.out.println("hello");
}
}

Таким образом, этот код напечатает «вы воняете!»

1 = 42

Та же идея может быть использована с классом Integer

public class CrazyMath {


static {
try {
Field value = Integer.class.getDeclaredField("value");
value.setAccessible(true);
value.setInt(Integer.valueOf(1), 42);
} catch (Exception e) {
}
}
public static void main(String args[]) {
System.out.println(Integer.valueOf(1));
}
}

Все верно

И, согласно этому сообщению stackoverflow, мы можем использовать отражение, чтобы


сделать что-то действительно злое.

public class Evil {

https://riptutorial.com/ru/home 30
static {
try {
Field field = Boolean.class.getField("FALSE");
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, true);
} catch (Exception e) {
}
}
public static void main(String args[]){
System.out.format("Everything is %s", false);
}
}

Обратите внимание, что то, что мы делаем здесь, приведет к тому, что JVM будет вести
себя необъяснимыми способами. Это очень опасно.

Прочитайте API Reflection онлайн: https://riptutorial.com/ru/java/topic/629/api-reflection

https://riptutorial.com/ru/home 31
глава 5: API стека
Вступление
До Java 9 доступ к кадрам стека потоков был ограничен внутренним классом
sun.reflect.Reflection . В частности, метод sun.reflect.Reflection::getCallerClass . Некоторые
библиотеки полагаются на этот метод, который устарел.

Альтернативный стандарт API , теперь предоставляется в JDK 9 через java.lang.StackWalker


класса, и предназначен , чтобы быть эффективными, позволяя ленивый доступ к кадрам
стеки. Некоторые приложения могут использовать этот API для прохождения стека
выполнения и фильтрации по классам.

Examples

Печать всех кадров стека текущего потока

Следующее выводит все кадры стека текущего потока:

1 package test;
2
3 import java.lang.StackWalker.StackFrame;
4 import java.lang.reflect.InvocationTargetException;
5 import java.lang.reflect.Method;
6 import java.util.List;
7 import java.util.stream.Collectors;
8
9 public class StackWalkerExample {
10
11 public static void main(String[] args) throws NoSuchMethodException, SecurityException,
IllegalAccessException, IllegalArgumentException, InvocationTargetException {
12 Method fooMethod = FooHelper.class.getDeclaredMethod("foo", (Class<?>[])null);
13 fooMethod.invoke(null, (Object[]) null);
14 }
15 }
16
17 class FooHelper {
18 protected static void foo() {
19 BarHelper.bar();
20 }
21 }
22
23 class BarHelper {
24 protected static void bar() {
25 List<StackFrame> stack = StackWalker.getInstance()
26 .walk((s) -> s.collect(Collectors.toList()));
27 for(StackFrame frame : stack) {
28 System.out.println(frame.getClassName() + " " + frame.getLineNumber() + " " +
frame.getMethodName());
29 }
30 }

https://riptutorial.com/ru/home 32
31 }

Выход:

test.BarHelper 26 bar
test.FooHelper 19 foo
test.StackWalkerExample 13 main

Распечатать текущий класс вызывающего абонента

Следующее выводит текущий класс вызывающего абонента. Обратите внимание, что в этом
случае StackWalker необходимо создать с помощью опции RETAIN_CLASS_REFERENCE , чтобы
экземпляры Class сохранялись в объектах StackFrame . В противном случае произойдет
исключение.

public class StackWalkerExample {

public static void main(String[] args) {


FooHelper.foo();
}

class FooHelper {
protected static void foo() {
BarHelper.bar();
}
}

class BarHelper {
protected static void bar() {

System.out.println(StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE).getCallerClass());
}
}

Выход:

class test.FooHelper

Отображение отражения и других скрытых фреймов

Пара других опций позволяет трассировать трассировки стека реализации и / или


отражения. Это может быть полезно для целей отладки. Например, мы можем добавить
параметр SHOW_REFLECT_FRAMES к экземпляру StackWalker при создании, чтобы также были
напечатаны кадры для отражающих методов:

package test;

import java.lang.StackWalker.Option;
import java.lang.StackWalker.StackFrame;

https://riptutorial.com/ru/home 33
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.stream.Collectors;

public class StackWalkerExample {

public static void main(String[] args) throws NoSuchMethodException, SecurityException,


IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Method fooMethod = FooHelper.class.getDeclaredMethod("foo", (Class<?>[])null);
fooMethod.invoke(null, (Object[]) null);
}
}

class FooHelper {
protected static void foo() {
BarHelper.bar();
}
}

class BarHelper {
protected static void bar() {
// show reflection methods
List<StackFrame> stack = StackWalker.getInstance(Option.SHOW_REFLECT_FRAMES)
.walk((s) -> s.collect(Collectors.toList()));
for(StackFrame frame : stack) {
System.out.println(frame.getClassName() + " " + frame.getLineNumber() + " " +
frame.getMethodName());
}
}
}

Выход:

test.BarHelper 27 bar
test.FooHelper 20 foo
jdk.internal.reflect.NativeMethodAccessorImpl -2 invoke0
jdk.internal.reflect.NativeMethodAccessorImpl 62 invoke
jdk.internal.reflect.DelegatingMethodAccessorImpl 43 invoke
java.lang.reflect.Method 563 invoke
test.StackWalkerExample 14 main

Обратите внимание, что номера строк для некоторых методов отражения могут быть
недоступны, поэтому StackFrame.getLineNumber() может возвращать отрицательные значения.

Прочитайте API стека онлайн: https://riptutorial.com/ru/java/topic/9868/api-стека

https://riptutorial.com/ru/home 34
глава 6: AppDynamics и TIBCO
BusinessWorks для легкой интеграции
Вступление
Поскольку AppDynamics стремится обеспечить способ измерения производительности
приложений, скорость разработки, доставки (развертывания) приложений является
важным фактором в достижении успеха DevOps. Мониторинг приложения TIBCO BW с
AppD обычно прост и не требует много времени, но при развертывании больших наборов
приложений быстрые инструменты являются ключевыми. В этом руководстве показано, как
применять все ваши приложения BW на одном шаге без изменения каждого приложения
перед его развертыванием.

Examples

Пример инструментария всех приложений BW в одном шаге для


Appdynamics

1. Найдите и откройте свой файл BWengine.tra TIBCO BW под TIBCO_HOME / bw / 5.12 /


bin / bwengine.tra (среда Linux)

2. Найдите строку, которая гласит:

*** Общие переменные. Измените их


только. ***
3. Добавьте следующую строку сразу после этого раздела tibco.deployment =%
tibco.deployment%

4. Перейдите в конец файла и добавьте (замените? Вашими значениями по мере


необходимости или удалите флаг, который не применяется): java.extended.properties =
-javaagent: /opt/appd/current/appagent/javaagent.jar - Dappdynamics.http.proxyHost =? -
Dappdynamics.http.proxyPort =? -Dappdynamics.agent.applicationName =? -
Dappdynamics.agent.tierName =? -Dappdynamics.agent.nodeName =% tibco.deployment%
-Dappdynamics.controller.ssl.enabled =? -Dappdynamics.controller.sslPort =? -
Dappdynamics.agent.logs.dir =? -Dappdynamics.agent.runtime.dir =? -
Dappdynamics.controller.hostName =? -Dappdynamics.controller.port =? -
Dappdynamics.agent.accountName =? -Dappdynamics.agent.accountAccessKey =?

https://riptutorial.com/ru/home 35
5. Сохраните файл и переустановите. Все ваши приложения теперь должны быть
автоматизированы во время развертывания.

Прочитайте AppDynamics и TIBCO BusinessWorks для легкой интеграции онлайн:


https://riptutorial.com/ru/java/topic/10602/appdynamics-и-tibco-businessworks-для-легкой-
интеграции

https://riptutorial.com/ru/home 36
глава 7: Autoboxing
Вступление
Autoboxing - это автоматическое преобразование, которое компилятор Java делает между
примитивными типами и соответствующими классами обертки объектов. Пример,
преобразование int -> Integer, double -> Double ... Если преобразование идет другим путем,
это называется распаковкой. Как правило, это используется в коллекциях, которые не
могут содержать объекты, отличные от объектов, где необходимы примитивные типы
бокса, прежде чем устанавливать их в коллекции.

замечания
Автобоксирование может иметь проблемы с производительностью при частом
использовании в вашем коде.

• http://docs.oracle.com/javase/1.5.0/docs/guide/language/autoboxing.html
• Целое автоматическое разблокирование и авто-бокс дает проблемы с
производительностью?

Examples

Использование int и Integer взаимозаменяемо

Поскольку вы используете общие типы с классами утилит, вы часто можете обнаружить,


что типы номеров не очень полезны при указании в качестве типов объектов, поскольку
они не равны их примитивным аналогам.

List<Integer> ints = new ArrayList<Integer>();

Java SE 7

List<Integer> ints = new ArrayList<>();

К счастью, выражения, которые оценивают int могут использоваться вместо Integer когда
это необходимо.

for (int i = 0; i < 10; i++)


ints.add(i);

ints.add(i); утверждение эквивалентно:

ints.add(Integer.valueOf(i));

https://riptutorial.com/ru/home 37
И сохраняет свойства из значения Integer#valueOf например, с теми же Integer объектами,
которые кешируются JVM, когда он находится в диапазоне кеширования чисел.

Это также относится к:

• byte и Byte
• short и Short
• float и Float
• double и Double
• long и Long
• char и Character
• boolean и Boolean

Однако следует проявлять осторожность в неоднозначных ситуациях. Рассмотрим


следующий код:

List<Integer> ints = new ArrayList<Integer>();


ints.add(1);
ints.add(2);
ints.add(3);
ints.remove(1); // ints is now [1, 3]

Интерфейс java.util.List содержит как метод remove(int index) (метод интерфейса List ),
так и remove(Object o) (метод, унаследованный от java.util.Collection ). В этом случае бокс
не происходит и не вызывается remove(int index) .

Еще один пример странного поведения кода Java, вызванного автобоксированием Целые
числа со значениями в диапазоне от -128 до 127 :

Integer a = 127;
Integer b = 127;
Integer c = 128;
Integer d = 128;
System.out.println(a == b); // true
System.out.println(c <= d); // true
System.out.println(c >= d); // true
System.out.println(c == d); // false

Это происходит потому, что >= оператор неявно вызывает intValue() который возвращает
int while == сравнивает ссылки , а не значения int .

По умолчанию Java кэширует значения в диапазоне [-128, 127] , поэтому оператор ==


работает, потому что Integers в этом диапазоне ссылаются на одни и те же объекты, если
их значения одинаковы. Максимальное значение кэшируемого диапазона можно
определить с -XX:AutoBoxCacheMax опции -XX:AutoBoxCacheMax JVM. Итак, если вы запустите
программу с помощью -XX:AutoBoxCacheMax=1000 , следующий код напечатает true :

Integer a = 1000;

https://riptutorial.com/ru/home 38
Integer b = 1000;
System.out.println(a == b); // true

Использование Boolean в выражении if

Из-за автоматического распаковки в операторе if можно использовать Boolean выражение:

Boolean a = Boolean.TRUE;
if (a) { // a gets converted to boolean
System.out.println("It works!");
}

Это работает while , do while и условие в операторах for .

Обратите внимание, что если Boolean равно null , в преобразовании будет


NullPointerException .

Автоматическая распаковка может привести к NullPointerException

Этот код компилирует:

Integer arg = null;


int x = arg;

Но во время выполнения он будет сбой при исключении java.lang.NullPointerException во


второй строке.

Проблема в том, что примитивный int не может иметь null значение.

Это минималистический пример, но на практике он часто проявляется в более сложных


формах. NullPointerException не очень интуитивно понятное и часто мало помогает в поиске
таких ошибок.

Положитесь на автобоксинг и автоматическую распаковку с осторожностью, убедитесь,


что значения unboxed не будут иметь null значений во время выполнения.

Память и вычислительные накладные расходы на автобоксинг

Автобоксинг может иметь значительные накладные расходы памяти. Например:

Map<Integer, Integer> square = new HashMap<Integer, Integer>();


for(int i = 256; i < 1024; i++) {
square.put(i, i * i); // Autoboxing of large integers
}

как правило, потребляют значительный объем памяти (около 60 кб для 6 тыс. фактических
данных).

https://riptutorial.com/ru/home 39
Кроме того, целые числа в штучной упаковке обычно требуют дополнительных округлений
в памяти и, таким образом, делают кэширование процессора менее эффективным. В
приведенном выше примере доступ к памяти распространяется на пять разных
местоположений, которые могут находиться в совершенно разных областях памяти: 1.
объект HashMap , 2. объект Entry[] table , 3. объект Entry , 4. элемент ввода key слов (бокс
примитивного ключа), 5. объект value entry (бокс примитивного значения).

class Example {
int primitive; // Stored directly in the class `Example`
Integer boxed; // Reference to another memory location
}

Чтение в boxed требует двух обращений к памяти, доступ к primitive только один.

При получении данных с этой карты, казалось бы, невинный код

int sumOfSquares = 0;
for(int i = 256; i < 1024; i++) {
sumOfSquares += square.get(i);
}

эквивалентно:

int sumOfSquares = 0;
for(int i = 256; i < 1024; i++) {
sumOfSquares += square.get(Integer.valueOf(i)).intValue();
}

Как правило, приведенный выше код вызывает сбор и сбор мусора объекта Integer для
каждой операции Map#get(Integer) . (Подробнее см. Примечание ниже).

Чтобы уменьшить эти накладные расходы, несколько библиотек предлагают


оптимизированные коллекции для примитивных типов, которые не требуют бокса. В
дополнение к тому, чтобы избежать накладных расходов на бокс, для этой коллекции
потребуется примерно 4 раза меньше памяти на запись. В то время как Java Hotspot может
оптимизировать автобоксинг, работая с объектами в стеке вместо кучи, невозможно
оптимизировать накладные расходы памяти и вызванную память.

В потоках Java 8 также есть оптимизированные интерфейсы для примитивных типов


данных, таких как IntStream которые не требуют бокса.

Примечание: типичная среда выполнения Java поддерживает простой кэш Integer и другой
примитивный объект-оболочку, который используется фабричными методами valueOf и
автобоксированием. Для Integer диапазон по умолчанию этого кеша составляет от -128 до
+127. Некоторые JVM предоставляют параметр командной строки JVM для изменения
размера и диапазона кеша.

https://riptutorial.com/ru/home 40
Различные случаи Когда Integer и int могут использоваться
взаимозаменяемо

Случай 1: используется вместо аргументов метода.

Если метод требует, чтобы объект класса-оболочки был аргументом. Затем, в качестве
взаимозаменяемого аргумента может быть передана переменная соответствующего
примитивного типа и наоборот.

Пример:

int i;
Integer j;
void ex_method(Integer i)//Is a valid statement
void ex_method1(int j)//Is a valid statement

Случай 2: При передаче возвращаемых значений:

Когда метод возвращает примитивную переменную типа, тогда объект соответствующего


класса-оболочки может быть передан как возвращаемое значение взаимозаменяемо и
наоборот.

Пример:

int i;
Integer j;
int ex_method()
{...
return j;}//Is a valid statement
Integer ex_method1()
{...
return i;//Is a valid statement
}

Случай 3: При выполнении операций.

Всякий раз, когда выполняются операции над числами, переменная примитива и объект
соответствующего класса-оболочки могут использоваться взаимозаменяемо.

int i=5;
Integer j=new Integer(7);
int k=i+j;//Is a valid statement
Integer m=i+j;//Is also a valid statement

Pitfall : не забудьте инициализировать или присвоить значение объекту класса-оболочки.

При использовании объекта класса-оболочки и примитивной переменной взаимозаменяемо


никогда не забывать или пропустить инициализацию или присвоение значения объекту
класса-оболочки иначе он может привести к исключению нулевого указателя во время

https://riptutorial.com/ru/home 41
выполнения.

Пример:

public class Test{


Integer i;
int j;
public void met()
{j=i;//Null pointer exception
SOP(j);
SOP(i);}
public static void main(String[] args)
{Test t=new Test();
t.go();//Null pointer exception
}

В приведенном выше примере значение объекта не назначено и неинициализировано, и,


таким образом, во время выполнения программа будет запущена в исключение нулевого
указателя. Так же, как ясно из приведенного выше примера, значение объекта никогда не
должно оставаться неинициализированным и неназначенным.

Прочитайте Autoboxing онлайн: https://riptutorial.com/ru/java/topic/138/autoboxing

https://riptutorial.com/ru/home 42
глава 8: BigDecimal
Вступление
Класс BigDecimal предоставляет операции для арифметики (добавление, вычитание,
умножение, деление), масштабирование, округление, сравнение, хэширование и
преобразование формата. BigDecimal представляет собой неизменяемые десятичные
числа с произвольной точностью. Этот класс должен использоваться при необходимости
высокоточного вычисления.

Examples

Объекты BigDecimal являются неизменяемыми

Если вы хотите рассчитать с помощью BigDecimal, вы должны использовать возвращаемое


значение, потому что объекты BigDecimal являются неизменяемыми:

BigDecimal a = new BigDecimal("42.23");


BigDecimal b = new BigDecimal("10.001");

a.add(b); // a will still be 42.23

BigDecimal c = a.add(b); // c will be 52.231

Сравнение BigDecimals

Метод compareTo должен использоваться для сравнения BigDecimals :

BigDecimal a = new BigDecimal(5);


a.compareTo(new BigDecimal(0)); // a is greater, returns 1
a.compareTo(new BigDecimal(5)); // a is equal, returns 0
a.compareTo(new BigDecimal(10)); // a is less, returns -1

Обычно вы не должны использовать метод equals поскольку он считает, что два BigDecimals
равны, только если они равны по стоимости и также масштабируются :

BigDecimal a = new BigDecimal(5);


a.equals(new BigDecimal(5)); // value and scale are equal, returns true
a.equals(new BigDecimal(5.00)); // value is equal but scale is not, returns false

Математические операции с BigDecimal

В этом примере показано, как выполнять основные математические операции с помощью


BigDecimals.

https://riptutorial.com/ru/home 43
1.Addition
BigDecimal a = new BigDecimal("5");
BigDecimal b = new BigDecimal("7");

//Equivalent to result = a + b
BigDecimal result = a.add(b);
System.out.println(result);

Результат: 12

2.Subtraction
BigDecimal a = new BigDecimal("5");
BigDecimal b = new BigDecimal("7");

//Equivalent to result = a - b
BigDecimal result = a.subtract(b);
System.out.println(result);

Результат: 2

3.Multiplication
При умножении двух BigDecimal s результат будет иметь масштаб, равный сумме шкал
операндов.

BigDecimal a = new BigDecimal("5.11");


BigDecimal b = new BigDecimal("7.221");

//Equivalent to result = a * b
BigDecimal result = a.multiply(b);
System.out.println(result);

Результат: 36.89931

Чтобы изменить масштаб результата, используйте метод перегруженного множителя,


который позволяет передавать MathContext - объект, описывающий правила для
операторов, в частности, режим точности и округления результата. Дополнительные
сведения о доступных режимах округления см. В документации Oracle.

BigDecimal a = new BigDecimal("5.11");


BigDecimal b = new BigDecimal("7.221");

MathContext returnRules = new MathContext(4, RoundingMode.HALF_DOWN);

//Equivalent to result = a * b

https://riptutorial.com/ru/home 44
BigDecimal result = a.multiply(b, returnRules);
System.out.println(result);

Результат: 36.90

4.Division
Разделение немного сложнее, чем другие арифметические операции, например,
рассмотрим приведенный ниже пример:

BigDecimal a = new BigDecimal("5");


BigDecimal b = new BigDecimal("7");

BigDecimal result = a.divide(b);


System.out.println(result);

Мы ожидаем, что это даст нечто похожее: 0.7142857142857143, но мы получим:

Результат: java.lang.ArithmeticException: Неограничивающее десятичное


расширение; нет точного представимого десятичного результата.

Это будет отлично работать, когда результат будет завершающим десятичным, скажем,
если бы я хотел разделить 5 на 2, но для тех чисел, которые при делении будут давать не
заканчивающийся результат, мы получим ArithmeticException . В сценарии реального мира
невозможно предсказать значения, которые будут встречаться во время деления, поэтому
нам нужно указать масштаб и режим округления для деления BigDecimal. Для получения
дополнительной информации о режиме масштабирования и округления см. Документацию
Oracle .

Например, я мог бы сделать:

BigDecimal a = new BigDecimal("5");


BigDecimal b = new BigDecimal("7");

//Equivalent to result = a / b (Upto 10 Decimal places and Round HALF_UP)


BigDecimal result = a.divide(b,10,RoundingMode.HALF_UP);
System.out.println(result);

Результат: 0.7142857143

5.Remainder или модуль


BigDecimal a = new BigDecimal("5");
BigDecimal b = new BigDecimal("7");

//Equivalent to result = a % b
BigDecimal result = a.remainder(b);

https://riptutorial.com/ru/home 45
System.out.println(result);

Результат: 5

6.Power
BigDecimal a = new BigDecimal("5");

//Equivalent to result = a^10


BigDecimal result = a.pow(10);
System.out.println(result);

Результат: 9765625

7.Max
BigDecimal a = new BigDecimal("5");
BigDecimal b = new BigDecimal("7");

//Equivalent to result = MAX(a,b)


BigDecimal result = a.max(b);
System.out.println(result);

Результат: 7

8.Min
BigDecimal a = new BigDecimal("5");
BigDecimal b = new BigDecimal("7");

//Equivalent to result = MIN(a,b)


BigDecimal result = a.min(b);
System.out.println(result);

Результат: 5

9. Переместите точку влево


BigDecimal a = new BigDecimal("5234.49843776");

//Moves the decimal point to 2 places left of current position


BigDecimal result = a.movePointLeft(2);
System.out.println(result);

Результат: 52.3449843776

https://riptutorial.com/ru/home 46
10.Переведите точку вправо
BigDecimal a = new BigDecimal("5234.49843776");

//Moves the decimal point to 3 places right of current position


BigDecimal result = a.movePointRight(3);
System.out.println(result);

Результат: 5234498.43776

Существует множество дополнительных параметров и комбинаций параметров для


вышеупомянутых примеров (например, существует 6 вариантов метода разделения), этот
набор является неисчерпывающим списком и охватывает несколько базовых примеров.

Использование BigDecimal вместо float

В связи с тем, что тип float представлен в памяти компьютера, результаты операций с
использованием этого типа могут быть неточными - некоторые значения сохраняются в
виде приближений. Хорошими примерами этого являются денежные расчеты. Если
требуется высокая точность, следует использовать другие типы. например, Java 7
предоставляет BigDecimal.

import java.math.BigDecimal;

public class FloatTest {

public static void main(String[] args) {


float accountBalance = 10000.00f;
System.out.println("Operations using float:");
System.out.println("1000 operations for 1.99");
for(int i = 0; i<1000; i++){
accountBalance -= 1.99f;
}
System.out.println(String.format("Account balance after float operations: %f",
accountBalance));

BigDecimal accountBalanceTwo = new BigDecimal("10000.00");


System.out.println("Operations using BigDecimal:");
System.out.println("1000 operations for 1.99");
BigDecimal operation = new BigDecimal("1.99");
for(int i = 0; i<1000; i++){
accountBalanceTwo = accountBalanceTwo.subtract(operation);
}
System.out.println(String.format("Account balance after BigDecimal operations: %f",
accountBalanceTwo));
}

Вывод этой программы:

Operations using float:


1000 operations for 1.99

https://riptutorial.com/ru/home 47
Account balance after float operations: 8009,765625
Operations using BigDecimal:
1000 operations for 1.99
Account balance after BigDecimal operations: 8010,000000

Для стартового баланса 10000,00, после 1000 операций за 1.99, мы ожидаем, что баланс
будет равен 8010,00. Использование типа float дает нам ответ около 8009,77, что
неприемлемо неточно в случае денежных расчетов. Использование BigDecimal дает нам
правильный результат.

BigDecimal.valueOf ()

Класс BigDecimal содержит внутренний кеш часто используемых чисел, например, от 0 до


10. Методы BigDecimal.valueOf () предоставляются в предпочтении конструкторам с
похожими параметрами типа, то есть в приведенном ниже примере a предпочтительнее b.

BigDecimal a = BigDecimal.valueOf(10L); //Returns cached Object reference


BigDecimal b = new BigDecimal(10L); //Does not return cached Object reference

BigDecimal a = BigDecimal.valueOf(20L); //Does not return cached Object reference


BigDecimal b = new BigDecimal(20L); //Does not return cached Object reference

BigDecimal a = BigDecimal.valueOf(15.15); //Preferred way to convert a double (or float) into


a BigDecimal, as the value returned is equal to that resulting from constructing a BigDecimal
from the result of using Double.toString(double)
BigDecimal b = new BigDecimal(15.15); //Return unpredictable result

Инициализация BigDecimals со значением нуля, один или десять

BigDecimal предоставляет статические свойства для чисел 0, один и десять.


Рекомендуется использовать их вместо использования фактических чисел:

• BigDecimal.ZERO
• BigDecimal.ONE
• BigDecimal.TEN

Используя статические свойства, вы избегаете ненужного создания экземпляра, также у


вас есть буквальный код, а не «магическое число».

//Bad example:
BigDecimal bad0 = new BigDecimal(0);
BigDecimal bad1 = new BigDecimal(1);
BigDecimal bad10 = new BigDecimal(10);

//Good Example:
BigDecimal good0 = BigDecimal.ZERO;
BigDecimal good1 = BigDecimal.ONE;
BigDecimal good10 = BigDecimal.TEN;

Прочитайте BigDecimal онлайн: https://riptutorial.com/ru/java/topic/1667/bigdecimal

https://riptutorial.com/ru/home 48
глава 9: BigInteger
Вступление
Класс BigInteger используется для математических операций с большими целыми числами с
слишком большими величинами для примитивных типов данных. Например, 100-факториал
составляет 158 цифр - намного больше, чем может представлять long . BigInteger
предоставляет аналоги всем примитивным целочисленным операторам Java и всем
соответствующим методам из java.lang.Math а также нескольким другим операциям.

Синтаксис
• BigInteger variable_name = new BigInteger ("12345678901234567890"); // десятичное
целое в виде строки
• BigInteger variable_name = new BigInteger
("1010101101010100101010011000110011101011000111110000101011010010", 2) //
двоичное целое в виде строки
• BigInteger variable_name = new BigInteger ("ab54a98ceb1f0800", 16) //
шестнадцатеричное целое число в виде строки
• BigInteger variable_name = new BigInteger (64, new Random ()); // генератор
псевдослучайных чисел, обеспечивающий 64 бита для построения целого числа
• BigInteger variable_name = new BigInteger (новый байт [] {0, -85, 84, -87, -116, -21, 31, 10,
-46}); // подписали двухдополнительное представление целого (big endian)
• BigInteger variable_name = new BigInteger (1, новый байт [] {- 85, 84, -87, -116, -21, 31,
10, -46}); // Непрерывное представление целых чисел без знака (положительное
целое число)

замечания
неизменен. Поэтому вы не можете изменить свое состояние. Например,
BigInteger
следующее не будет работать, поскольку sum не будет обновляться из-за неизменности.

BigInteger sum = BigInteger.ZERO;


for(int i = 1; i < 5000; i++) {
sum.add(BigInteger.valueOf(i));
}

Назначьте результат переменной sum чтобы она работала.

sum = sum.add(BigInteger.valueOf(i));

Java SE 8

https://riptutorial.com/ru/home 49
В официальной документации BigInteger говорится, что реализации BigInteger должны
поддерживать все целые числа от -2 2147483647 до 2 2147483647 (эксклюзивные). Это
означает, что BigInteger s может иметь более 2 миллиардов бит!

Examples

инициализация

Класс java.math.BigInteger обеспечивает аналоги операций для всех примитивных


целочисленных операторов Java и для всех соответствующих методов из java.lang.Math .
Поскольку пакет java.math не будет автоматически доступен, вам может потребоваться
импортировать java.math.BigInteger прежде чем вы сможете использовать простое имя
класса.

Чтобы преобразовать значения long или int в BigInteger используйте:

long longValue = Long.MAX_VALUE;


BigInteger valueFromLong = BigInteger.valueOf(longValue);

или, для целых чисел:

int intValue = Integer.MIN_VALUE; // negative


BigInteger valueFromInt = BigInteger.valueOf(intValue);

который расширит целое число intValue до long, используя расширение бита знака для
отрицательных значений, так что отрицательные значения останутся отрицательными.

Чтобы преобразовать числовую String в BigInteger используйте:

String decimalString = "-1";


BigInteger valueFromDecimalString = new BigInteger(decimalString);

Следующий конструктор используется для преобразования строкового представления


BigInteger в указанном радиусе в BigInteger .

String binaryString = "10";


int binaryRadix = 2;
BigInteger valueFromBinaryString = new BigInteger(binaryString , binaryRadix);

Java также поддерживает прямое преобразование байтов в экземпляр BigInteger . В


настоящее время может использоваться только подписанная и беззнаковая кодировка
большого конца:

byte[] bytes = new byte[] { (byte) 0x80 };


BigInteger valueFromBytes = new BigInteger(bytes);

https://riptutorial.com/ru/home 50
Это будет генерировать экземпляр BigInteger со значением -128, поскольку первый бит
интерпретируется как бит знака.

byte[] unsignedBytes = new byte[] { (byte) 0x80 };


int sign = 1; // positive
BigInteger valueFromUnsignedBytes = new BigInteger(sign, unsignedBytes);

Это будет генерировать экземпляр BigInteger со значением 128, поскольку байты


интерпретируются как беззнаковое число, а знак явно установлен в 1, положительное
число.

Существуют предопределенные константы для общих значений:

• BigInteger.ZERO - значение «0».


• BigInteger.ONE - значение «1».
• BigInteger.TEN - значение «10».

Существует также BigInteger.TWO (значение «2»), но вы не можете использовать его в своем


коде, потому что он является private .

Сравнение BigIntegers

Вы можете сравнить BigIntegers же, как вы сравниваете String или другие объекты в Java.

Например:

BigInteger one = BigInteger.valueOf(1);


BigInteger two = BigInteger.valueOf(2);

if(one.equals(two)){
System.out.println("Equal");
}
else{
System.out.println("Not Equal");
}

Выход:

Not Equal

Замечания:

В общем, не используйте использование оператора == для сравнения BigIntegers

• == operator: сравнивает ссылки; т.е. имеют ли два значения один и тот же объект
• Метод equals() : сравнивает содержимое двух BigIntegers.

Например, BigIntegers не следует сравнивать следующим образом:

https://riptutorial.com/ru/home 51
if (firstBigInteger == secondBigInteger) {
// Only checks for reference equality, not content equality!
}

Это может привести к неожиданному поведению, поскольку оператор == проверяет только


ссылочное равенство. Если оба BigIntegers содержат один и тот же контент, но не
относятся к одному и тому же объекту, это не сработает. Вместо этого сравните
BigIntegers, используя методы equals , как описано выше.

Вы также можете сравнить свой BigInteger с постоянными значениями, такими как 0,1,10.

например:

BigInteger reallyBig = BigInteger.valueOf(1);


if(BigInteger.ONE.equals(reallyBig)){
//code when they are equal.
}

Вы также можете сравнить два BigIntegers с помощью метода compareTo() , как compareTo()
ниже: compareTo() возвращает 3 значения.

• 0: Когда оба равны .


• 1: Когда первое больше второго (одно в скобках).
• -1: Когда первое меньше секунды.

BigInteger reallyBig = BigInteger.valueOf(10);


BigInteger reallyBig1 = BigInteger.valueOf(100);

if(reallyBig.compareTo(reallyBig1) == 0){
//code when both are equal.
}
else if(reallyBig.compareTo(reallyBig1) == 1){
//code when reallyBig is greater than reallyBig1.
}
else if(reallyBig.compareTo(reallyBig1) == -1){
//code when reallyBig is less than reallyBig1.
}

Примеры математических операций BigInteger

BigInteger находится в неизменяемом объекте, поэтому вам нужно назначить результаты


любой математической операции новому экземпляру BigInteger.

Дополнение: 10 + 10 = 20

BigInteger value1 = new BigInteger("10");


BigInteger value2 = new BigInteger("10");

BigInteger sum = value1.add(value2);


System.out.println(sum);

https://riptutorial.com/ru/home 52
выход: 20

Субстрат: 10 - 9 = 1

BigInteger value1 = new BigInteger("10");


BigInteger value2 = new BigInteger("9");

BigInteger sub = value1.subtract(value2);


System.out.println(sub);

выход: 1

Отдел: 10/5 = 2

BigInteger value1 = new BigInteger("10");


BigInteger value2 = new BigInteger("5");

BigInteger div = value1.divide(value2);


System.out.println(div);

выход: 2

Отдел: 17/4 = 4

BigInteger value1 = new BigInteger("17");


BigInteger value2 = new BigInteger("4");

BigInteger div = value1.divide(value2);


System.out.println(div);

выход: 4

Умножение: 10 * 5 = 50

BigInteger value1 = new BigInteger("10");


BigInteger value2 = new BigInteger("5");

BigInteger mul = value1.multiply(value2);


System.out.println(mul);

выход: 50

Мощность: 10 ^ 3 = 1000

BigInteger value1 = new BigInteger("10");


BigInteger power = value1.pow(3);
System.out.println(power);

выход: 1000

Остаток: 10% 6 = 4

https://riptutorial.com/ru/home 53
BigInteger value1 = new BigInteger("10");
BigInteger value2 = new BigInteger("6");

BigInteger power = value1.remainder(value2);


System.out.println(power);

выход: 4

GCD: наибольший общий делитель (GCD) для 12 и 18 - 6 .

BigInteger value1 = new BigInteger("12");


BigInteger value2 = new BigInteger("18");

System.out.println(value1.gcd(value2));

Выход: 6

Максимум два BigIntegers:

BigInteger value1 = new BigInteger("10");


BigInteger value2 = new BigInteger("11");

System.out.println(value1.max(value2));

Выход: 11

Минимум двух BigIntegers:

BigInteger value1 = new BigInteger("10");


BigInteger value2 = new BigInteger("11");

System.out.println(value1.min(value2));

Выход: 10

Двоичные логические операции на BigInteger

BigInteger поддерживает двоичные логические операции, доступные также для типов


Number . Как и во всех операциях, они реализуются путем вызова метода.

Двоичный или:

BigInteger val1 = new BigInteger("10");


BigInteger val2 = new BigInteger("9");

val1.or(val2);

Выход: 11 (что эквивалентно 10 | 9 )

Двоичные и:

https://riptutorial.com/ru/home 54
BigInteger val1 = new BigInteger("10");
BigInteger val2 = new BigInteger("9");

val1.and(val2);

Выход: 8 (что эквивалентно 10 & 9 )

Binary Xor:

BigInteger val1 = new BigInteger("10");


BigInteger val2 = new BigInteger("9");

val1.xor(val2);

Выход: 3 (что эквивалентно 10 ^ 9 )

RightShift:

BigInteger val1 = new BigInteger("10");

val1.shiftRight(1); // the argument be an Integer

Выход: 5 (эквивалентно 10 >> 1 )

Сдвиг влево:

BigInteger val1 = new BigInteger("10");

val1.shiftLeft(1); // here parameter should be Integer

Выход: 20 (эквивалентно 10 << 1 )

Двоичная инверсия (нет):

BigInteger val1 = new BigInteger("10");

val1.not();

Выход: 5

NAND (And-Not): *

BigInteger val1 = new BigInteger("10");


BigInteger val2 = new BigInteger("9");

val1.andNot(val2);

Выход: 7

Создание случайных BigIntegers

https://riptutorial.com/ru/home 55
Класс BigInteger имеет конструктор, предназначенный для генерации случайных BigIntegers
, учитывая экземпляр java.util.Random и int который определяет, сколько бит будет иметь
BigInteger . Его использование довольно просто - когда вы вызываете конструктор
BigInteger(int, Random) следующим образом:

BigInteger randomBigInt = new BigInteger(bitCount, sourceOfRandomness);

то вы получите BigInteger , значение которого находится в bitCount от 0 (включительно) и до


2 bitCount (исключение).

Это также означает, что new BigInteger(2147483647, sourceOfRandomness) может вернуть все
положительные значения BigInteger с достаточным временем.

Какова будет sourceOfRandomness ? Например, new Random() достаточно хорош в большинстве


случаев:

new BigInteger(32, new Random());

Если вы хотите отказаться от скорости для более качественных случайных чисел, вместо
этого вы можете использовать new SecureRandom () :

import java.security.SecureRandom;

// somewhere in the code...


new BigInteger(32, new SecureRandom());

Вы даже можете реализовать алгоритм «на лету» с анонимным классом! Обратите


внимание , что выкатывает свой собственный алгоритм ГСЧ закончится вас с низким
качеством случайностью, поэтому всегда обязательно использовать алгоритм , который ,
как доказано , чтобы быть достойной , если вы не хотите, чтобы в результате BigInteger (ы)
быть предсказуемым.

new BigInteger(32, new Random() {


int seed = 0;

@Override
protected int next(int bits) {
seed = ((22695477 * seed) + 1) & 2147483647; // Values shamelessly stolen from
Wikipedia
return seed;
}
});

Прочитайте BigInteger онлайн: https://riptutorial.com/ru/java/topic/1514/biginteger

https://riptutorial.com/ru/home 56
глава 10: BufferedWriter
Синтаксис
• новый BufferedWriter (Writer); // Конструктор по умолчанию
• BufferedWriter.write (int c); // Записывает один символ
• BufferedWriter.write (String str); // Записывает строку
• BufferedWriter.newLine (); // Записывает разделитель строк
• BufferedWriter.close (); // Закрывает BufferedWriter

замечания
• Если вы попытаетесь написать из BufferedWriter (используя BufferedWriter.write() )
после закрытия BufferedWriter (используя BufferedWriter.close() ), это вызовет
IOException .
• Конструктор BufferedWriter(Writer) НЕ выбрасывает IOException . Однако конструктор
FileWriter(File) FileNotFoundException , которое расширяет IOException . Таким образом,
IOException также поймает FileNotFoundException , никогда не требуется второй
оператор catch, если вы не планируете делать что-то другое с FileNotFoundException .

Examples

Напишите строку текста в файл

Этот код записывает строку в файл. Важно закрыть автора, так что это делается в блоке
finally .

public void writeLineToFile(String str) throws IOException {


File file = new File("file.txt");
BufferedWriter bw = null;
try {
bw = new BufferedWriter(new FileWriter(file));
bw.write(str);
} finally {
if (bw != null) {
bw.close();
}
}
}

Также обратите внимание, что write(String s) не помещает символ новой строки после
того, как строка была записана. Для этого используйте newLine() .

Java SE 7

https://riptutorial.com/ru/home 57
Java 7 добавляет пакет java.nio.file и пытается использовать ресурсы :

public void writeLineToFile(String str) throws IOException {


Path path = Paths.get("file.txt");
try (BufferedWriter bw = Files.newBufferedWriter(path)) {
bw.write(str);
}
}

Прочитайте BufferedWriter онлайн: https://riptutorial.com/ru/java/topic/3063/bufferedwriter

https://riptutorial.com/ru/home 58
глава 11: ByteBuffer
Вступление
Класс ByteBuffer был введен в java 1.4 для облегчения работы с двоичными данными. Он
особенно подходит для использования с данными примитивного типа. Это позволяет
создавать, но также и последующую манипуляцию byte[] s на более высоком уровне
абстракции

Синтаксис
• byte [] arr = новый байт [1000];
• ByteBuffer buffer = ByteBuffer.wrap (arr);
• ByteBuffer buffer = ByteBuffer.allocate (1024);
• ByteBuffer buffer = ByteBuffer.allocateDirect (1024);
• byte b = buffer.get ();
• байт b = buffer.get (10);
• short s = buffer.getShort (10);
• buffer.put ((byte) 120);
• buffer.putChar ( 'а');

Examples

Основное использование - создание ByteBuffer

Существует два способа создания ByteBuffer , где можно снова подразделить.

Если у вас уже есть byte[] , вы можете «обернуть» его в ByteBuffer чтобы упростить
обработку:

byte[] reqBuffer = new byte[BUFFER_SIZE];


int readBytes = socketInputStream.read(reqBuffer);
final ByteBuffer reqBufferWrapper = ByteBuffer.wrap(reqBuffer);

Это будет возможность для кода, который обрабатывает сетевые взаимодействия на


низком уровне

Если у вас нет уже существующего byte[] , вы можете создать ByteBuffer над массивом,
специально выделенным для буфера следующим образом:

final ByteBuffer respBuffer = ByteBuffer.allocate(RESPONSE_BUFFER_SIZE);


putResponseData(respBuffer);
socketOutputStream.write(respBuffer.array());

https://riptutorial.com/ru/home 59
Если код-путь чрезвычайно критичен по производительности и вам нужен прямой доступ
к системной памяти , ByteBuffer может даже выделять прямые буферы с помощью
#allocateDirect()

Основное использование - запись данных в буфер

Учитывая ByteBuffer экземпляр можно записывать данные примитивного типа к нему с


помощью относительного и абсолютного put . Поразительное различие заключается в том,
что помещение данных с использованием относительного метода отслеживает индекс, в
который данные вставляются для вас, в то время как абсолютный метод всегда требует
указания индекса для put данных.

Оба метода позволяют «цепочки» вызовов. При достаточно большом буфере можно
сделать следующее:

buffer.putInt(0xCAFEBABE).putChar('c').putFloat(0.25).putLong(0xDEADBEEFCAFEBABE);

что эквивалентно:

buffer.putInt(0xCAFEBABE);
buffer.putChar('c');
buffer.putFloat(0.25);
buffer.putLong(0xDEADBEEFCAFEBABE);

Обратите внимание, что метод, базирующийся на byte не указан специально. Кроме того ,
обратите внимание , что это справедливо и для передачи одновременно ByteBuffer и byte[] ,
чтобы put . Кроме этого, все примитивные типы имеют специализированные put методы.

Дополнительная заметка: индекс, указанный при использовании абсолютного значения


put* , всегда учитывается в byte .

Основное использование - использование DirectByteBuffer

DirectByteBuffer - это специальная реализация ByteBuffer , у которой нет byte[] .

Мы можем выделить такой ByteBuffer, вызывая:

ByteBuffer directBuffer = ByteBuffer.allocateDirect(16);

Эта операция будет выделять 16 байт памяти. Содержимое прямых буферов может
находиться вне обычной кучи мусора.

Мы можем проверить, является ли ByteBuffer прямым, вызывая:

directBuffer.isDirect(); // true

https://riptutorial.com/ru/home 60
Основные характеристики DirectByteBuffer том, что JVM будет пытаться изначально
работать с выделенной памятью без дополнительной буферизации, поэтому выполняемые
на ней операции могут быть быстрее, чем выполняемые на ByteBuffers с лежащими под ним
массивами.

Рекомендуется использовать DirectByteBuffer с тяжелыми операциями ввода-вывода,


которые полагаются на скорость выполнения, например, в режиме реального времени.

Мы должны знать, что если мы попытаемся использовать метод array() мы получим


UnsupportedOperationException . Таким образом, это хорошая практика, чтобы проверить, есть
ли у нашего ByteBuffer (байтовый массив), прежде чем мы попытаемся получить к нему
доступ:

byte[] arrayOfBytes;
if(buffer.hasArray()) {
arrayOfBytes = buffer.array();
}

Другое использование прямого байтового буфера - это взаимодействие через JNI.


Поскольку буфер прямого байта не использует byte[] , а представляет собой фактический
блок памяти, можно получить доступ к этой памяти непосредственно через указатель в
собственном коде. Это может сэкономить массу проблем и накладных расходов при
сортировке между Java и собственным представлением данных.

Интерфейс JNI определяет несколько функций для обработки буферов с прямым байтом:
поддержка NIO .

Прочитайте ByteBuffer онлайн: https://riptutorial.com/ru/java/topic/702/bytebuffer

https://riptutorial.com/ru/home 61
глава 12: CompletableFuture
Вступление
CompletableFuture - это класс, добавленный в Java SE 8, который реализует интерфейс
Future от Java SE 5. Помимо поддержки интерфейса Future, он добавляет множество
методов, которые позволяют асинхронный обратный вызов, когда будущее будет
завершено.

Examples

Преобразование метода блокировки в асинхронный

Следующий метод займет секунду или два в зависимости от вашего подключения, чтобы
получить веб-страницу и подсчитать длину текста. Какими бы ни были потоковые вызовы,
они будут блокироваться в течение этого периода времени. Также он вызывает
исключение, которое полезно позже.

public static long blockingGetWebPageLength(String urlString) {


try (BufferedReader br = new BufferedReader(new InputStreamReader(new
URL(urlString).openConnection().getInputStream()))) {
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
return sb.toString().length();
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}

Это преобразует его в метод, который немедленно возвращается, перемещая вызов метода
блокировки в другой поток. По умолчанию метод supplyAsync будет запускать поставщика
в общий пул. Для метода блокировки это, вероятно, не очень хороший выбор, поскольку вы
могли бы исчерпать потоки в этом пуле, поэтому я добавил дополнительный параметр
сервиса.

static private ExecutorService service = Executors.newCachedThreadPool();

static public CompletableFuture<Long> asyncGetWebPageLength(String url) {


return CompletableFuture.supplyAsync(() -> blockingGetWebPageLength(url), service);
}

Чтобы использовать функцию в асинхронном режиме, следует использовать методы,


которые принимают ламду, которую вызывают с результатом поставщика, когда она

https://riptutorial.com/ru/home 62
завершается, например thenAccept. Также важно использовать метод исключения или
обработки для регистрации любых исключений, которые могли произойти.

public static void main(String[] args) {

asyncGetWebPageLength("https://stackoverflow.com/")
.thenAccept(l -> {
System.out.println("Stack Overflow returned " + l);
})
.exceptionally((Throwable throwable) -> {
Logger.getLogger("myclass").log(Level.SEVERE, "", throwable);
return null;
});

Простой пример CompletingFuture

В приведенном ниже примере, calculateShippingPrice метод вычисляет стоимость доставки,


которая занимает некоторое время обработки. Например, в реальном мире это может быть
обращение к другому серверу, который возвращает цену, основанную на весе продукта и
способе доставки.

Путем моделирования этого методом async через CompletableFuture мы можем продолжить


разную работу в методе (т.е. рассчитать затраты на упаковку).

public static void main(String[] args) {


int price = 15; // Let's keep it simple and work with whole number prices here
int weightInGrams = 900;

calculateShippingPrice(weightInGrams) // Here, we get the future


.thenAccept(shippingPrice -> { // And then immediately work on it!
// This fluent style is very useful for keeping it concise
System.out.println("Your total price is: " + (price + shippingPrice));
});
System.out.println("Please stand by. We are calculating your total price.");
}

public static CompletableFuture<Integer> calculateShippingPrice(int weightInGrams) {


return CompletableFuture.supplyAsync(() -> {
// supplyAsync is a factory method that turns a given
// Supplier<U> into a CompletableFuture<U>

// Let's just say each 200 grams is a new dollar on your shipping costs
int shippingCosts = weightInGrams / 200;

try {
Thread.sleep(2000L); // Now let's simulate some waiting time...
} catch(InterruptedException e) { /* We can safely ignore that */ }

return shippingCosts; // And send the costs back!


});
}

https://riptutorial.com/ru/home 63
Прочитайте CompletableFuture онлайн:
https://riptutorial.com/ru/java/topic/10935/completablefuture

https://riptutorial.com/ru/home 64
глава 13: Enum, начиная с номера
Вступление
Java не разрешает имя enum начинать с номера типа 100A, 25K. В этом случае мы можем
добавить код с помощью _ (underscore) или любого разрешенного шаблона и проверить его.

Examples

Enum с именем при начале

public enum BookCode {


_10A("Simon Haykin", "Communication System"),
_42B("Stefan Hakins", "A Brief History of Time"),
E1("Sedra Smith", "Electronics Circuits");

private String author;


private String title;

BookCode(String author, String title) {


this.author = author;
this.title = title;
}

public String getName() {


String name = name();
if (name.charAt(0) == '_') {
name = name.substring(1, name.length());
}
return name;
}

public static BookCode of(String code) {


if (Character.isDigit(code.charAt(0))) {
code = "_" + code;
}
return BookCode.valueOf(code);
}
}

Прочитайте Enum, начиная с номера онлайн: https://riptutorial.com/ru/java/topic/10719/enum--


начиная-с-номера

https://riptutorial.com/ru/home 65
глава 14: FileUpload для AWS
Вступление
Загрузите файл в ведро AWS s3 с использованием API Spring Spring.

Examples

Загрузить файл в корзину s3

Здесь мы создадим отдых APi, который возьмет файл-объект в качестве


параметра multipart из front-end и загрузит его в ведро S3 с помощью java rest
API.

Требование : - секретный ключ и ключ доступа для ведра s3, где вы хотите загрузить
файл.

код: - DocumentController.java

@RestController
@RequestMapping("/api/v2")
public class DocumentController {

private static String bucketName = "pharmerz-chat";


// private static String keyName = "Pharmerz"+ UUID.randomUUID();

@RequestMapping(value = "/upload", method = RequestMethod.POST, consumes =


MediaType.MULTIPART_FORM_DATA)
public URL uploadFileHandler(@RequestParam("name") String name,
@RequestParam("file") MultipartFile file) throws IOException
{

/******* Printing all the possible parameter from @RequestParam *************/

System.out.println("*****************************");

System.out.println("file.getOriginalFilename() " + file.getOriginalFilename());


System.out.println("file.getContentType()" + file.getContentType());
System.out.println("file.getInputStream() " + file.getInputStream());
System.out.println("file.toString() " + file.toString());
System.out.println("file.getSize() " + file.getSize());
System.out.println("name " + name);
System.out.println("file.getBytes() " + file.getBytes());
System.out.println("file.hashCode() " + file.hashCode());
System.out.println("file.getClass() " + file.getClass());
System.out.println("file.isEmpty() " + file.isEmpty());

/*************Parameters to b pass to s3 bucket put Object **************/


InputStream is = file.getInputStream();
String keyName = file.getOriginalFilename();

https://riptutorial.com/ru/home 66
// Credentials for Aws
AWSCredentials credentials = new BasicAWSCredentials("AKIA*************",
"zr**********************");

/****************** DocumentController.uploadfile(credentials);
***************************/

AmazonS3 s3client = new AmazonS3Client(credentials);


try {
System.out.println("Uploading a new object to S3 from a file\n");
//File file = new File(awsuploadfile);
s3client.putObject(new PutObjectRequest(
bucketName, keyName, is, new ObjectMetadata()));

URL url = s3client.generatePresignedUrl(bucketName, keyName,


Date.from(Instant.now().plus(5, ChronoUnit.MINUTES)));
// URL url=s3client.generatePresignedUrl(bucketName,keyName,
Date.from(Instant.now().plus(5, ChronoUnit.)));
System.out.println("************************************");
System.out.println(url);

return url;

} catch (AmazonServiceException ase) {


System.out.println("Caught an AmazonServiceException, which " +
"means your request made it " +
"to Amazon S3, but was rejected with an error response" +
" for some reason.");
System.out.println("Error Message: " + ase.getMessage());
System.out.println("HTTP Status Code: " + ase.getStatusCode());
System.out.println("AWS Error Code: " + ase.getErrorCode());
System.out.println("Error Type: " + ase.getErrorType());
System.out.println("Request ID: " + ase.getRequestId());
} catch (AmazonClientException ace) {
System.out.println("Caught an AmazonClientException, which " +
"means the client encountered " +
"an internal error while trying to " +
"communicate with S3, " +
"such as not being able to access the network.");
System.out.println("Error Message: " + ace.getMessage());
}

return null;

Функция переднего конца

var form = new FormData();


form.append("file", "image.jpeg");

var settings = {
"async": true,
"crossDomain": true,
"url": "http://url/",

https://riptutorial.com/ru/home 67
"method": "POST",
"headers": {
"cache-control": "no-cache"
},
"processData": false,
"contentType": false,
"mimeType": "multipart/form-data",
"data": form
}

$.ajax(settings).done(function (response) {
console.log(response);
});

Прочитайте FileUpload для AWS онлайн: https://riptutorial.com/ru/java/topic/10589/fileupload-


для-aws

https://riptutorial.com/ru/home 68
глава 15: FTP (протокол передачи файлов)
Синтаксис
• Соединение FTPClient (хост InetAddress, int port)
• Логин FTPClient (имя пользователя String, пароль String)
• Отключение FTPClient ()
• FTPReply getReplyStrings ()
• boolean storeFile (String remote, InputStream local)
• Хранилище OutputStreamFileStream (String remote)
• boolean setFileType (int fileType)
• boolean completePendingCommand ()

параметры

параметры подробности

хозяин Либо имя хоста, либо IP-адрес FTP-сервера

порт Порт FTP-сервера

имя пользователя Имя пользователя FTP-сервера

пароль Пароль FTP-сервера

Examples

Подключение и вход в FTP-сервер

Чтобы начать использовать FTP с Java, вам нужно будет создать новый FTPClient а затем
подключиться и войти на сервер с помощью .connect(String server, int port) и .login(String
username, String password) .

import java.io.IOException;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
//Import all the required resource for this project.

public class FTPConnectAndLogin {


public static void main(String[] args) {
// SET THESE TO MATCH YOUR FTP SERVER //
String server = "www.server.com"; //Server can be either host name or IP address.
int port = 21;
String user = "Username";
String pass = "Password";

https://riptutorial.com/ru/home 69
FTPClient ftp = new FTPClient;
ftp.connect(server, port);
ftp.login(user, pass);
}
}

Теперь у нас есть основы. Но что, если у нас есть ошибка подключения к серверу? Мы
хотим знать, когда что-то пойдет не так, и получите сообщение об ошибке. Давайте
добавим код, чтобы поймать ошибки при подключении.

try {
ftp.connect(server, port);
showServerReply(ftp);
int replyCode = ftp.getReplyCode();
if (!FTPReply.isPositiveCompletion(replyCode)) {
System.out.printIn("Operation failed. Server reply code: " + replyCode)
return;
}
ftp.login(user, pass);
} catch {

Давайте сломаем то, что мы только что сделали, шаг за шагом.

showServerReply(ftp);

Это относится к функции, которую мы будем делать на более позднем этапе.

int replyCode = ftp.getReplyCode();

Это захватывает код ответа / ошибки с сервера и сохраняет его как целое.

if (!FTPReply.isPositiveCompletion(replyCode)) {
System.out.printIn("Operation failed. Server reply code: " + replyCode)
return;
}

Это проверяет код ответа, чтобы узнать, была ли ошибка. Если произошла ошибка, она
просто выведет «Операция не выполнена. Код ответа сервера:», за которой следует код
ошибки. Мы также добавили блок try / catch, который мы добавим на следующем шаге.
Затем давайте создадим функцию, которая проверяет ftp.login() наличие ошибок.

boolean success = ftp.login(user, pass);


showServerReply(ftp);
if (!success) {
System.out.println("Failed to log into the server");
return;
} else {
System.out.println("LOGGED IN SERVER");
}

https://riptutorial.com/ru/home 70
Давайте также сломаем этот блок.

boolean success = ftp.login(user, pass);

Это не просто попытка входа на FTP-сервер, но и сохранение результата в виде


логического.

showServerReply(ftp);

Это проверит, посылал ли сервер нам какие-либо сообщения, но сначала нам нужно
создать функцию на следующем шаге.

if (!success) {
System.out.println("Failed to log into the server");
return;
} else {
System.out.println("LOGGED IN SERVER");
}

Этот оператор проверяет, успешно ли мы вошли в систему; если это так, он напечатает «
LOGGED IN SERVER», иначе он напечатает «Не удалось войти в сервер». Это наш скрипт:

import java.io.IOException;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;

public class FTPConnectAndLogin {


public static void main(String[] args) {
// SET THESE TO MATCH YOUR FTP SERVER //
String server = "www.server.com";
int port = 21;
String user = "username"
String pass = "password"

FTPClient ftp = new FTPClient


try {
ftp.connect(server, port)
showServerReply(ftp);
int replyCode = ftpClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(replyCode)) {
System.out.println("Operation failed. Server reply code: " + replyCode);
return;
}
boolean success = ftp.login(user, pass);
showServerReply(ftp);
if (!success) {
System.out.println("Failed to log into the server");
return;
} else {
System.out.println("LOGGED IN SERVER");
}
} catch {

}
}

https://riptutorial.com/ru/home 71
}

Теперь давайте создадим полный блок Catch, если мы столкнемся с любыми ошибками
всего процесса.

} catch (IOException ex) {


System.out.println("Oops! Something went wrong.");
ex.printStackTrace();
}

Завершенный блок блокировки теперь будет печатать «Ой, что-то пошло не так». и
stacktrace, если есть ошибка. Теперь наш последний шаг - создать showServerReply() мы
использовали некоторое время.

private static void showServerReply(FTPClient ftp) {


String[] replies = ftp.getReplyStrings();
if (replies != null && replies.length > 0) {
for (String aReply : replies) {
System.out.println("SERVER: " + aReply);
}
}
}

Эта функция принимает FTPClient как переменную и называет ее «ftp». После этого он
хранит любые серверные ответы с сервера в массиве строк. Затем он проверяет,
сохранены ли какие-либо сообщения. Если он есть, он печатает каждый из них как
«СЕРВЕР: [ответ]». Теперь, когда мы выполнили эту функцию, это завершенный скрипт:

import java.io.IOException;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;

public class FTPConnectAndLogin {


private static void showServerReply(FTPClient ftp) {
String[] replies = ftp.getReplyStrings();
if (replies != null && replies.length > 0) {
for (String aReply : replies) {
System.out.println("SERVER: " + aReply);
}
}
}

public static void main(String[] args) {


// SET THESE TO MATCH YOUR FTP SERVER //
String server = "www.server.com";
int port = 21;
String user = "username"
String pass = "password"

FTPClient ftp = new FTPClient


try {
ftp.connect(server, port)
showServerReply(ftp);
int replyCode = ftpClient.getReplyCode();

https://riptutorial.com/ru/home 72
if (!FTPReply.isPositiveCompletion(replyCode)) {
System.out.println("Operation failed. Server reply code: " + replyCode);
return;
}
boolean success = ftp.login(user, pass);
showServerReply(ftp);
if (!success) {
System.out.println("Failed to log into the server");
return;
} else {
System.out.println("LOGGED IN SERVER");
}
} catch (IOException ex) {
System.out.println("Oops! Something went wrong.");
ex.printStackTrace();
}
}
}

Сначала нам нужно создать новый FTPClient и попробовать подключиться к серверу и


войти в него с помощью .connect(String server, int port) и .login(String username, String
password) . Важно подключиться и войти в систему с помощью блока try / catch, если наш код
не сможет подключиться к серверу. Нам также необходимо создать функцию, которая
проверяет и отображает любые сообщения, которые мы можем получать с сервера, когда
мы пытаемся подключиться и войти в систему. Мы будем называть эту функцию «
showServerReply(FTPClient ftp) ».

import java.io.IOException;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;

public class FTPConnectAndLogin {


private static void showServerReply(FTPClient ftp) {
if (replies != null && replies.length > 0) {
for (String aReply : replies) {
System.out.println("SERVER: " + aReply);
}
}
}

public static void main(String[] args) {


// SET THESE TO MATCH YOUR FTP SERVER //
String server = "www.server.com";
int port = 21;
String user = "username"
String pass = "password"

FTPClient ftp = new FTPClient


try {
ftp.connect(server, port)
showServerReply(ftp);
int replyCode = ftpClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(replyCode)) {
System.out.println("Operation failed. Server reply code: " + replyCode);
return;
}
boolean success = ftp.login(user, pass);

https://riptutorial.com/ru/home 73
showServerReply(ftp);
if (!success) {
System.out.println("Failed to log into the server");
return;
} else {
System.out.println("LOGGED IN SERVER");
}
} catch (IOException ex) {
System.out.println("Oops! Something went wrong.");
ex.printStackTrace();
}
}
}

После этого вы должны теперь подключить свой FTP-сервер к вам Java-скрипту.

Прочитайте FTP (протокол передачи файлов) онлайн:


https://riptutorial.com/ru/java/topic/5228/ftp--протокол-передачи-файлов-

https://riptutorial.com/ru/home 74
глава 16: HttpURLConnection
замечания
• Использование HttpUrlConnection на Android требует, чтобы вы добавили разрешение
на доступ в Интернет для своего приложения (в AndroidManifest.xml ).

• Существуют также другие Java-HTTP-клиенты и библиотеки, такие как OkHttp Square,


которые более удобны в использовании и могут обеспечить лучшую
производительность или больше возможностей.

Examples

Получить тело ответа из URL-адреса в виде строки

String getText(String url) throws IOException {


HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
//add headers to the connection, or check the status if desired..

// handle error response code it occurs


int responseCode = conn.getResponseCode();
InputStream inputStream;
if (200 <= responseCode && responseCode <= 299) {
inputStream = connection.getInputStream();
} else {
inputStream = connection.getErrorStream();
}

BufferedReader in = new BufferedReader(


new InputStreamReader(
inputStream));

StringBuilder response = new StringBuilder();


String currentLine;

while ((currentLine = in.readLine()) != null)


response.append(currentLine);

in.close();

return response.toString();
}

Это будет загружать текстовые данные из указанного URL-адреса и возвращать их как


строку.

Как это работает:

• Во-первых, мы создаем HttpUrlConnection из нашего URL-адреса с new


URL(url).openConnection() . Мы UrlConnection это возвращает HttpUrlConnection , поэтому у

https://riptutorial.com/ru/home 75
нас есть доступ к таким вещам, как добавление заголовков (например, User Agent) или
проверка кода ответа. (Этот пример не делает этого, но его легко добавить.)

• Затем создайте InputStream на основе кода ответа (для обработки ошибок)

• Затем создайте BufferedReader который позволяет нам читать текст из InputStream мы


получаем из соединения.

• Теперь мы добавляем текст в StringBuilder последовательно.

• Закройте InputStream и верните строку, которую мы теперь имеем.

Заметки:

• Этот метод будет генерировать IoException в случае сбоя (например, сетевую ошибку
или отсутствие подключения к Интернету), а также исключить исключение
MalformedUrlException если данный URL-адрес недействителен.

• Его можно использовать для чтения с любого URL-адреса, который возвращает


текст, например веб-страницы (HTML), API REST, которые возвращают JSON или XML
и т. Д.

• См. Также: Прочитать URL-адрес строки в нескольких строках кода Java .

Использование:

Очень просто:

String text = getText(”http://example.com");


//Do something with the text from example.com, in this case the HTML.

Данные POST

public static void post(String url, byte [] data, String contentType) throws IOException {
HttpURLConnection connection = null;
OutputStream out = null;
InputStream in = null;

try {
connection = (HttpURLConnection) new URL(url).openConnection();
connection.setRequestProperty("Content-Type", contentType);
connection.setDoOutput(true);

out = connection.getOutputStream();
out.write(data);
out.close();

in = connection.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line = null;
while ((line = reader.readLine()) != null) {

https://riptutorial.com/ru/home 76
System.out.println(line);
}
in.close();

} finally {
if (connection != null) connection.disconnect();
if (out != null) out.close();
if (in != null) in.close();
}
}

Это будет POST-данных для указанного URL-адреса, а затем прочитайте ответ по


очереди.

Как это устроено


• Как обычно, мы получаем HttpURLConnection из URL .
• Задайте тип содержимого с помощью setRequestProperty , по умолчанию это
application/x-www-form-urlencoded
• setDoOutput(true) сообщает подключению, что мы будем отправлять данные.
• Затем мы получаем OutputStream , вызывая getOutputStream() и записывая данные на
него. Не забудьте закрыть его после завершения.
• Наконец, мы читаем ответ сервера.

Удалить ресурс

public static void delete (String urlString, String contentType) throws IOException {
HttpURLConnection connection = null;

try {
URL url = new URL(urlString);
connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.setRequestMethod("DELETE");
connection.setRequestProperty("Content-Type", contentType);

Map<String, List<String>> map = connection.getHeaderFields();


StringBuilder sb = new StringBuilder();
Iterator<Map.Entry<String, String>> iterator =
responseHeader.entrySet().iterator();
while(iterator.hasNext())
{
Map.Entry<String, String> entry = iterator.next();
sb.append(entry.getKey());
sb.append('=').append('"');
sb.append(entry.getValue());
sb.append('"');
if(iterator.hasNext())
{
sb.append(',').append(' ');
}
}
System.out.println(sb.toString());

https://riptutorial.com/ru/home 77
} catch (Exception e) {
e.printStackTrace();
} finally {
if (connection != null) connection.disconnect();
}
}

Это УДАЛИТЬ ресурс в указанном URL-адресе, а затем распечатает заголовок ответа.

Как это устроено


• мы получаем HttpURLConnection из URL .
• Задайте тип содержимого с помощью setRequestProperty , по умолчанию это
application/x-www-form-urlencoded
• сообщает о соединении, которое мы намерены использовать для
setDoInput(true)
ввода URL-адреса.
• setRequestMethod("DELETE") для выполнения HTTP DELETE

Наконец, мы печатаем заголовок ответа сервера.

Проверьте, существует ли ресурс

/**
* Checks if a resource exists by sending a HEAD-Request.
* @param url The url of a resource which has to be checked.
* @return true if the response code is 200 OK.
*/
public static final boolean checkIfResourceExists(URL url) throws IOException {
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("HEAD");
int code = conn.getResponseCode();
conn.disconnect();
return code == 200;
}

Объяснение:
Если вы просто проверяете, существует ли ресурс, лучше использовать запрос HEAD, чем
GET. Это позволяет избежать накладных расходов на передачу ресурса.

Обратите внимание, что метод возвращает true если код ответа 200 . Если вы ожидаете
ответа на перенаправление (т. Е. 3XX), то, возможно, этот способ может быть усилен для
их соблюдения.

Пример:

https://riptutorial.com/ru/home 78
checkIfResourceExists(new URL("http://images.google.com/")); // true
checkIfResourceExists(new URL("http://pictures.google.com/")); // false

Прочитайте HttpURLConnection онлайн:


https://riptutorial.com/ru/java/topic/156/httpurlconnection

https://riptutorial.com/ru/home 79
глава 17: InputStreams и OutputStreams
Синтаксис
• int read (byte [] b) выбрасывает IOException

замечания
Обратите внимание, что большую часть времени вы НЕ используете InputStream s напрямую,
но используете BufferedStream или похожи. Это связано с тем, что InputStream считывает из
источника каждый раз при вызове метода чтения. Это может вызвать значительное
использование ЦП в контекстных коммутаторах в ядре и из него.

Examples

Чтение InputStream в строку

Иногда вы можете читать байтовый ввод в String. Для этого вам нужно будет найти что-то,
что преобразует между byte и «родной Java» UTF-16 Codepoints, используемым как char .
Это делается с помощью InputStreamReader .

Чтобы немного ускорить процесс, «обычным» является выделение буфера, так что у нас не
слишком много накладных расходов при чтении с Input.

Java SE 7

public String inputStreamToString(InputStream inputStream) throws Exception {


StringWriter writer = new StringWriter();

char[] buffer = new char[1024];


try (Reader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"))) {
int n;
while ((n = reader.read(buffer)) != -1) {
// all this code does is redirect the output of `reader` to `writer` in
// 1024 byte chunks
writer.write(buffer, 0, n);
}
}
return writer.toString();
}

Преобразование этого примера в Java SE 6 (и более низкий) совместимый код не


учитывается как упражнение для читателя.

Запись байтов в OutputStream

https://riptutorial.com/ru/home 80
Запись байтов в OutputStream одному байту за раз

OutputStream stream = object.getOutputStream();

byte b = 0x00;
stream.write( b );

Запись байтового массива

byte[] bytes = new byte[] { 0x00, 0x00 };

stream.write( bytes );

Написание раздела массива байтов

int offset = 1;
int length = 2;
byte[] bytes = new byte[] { 0xFF, 0x00, 0x00, 0xFF };

stream.write( bytes, offset, length );

Закрытие потоков

Большинство потоков необходимо закрыть, когда вы закончите с ними, иначе вы можете


ввести утечку памяти или оставить файл открытым. Важно, чтобы потоки были закрыты,
даже если выбрано исключение.

Java SE 7

try(FileWriter fw = new FileWriter("outfilename");


BufferedWriter bw = new BufferedWriter(fw);
PrintWriter out = new PrintWriter(bw))
{
out.println("the text");
//more code
out.println("more text");
//more code
} catch (IOException e) {
//handle this however you
}

Помните: try-with-resources гарантирует, что ресурсы были закрыты при выходе из блока,
независимо от того, происходит ли это с обычным потоком управления или из-за
исключения.

Java SE 6

Иногда попробовать-с-ресурсами не вариант, или, может быть, вы поддерживаете более


старую версию Java 6 или ранее. В этом случае правильная обработка заключается в
использовании блока finally :

https://riptutorial.com/ru/home 81
FileWriter fw = null;
BufferedWriter bw = null;
PrintWriter out = null;
try {
fw = new FileWriter("myfile.txt");
bw = new BufferedWriter(fw);
out = new PrintWriter(bw);
out.println("the text");
out.close();
} catch (IOException e) {
//handle this however you want
}
finally {
try {
if(out != null)
out.close();
} catch (IOException e) {
//typically not much you can do here...
}
}

Обратите внимание, что закрытие потока оболочки также закрывает его базовый поток.
Это означает, что вы не можете обернуть поток, закрыть оболочку и продолжить
использование исходного потока.

Копирование входного потока в выходной поток

Эта функция копирует данные между двумя потоками -

void copy(InputStream in, OutputStream out) throws IOException {


byte[] buffer = new byte[8192];
while ((bytesRead = in.read(buffer)) > 0) {
out.write(buffer, 0, bytesRead);
}
}

Пример -

// reading from System.in and writing to System.out


copy(System.in, System.out);

Обтекание потоков ввода / вывода

и InputStream имеют много разных классов, каждый из которых обладает


OutputStream
уникальной функциональностью. Обертывая поток вокруг другого, вы получаете
функциональность обоих потоков.

Вы можете обтекать поток сколько угодно раз, просто обратите внимание на порядок.

Полезные комбинации

https://riptutorial.com/ru/home 82
Запись символов в файл при использовании буфера

File myFile = new File("targetFile.txt");


PrintWriter writer = new PrintWriter(new BufferedOutputStream(new FileOutputStream(myFile)));

Сжатие и шифрование данных перед записью в файл при использовании буфера

Cipher cipher = ... // Initialize cipher


File myFile = new File("targetFile.enc");
BufferedOutputStream outputStream = new BufferedOutputStream(new DeflaterOutputStream(new
CipherOutputStream(new FileOutputStream(myFile), cipher)));

Список оберток потока ввода / вывода


обертка Описание

В то время как OutputStream записывает данные по одному


BufferedOutputStream / байту за один раз, BufferedOutputStream записывает данные
BufferedInputStream в куски. Это уменьшает количество системных вызовов,
что повышает производительность.

DeflaterOutputStream /
Выполняет сжатие данных.
DeflaterInputStream

InflaterOutputStream /
Выполняет декомпрессию данных.
InflaterInputStream

CipherOutputStream /
Шифрует / расшифровывает данные.
CipherInputStream

DigestOutputStream / Генерирует дайджест сообщений для проверки


DigestInputStream целостности данных.

CheckedOutputStream / Создает CheckSum. CheckSum - это более тривиальная


CheckedInputStream версия Message Digest.

Позволяет писать примитивные типы данных и строки.


DataOutputStream /
Предназначен для написания байтов. Независимая
DataInputStream
платформа.

Позволяет писать примитивные типы данных и строки.


PrintStream
Предназначен для написания байтов. Платформа зависит.

Преобразует OutputStream в Writer. OutputStream имеет


OutputStreamWriter дело с байтами, в то время как Writers имеет дело с
символами

https://riptutorial.com/ru/home 83
обертка Описание

Автоматически вызывает OutputStreamWriter. Позволяет


PrintWriter писать примитивные типы данных и строки. Строго для
написания символов и лучше всего писать символы

Пример DataInputStream

package com.streams;
import java.io.*;
public class DataStreamDemo {
public static void main(String[] args) throws IOException {
InputStream input = new FileInputStream("D:\\datastreamdemo.txt");
DataInputStream inst = new DataInputStream(input);
int count = input.available();
byte[] arr = new byte[count];
inst.read(arr);
for (byte byt : arr) {
char ki = (char) byt;
System.out.print(ki+"-");
}
}
}

Прочитайте InputStreams и OutputStreams онлайн:


https://riptutorial.com/ru/java/topic/110/inputstreams-и-outputstreams

https://riptutorial.com/ru/home 84
глава 18: Java Pitfalls - использование
исключений
Вступление
Некоторые нарушения языка программирования Java могут выполнять программу для
получения неправильных результатов, несмотря на то, что они правильно составлены.
Основная цель этого раздела - перечислить общие ошибки, связанные с обработкой
исключений , и предложить правильный способ избежать таких ошибок.

Examples

Pitfall - Игнорирование или сбой исключений

В этом примере речь идет об умышленном игнорировании или «раздавливании»


исключений. Или, точнее, речь идет о том, как поймать и обработать исключение таким
образом, чтобы его игнорировать. Тем не менее, прежде чем мы опишем, как это сделать,
мы должны сначала указать, что исключение от раздавливания, как правило, не является
правильным способом борьбы с ними.

Исключения обычно забрасываются (кем-то), чтобы уведомить другие части программы о


том, что произошло какое-то значительное (то есть «исключительное») событие. Вообще
(хотя и не всегда) исключение означает, что что-то пошло не так. Если вы закодируете
свою программу для выдачи исключения, есть вероятность, что проблема снова появится в
другой форме. Чтобы ухудшить ситуацию, когда вы выкалываете исключение, вы
выбрасываете информацию в объекте исключения и связанной с ним трассировке стека.
Скорее всего, это затруднит выяснение того, каков был исходный источник проблемы.

На практике, при использовании функции автоматической коррекции IDE, «исправление»


ошибки компиляции, вызванной необработанным исключением, часто происходит сбой при
сбоях. Например, вы можете увидеть такой код:

try {
inputStream = new FileInputStream("someFile");
} catch (IOException e) {
/* add exception handling code here */
}

Ясно, что программист принял предложение IDE, чтобы ошибка компиляции исчезла, но
предложение было неуместным. (Если файл открылся не сработал, программа, скорее
всего, что-то с этим inputStream . С приведенной выше «коррекцией» программа может
потерпеть неудачу позже, например, с помощью NullPointerException поскольку inputStream

https://riptutorial.com/ru/home 85
теперь имеет значение null .)

Сказав это, вот пример умышленного подавления исключения. (В целях аргумента


предположим, что мы определили, что прерывание при показе самообороны является
безвредным.) Комментарий говорит читателю, что мы сознательно раздавили исключение
и почему мы это сделали.

try {
selfie.show();
} catch (InterruptedException e) {
// It doesn't matter if showing the selfie is interrupted.
}

Другой общепринятый способ подчеркнуть, что мы намеренно подавляем исключение, не


говоря о том, почему нужно указывать это с именем переменной исключения, например:

try {
selfie.show();
} catch (InterruptedException ignored) { }

Некоторые IDE (например, IntelliJ IDEA) не будут отображать предупреждение о пустом


блоке catch, если имя переменной установлено на ignored .

Pitfall - Catching Throwable, Exception, Error или RuntimeException

Общим шаблоном мыслей для неопытных программистов на Java является то, что
исключения - это «проблема» или «бремя», и лучший способ справиться с этим - как можно
скорее поймать их всех 1 . Это приводит к следующему коду:

....
try {
InputStream is = new FileInputStream(fileName);
// process the input
} catch (Exception ex) {
System.out.println("Could not open file " + fileName);
}

Вышеприведенный код имеет значительный недостаток. catch на самом деле поймает


больше исключений, чем ожидает программист. Предположим, что значение fileName равно
null из-за ошибки в другом месте приложения. Это заставит конструктор FileInputStream
выкинуть FileInputStream NullPointerException . Обработчик поймает это и сообщит
пользователю:

Could not open file null

что бесполезно и запутанно. Хуже того, предположим, что это был код «процесс ввода»,
который выдал неожиданное исключение (отмечено или не отмечено!). Теперь
пользователь получит сообщение об ошибке для проблемы, которая не возникла при

https://riptutorial.com/ru/home 86
открытии файла, и вообще не может быть связана с I / O.

Корень проблемы заключается в том, что программист закодировал обработчик для


Exception . Это почти всегда ошибка:

• Catching Exception поймает все проверенные исключения и большинство


непроверенных исключений.
• Catching RuntimeException большинство непроверенных исключений.
• Error Catching Error будет проверять неконтролируемые исключения, которые
сигнализируют внутренние ошибки JVM. Эти ошибки, как правило, не подлежат
восстановлению и не должны быть пойманы.
• Catching Throwable поймает все возможные исключения.

Проблема с улавливанием слишком широкого набора исключений заключается в том, что


обработчик обычно не может обрабатывать все из них соответствующим образом. В случае
Exception и т. Д. Программисту сложно предсказать, что можно поймать; т.е. чего ожидать.

В общем, правильное решение , чтобы иметь дело с исключениями , которые


выбрасываются. Например, вы можете поймать их и обработать их на месте:

try {
InputStream is = new FileInputStream(fileName);
// process the input
} catch (FileNotFoundException ex) {
System.out.println("Could not open file " + fileName);
}

или вы можете объявить их как thrown приложенным методом.

Очень мало ситуаций, когда ловушка Exception подходит. Единственное, что возникает
обычно, это что-то вроде этого:

public static void main(String[] args) {


try {
// do stuff
} catch (Exception ex) {
System.err.println("Unfortunately an error has occurred. " +
"Please report this to X Y Z");
// Write stacktrace to a log file.
System.exit(1);
}
}

Здесь мы действительно хотим иметь дело со всеми исключениями, поэтому Throwable


Exception (или даже Throwable ) верна.

1 - Также известен как Покемон Исключение обработки .

https://riptutorial.com/ru/home 87
Pitfall - Бросание Throwable, Exception, Error или RuntimeException

Хотя Throwable Exception Throwable , Exception , Error и RuntimeException является плохим,


бросать их еще хуже.

Основная проблема заключается в том, что когда ваше приложение должно обрабатывать
исключения, наличие исключений верхнего уровня затрудняет различение различных
условий ошибки. Например

try {
InputStream is = new FileInputStream(someFile); // could throw IOException
...
if (somethingBad) {
throw new Exception(); // WRONG
}
} catch (IOException ex) {
System.err.println("cannot open ...");
} catch (Exception ex) {
System.err.println("something bad happened"); // WRONG
}

Проблема в том, что, поскольку мы Exception экземпляр Exception , мы вынуждены его


поймать. Однако, как описано в другом примере, catching Exception является плохим. В этой
ситуации становится трудно различать «ожидаемый» случай Exception который
генерируется, если somethingBad true , и непредвиденный случай, когда мы фактически
поймаем неконтролируемое исключение, такое как NullPointerException .

Если исключение верхнего уровня разрешено распространять, мы сталкиваемся с другими


проблемами:

• Теперь мы должны помнить все разные причины, по которым мы выбрали верхний


уровень и дискриминируем / обрабатываем их.
• В случае Exception и Throwable нам также необходимо добавить эти исключения в
предложение throws методов, если мы хотим, чтобы исключение распространялось.
Это проблематично, как описано ниже.

Короче говоря, не бросайте эти исключения. Бросьте более конкретное исключение,


которое более подробно описывает «исключительное событие», которое произошло. Если
вам нужно, определите и используйте специальный класс исключений.

Объявление Throwable или Exception в «бросках» метода


проблематично.
Заманчиво заменить длинный список исключенных исключений в предложение throws
метода с Exception или даже Throwable. Это плохая идея:

1. Это заставляет вызывающего абонента обрабатывать (или распространять) Exception .

https://riptutorial.com/ru/home 88
2. Мы больше не можем полагаться на компилятор, чтобы рассказать нам о конкретных
проверенных исключениях, которые необходимо обработать.
3. Обработка Exception должным образом затруднено. Трудно понять, какие
фактические исключения могут быть пойманы, и если вы не знаете, что можно
поймать, трудно понять, какая стратегия восстановления подходит.
4. Обработка Throwable еще сложнее, так как теперь вы также должны справляться с
потенциальными сбоями, которые никогда не должны восстанавливаться.

Этот совет означает, что некоторые другие шаблоны следует избегать. Например:

try {
doSomething();
} catch (Exception ex) {
report(ex);
throw ex;
}

Вышеупомянутые попытки регистрировать все исключения по мере их прохождения, без


окончательного обращения с ними. К сожалению, до Java 7, throw ex; заявление заставило
компилятор думать, что любое Exception может быть выброшено. Это может заставить вас
объявить вложенный метод как throws Exception . Начиная с Java 7 компилятор знает, что
набор исключений, которые могут быть (переброшены), меньше.

Pitfall - Catching InterruptedException

Как уже указывалось в других ловушках, ловя все исключения, используя

try {
// Some code
} catch (Exception) {
// Some error handling
}

Поставляется с множеством разных проблем. Но одна из проблем заключается в том, что


это может привести к взаимоблокировкам, поскольку он разбивает систему прерываний
при написании многопоточных приложений.

Если вы начинаете нить, вы также должны быть в состоянии остановить ее внезапно по


разным причинам.

Thread t = new Thread(new Runnable() {


public void run() {
while (true) {
//Do something indefinetely
}
}
}

t.start();

https://riptutorial.com/ru/home 89
//Do something else

// The thread should be canceld if it is still active.


// A Better way to solve this is with a shared variable that is tested
// regularily by the thread for a clean exit, but for this example we try to
// forcibly interrupt this thread.
if (t.isAlive()) {
t.interrupt();
t.join();
}

//Continue with program

приведет к t.interrupt() InterruptedException в этом потоке, чем предназначен


t.interrupt()
для отключения потока. Но что, если Thread должен очистить некоторые ресурсы до того,
как он полностью остановится? Для этого он может поймать InterruptedException и
выполнить некоторую очистку.

Thread t = new Thread(new Runnable() {


public void run() {
try {
while (true) {
//Do something indefinetely
}
} catch (InterruptedException ex) {
//Do some quick cleanup

// In this case a simple return would do.


// But if you are not 100% sure that the thread ends after
// catching the InterruptedException you will need to raise another
// one for the layers surrounding this code.
Thread.currentThread().interrupt();
}
}
}

Но если у вас есть выражение catch-all в вашем коде, InterruptedException также будет
поймано им, и прерывание не продолжится. Который в этом случае может привести к
тупиковой ситуации, поскольку родительский поток ждет бесконечно, чтобы этот ада
остановился на t.join() .

Thread t = new Thread(new Runnable() {


public void run() {
try {
while (true) {
try {
//Do something indefinetely
}
catch (Exception ex) {
ex.printStackTrace();
}
}
} catch (InterruptedException ex) {
// Dead code as the interrupt exception was already caught in
// the inner try-catch
Thread.currentThread().interrupt();

https://riptutorial.com/ru/home 90
}
}
}

Так что лучше поймать Исключения отдельно, но если вы настаиваете на использовании


catch-all, по крайней мере, поймите InterruptedException индивидуально заранее.

Thread t = new Thread(new Runnable() {


public void run() {
try {
while (true) {
try {
//Do something indefinetely
} catch (InterruptedException ex) {
throw ex; //Send it up in the chain
} catch (Exception ex) {
ex.printStackTrace();
}
}
} catch (InterruptedException ex) {
// Some quick cleanup code

Thread.currentThread().interrupt();
}
}
}

Pitfall - Использование исключений для нормального управления потоком

Существует мантра, которую некоторые специалисты Java обычно читают:

«Исключения должны использоваться только в исключительных случаях».

(Например: http://programmers.stackexchange.com/questions/184654 )

Суть этого в том, что это плохая идея (в Java) использовать исключения и обработку
исключений для реализации нормального управления потоком. Например, сравните эти
два способа обращения с параметром, который может быть нулевым.

public String truncateWordOrNull(String word, int maxLength) {


if (word == null) {
return "";
} else {
return word.substring(0, Math.min(word.length(), maxLength));
}
}

public String truncateWordOrNull(String word, int maxLength) {


try {
return word.substring(0, Math.min(word.length(), maxLength));
} catch (NullPointerException ex) {
return "";
}
}

https://riptutorial.com/ru/home 91
В этом примере мы (по дизайну) рассматриваем случай, когда word равно null как будто это
пустое слово. Две версии имеют значение null либо с использованием обычных if ... else,
либо try ... catch . Как нам решить, какая версия лучше?

Первый критерий - читаемость. Хотя читаемость трудно объективно определить


количественно, большинство программистов согласятся с тем, что существенный смысл
первой версии легче распознать. Действительно, чтобы действительно понять вторую
форму, вам нужно понять, что Math.min NullPointerException не может быть String.substring
методами Math.min или String.substring .

Второй критерий - эффективность. В версиях Java до Java 8 вторая версия значительно


(на порядки) медленнее первой версии. В частности, построение объекта исключения
влечет за собой захват и запись стековых кадров, на всякий случай, если требуется стек.

С другой стороны, существует множество ситуаций, когда использование исключений


является более читаемым, более эффективным и (иногда) более правильным, чем
использование условного кода для обработки «исключительных» событий. Действительно,
есть редкие ситуации, когда необходимо использовать их для «не исключительных»
событий; т.е. события, которые происходят относительно часто. Для последнего стоит
взглянуть на способы сокращения накладных расходов на создание объектов исключений.

Pitfall - чрезмерные или неуместные стеки

Одним из наиболее неприятных вещей, которые могут сделать программисты, является


разброс вызовов printStackTrace() во всем их коде.

Проблема заключается в том, что printStackTrace() будет писать stacktrace для


стандартного вывода.

• Для приложения, предназначенного для конечных пользователей, которые не


являются Java-программистами, stacktrace в лучшем случае неинформативна и в
худшем случае вызывает тревогу.

• Вероятно, для серверного приложения никто не будет смотреть на стандартный


вывод.

Лучше всего не вызывать printStackTrace напрямую, или если вы вызываете его, сделайте
это так, чтобы трассировка стека была записана в файл журнала или файл ошибки, а не
на консоль конечного пользователя.

Один из способов сделать это - использовать структуру ведения журнала и передать


объект исключения в качестве параметра события журнала. Однако даже регистрация
исключений может быть вредной, если это было сделано вредно. Рассмотрим следующее:

public void method1() throws SomeException {


try {

https://riptutorial.com/ru/home 92
method2();
// Do something
} catch (SomeException ex) {
Logger.getLogger().warn("Something bad in method1", ex);
throw ex;
}
}

public void method2() throws SomeException {


try {
// Do something else
} catch (SomeException ex) {
Logger.getLogger().warn("Something bad in method2", ex);
throw ex;
}
}

Если исключение method2 в method2 , вы, вероятно, увидите два экземпляра одной и той же
stacktrace в файле журнала, что соответствует тому же отказу.

Короче говоря, либо регистрируйте исключение, либо повторно бросайте его (возможно,
завернутое с другим исключением). Не делай того и другого.

Pitfall - прямое подклассирование «Throwable»

имеет два прямых подкласса: Exception и Error . Хотя можно создать новый класс,
Throwable
который напрямую расширяет Throwable , это нецелесообразно, так как многие приложения
предполагают, что существуют только Exception и Error .

Более того, нет практической выгоды для прямого подкласса Throwable , поскольку
полученный класс, по сути, просто проверенное исключение. В противном случае Exception
подкласса приведет к такому же поведению, но будет более четко передавать ваши
намерения.

Прочитайте Java Pitfalls - использование исключений онлайн:


https://riptutorial.com/ru/java/topic/5381/java-pitfalls---использование-исключений

https://riptutorial.com/ru/home 93
глава 19: Java Pitfalls - синтаксис языка
Вступление
Некоторые нарушения языка программирования Java могут выполнять программу для
получения неправильных результатов, несмотря на то, что они правильно составлены.
Основной темой этой темы является список распространенных ошибок с их причинами и
предложение правильного способа избежать таких проблем.

замечания
В этом разделе рассматриваются конкретные аспекты синтаксиса языка Java, которые
либо подвержены ошибкам, либо не могут использоваться определенным образом.

Examples

Pitfall - игнорирование видимости метода

Даже опытные разработчики Java склонны думать, что Java имеет только три
модификатора защиты. На самом деле у этого языка четыре! Частый (видимо, обычный)
уровень видимости часто забывается.

Вы должны обратить внимание на то, какие методы вы публикуете. Публичные методы в


приложении - это видимый API приложения. Это должно быть как можно меньше и
компактнее, особенно если вы пишете библиотеку многократного использования (см.
Также принцип SOLID ). Важно также учитывать наглядность всех методов и
использовать только защищенный или пакетный доступ, если это необходимо.

Когда вы объявляете методы, которые должны быть закрытыми как общедоступные, вы


раскрываете внутренние детали реализации этого класса.

Следствием этого является то, что вы проверяете только публичные методы своего класса
- на самом деле вы можете тестировать только общедоступные методы. Плохая практика
заключается в повышении видимости частных методов, чтобы иметь возможность
запускать единичные тесты против этих методов. Тестирование общедоступных методов,
которые вызывают методы с более ограничительной видимостью, должно быть
достаточным для тестирования всего API. Вы никогда не должны расширять свой API
более публичными методами только для модульного тестирования.

Pitfall - Отсутствие «перерыва» в случае «переключения»

Эти проблемы с Java могут быть очень смущающими и иногда оставаться неоткрытыми до

https://riptutorial.com/ru/home 94
тех пор, пока они не будут запущены в производство. Эффективное поведение в
операторах switch часто полезно; однако отсутствие ключевого слова «break», когда такое
поведение нежелательно, может привести к катастрофическим результатам. Если вы
забыли поставить «break» в «case 0» в приведенном ниже примере кода, программа
напишет «Zero», а затем «One», так как поток управления внутри здесь будет проходить
весь оператор «switch» до тех пор, пока он достигает «перерыва». Например:

public static void switchCasePrimer() {


int caseIndex = 0;
switch (caseIndex) {
case 0:
System.out.println("Zero");
case 1:
System.out.println("One");
break;
case 2:
System.out.println("Two");
break;
default:
System.out.println("Default");
}
}

В большинстве случаев чище решение было бы использовать интерфейсы и перемещать


код с определенным поведением в отдельные реализации ( состав над наследованием )

Если оператор switch неизбежен, рекомендуется документировать «ожидаемые»


всплытия, если они происходят. Таким образом, вы показываете коллегам-разработчикам,
что знаете о недостающем разрыве и что это ожидаемое поведение.

switch(caseIndex) {
[...]
case 2:
System.out.println("Two");
// fallthrough
default:
System.out.println("Default");

Pitfall - Пункты с запятой и отсутствующие фигурные скобки

Это ошибка, которая вызывает реальную путаницу для начинающих Java, по крайней мере,
в первый раз, когда они это делают. Вместо того, чтобы писать это:

if (feeling == HAPPY)
System.out.println("Smile");
else
System.out.println("Frown");

они случайно пишут это:

if (feeling == HAPPY);

https://riptutorial.com/ru/home 95
System.out.println("Smile");
else
System.out.println("Frown");

и недоумевают, когда компилятор Java сообщает им, что else неуместно. Компилятор Java с
интерпретированием выше:

if (feeling == HAPPY)
/*empty statement*/ ;
System.out.println("Smile"); // This is unconditional
else // This is misplaced. A statement cannot
// start with 'else'
System.out.println("Frown");

В других случаях ошибки компиляции не будут, но код не будет делать то, что
намеревается программист. Например:

for (int i = 0; i < 5; i++);


System.out.println("Hello");

только печатает «Привет» один раз. Опять же паразитная точка с запятой означает, что
тело цикла for представляет собой пустой оператор. Это означает, что следующий вызов
println является безусловным.

Другой вариант:

for (int i = 0; i < 5; i++);


System.out.println("The number is " + i);

Это даст ошибку «Не могу найти символ» для i . Наличие ложной точки с запятой
означает, что вызов println пытается использовать i вне его области видимости.

В этих примерах есть прямолинейное решение: просто удалите ложную точку с запятой.
Однако из этих примеров можно извлечь более глубокие уроки:

1. Точка с запятой в Java не является «синтаксическим шумом». Наличие или отсутствие


точки с запятой может изменить смысл вашей программы. Не добавляйте их в конце
каждой строки.

2. Не доверяйте отступу вашего кода. В языке Java лишние пробелы в начале строки
игнорируются компилятором.

3. Используйте автоматический индентор. Все IDE и многие простые текстовые


редакторы понимают, как правильно отступать код Java.

4. Это самый важный урок. Следуйте последним рекомендациям стиля Java и поместите
фигурные скобки вокруг операторов «then» и «else» и оператора body цикла.
Открытая скобка ( { ) не должна быть на новой строке.

https://riptutorial.com/ru/home 96
Если программист следовал правилам стиля, то пример if с неуместными точками с
запятой выглядел бы так:

if (feeling == HAPPY); {
System.out.println("Smile");
} else {
System.out.println("Frown");
}

Это выглядит странно для опытного глаза. Если вы автоматически отступом этот код, он,
вероятно, будет выглядеть так:

if (feeling == HAPPY); {
System.out.println("Smile");
} else {
System.out.println("Frown");
}

который должен выделиться как неудачный даже для новичков.

Pitfall - Оставляя брекеты: проблемы с «болтающимися, если» и


«болтающимися»

В последней версии руководства по стилю Java Java указано, что операторы «then» и «
else» в операторе if всегда должны быть заключены в «фигурные скобки» или «фигурные
скобки». Аналогичные правила применяются к телам различных операторов цикла.

if (a) { // <- open brace


doSomething();
doSomeMore();
} // <- close brace

Синтаксис языка Java на самом деле не требуется. В самом деле, если «то» часть
оператора if является единственным выражением, то законно оставить фигурные скобки

if (a)
doSomething();

или даже

if (a) doSomething();

Однако есть опасность игнорировать правила стиля Java и оставлять фигурные скобки. В
частности, вы значительно увеличиваете риск того, что код с ошибочным отступом будет
неверно истолкован.

Проблема «болтаться»:

https://riptutorial.com/ru/home 97
Рассмотрим пример кода сверху, переписанный без брекетов.

if (a)
doSomething();
doSomeMore();

Этот код, кажется, говорит, что вызовы doSomething и doSomeMore будут возникать тогда и
только тогда, когда a true . Фактически, код имеет неправильный отступ. Спецификация
языка Java, что doSomeMore() представляет собой отдельный оператор, следующий за
оператором if . Правильный отступ выглядит следующим образом:

if (a)
doSomething();
doSomeMore();

Проблема «болтаться еще»

Вторая проблема возникает, когда мы добавляем else к миксу. Рассмотрим следующий


пример с отсутствующими фигурными скобками.

if (a)
if (b)
doX();
else if (c)
doY();
else
doZ();

Вышеприведенный код говорит, что doZ будет вызываться, когда a является false .
Фактически, отступ неверен еще раз. Правильный отступ для кода:

if (a)
if (b)
doX();
else if (c)
doY();
else
doZ();

Если код был написан в соответствии с правилами стиля Java, это выглядело бы так:

if (a) {
if (b) {
doX();
} else if (c) {
doY();
} else {
doZ();
}
}

https://riptutorial.com/ru/home 98
Чтобы проиллюстрировать, почему это лучше, предположите, что вы случайно ошиблись в
коде. У вас может получиться что-то вроде этого:

if (a) { if (a) {
if (b) { if (b) {
doX(); doX();
} else if (c) { } else if (c) {
doY(); doY();
} else { } else {
doZ(); doZ();
} }
} }

Но в обоих случаях ошибочный код «выглядит неправильно» для глаз опытного Java-
программиста.

Pitfall - перегрузка вместо переопределения

Рассмотрим следующий пример:

public final class Person {


private final String firstName;
private final String lastName;

public Person(String firstName, String lastName) {


this.firstName = (firstName == null) ? "" : firstName;
this.lastName = (lastName == null) ? "" : lastName;
}

public boolean equals(String other) {


if (!(other instanceof Person)) {
return false;
}
Person p = (Person) other;
return firstName.equals(p.firstName) &&
lastName.equals(p.lastName);
}

public int hashcode() {


return firstName.hashCode() + 31 * lastName.hashCode();
}
}

Этот код не будет вести себя так, как ожидалось. Проблема в том, что методы equals и
hashcode для Person не переопределяют стандартные методы, определенные Object .

• Метод equals имеет неправильную подпись. Он должен быть объявлен как


equals(Object) не equals(String) .
• Метод hashcode имеет неправильное имя. Это должен быть hashCode() (обратите
внимание на капитал C ).

Эти ошибки означают, что мы объявили случайные перегрузки, и они не будут


использоваться, если Person используется в полиморфном контексте.

https://riptutorial.com/ru/home 99
Однако есть простой способ справиться с этим (начиная с Java 5). Используйте аннотацию
@Override всякий раз, когда вы планируете переопределить ваш метод:

Java SE 5

public final class Person {


...

@Override
public boolean equals(String other) {
....
}

@Override
public hashcode() {
....
}
}

Когда мы добавим @Override аннотации к объявлению метода, компилятор проверяет , что


метод не переопределить (или реализацию) метод , объявленный в суперклассе или
интерфейсе. Итак, в приведенном выше примере компилятор даст нам две ошибки
компиляции, которых должно быть достаточно, чтобы предупредить нас об ошибке.

Pitfall - Октальные литералы

Рассмотрим следующий фрагмент кода:

// Print the sum of the numbers 1 to 10


int count = 0;
for (int i = 1; i < 010; i++) { // Mistake here ....
count = count + i;
}
System.out.println("The sum of 1 to 10 is " + count);

Новичок Java может быть удивлен, узнав, что указанная выше программа печатает
неверный ответ. Он фактически печатает сумму чисел от 1 до 8.

Причина в том, что целочисленный литерал, начинающийся с нуля ('0'), интерпретируется


компилятором Java как восьмеричный литерал, а не десятичный литерал, как вы могли
ожидать. Таким образом, 010 - это восьмеричное число 10, которое равно 8 десятичным.

Pitfall - объявление классов с теми же именами, что и стандартные классы

Иногда программисты, которые не знакомы с Java, ошибаются в определении класса с


именем, которое совпадает с широко используемым классом. Например:

package com.example;

/**
* My string utilities

https://riptutorial.com/ru/home 100
*/
public class String {
....
}

Затем они задаются вопросом, почему возникают неожиданные ошибки. Например:

package com.example;

public class Test {


public static void main(String[] args) {
System.out.println("Hello world!");
}
}

Если вы скомпилируете и затем попытаетесь запустить указанные выше классы, вы


получите сообщение об ошибке:

$ javac com/example/*.java
$ java com.example.Test
Error: Main method not found in class test.Test, please define the main method as:
public static void main(String[] args)
or a JavaFX application class must extend javafx.application.Application

Кто-то, смотрящий на код для класса Test , увидит объявление main и посмотрит на его
подпись и задается вопросом, о чем жалуется команда java . Но на самом деле, команда
java говорит правду.

Когда мы объявляем версию String в том же пакете, что и Test , эта версия имеет
приоритет перед автоматическим импортом java.lang.String . Таким образом, подпись
метода Test.main самом деле

void main(com.example.String[] args)

вместо

void main(java.lang.String[] args)

и команда java не будет распознавать это как метод точки входа.

Занятие. Не определяйте классы, которые имеют то же имя, что и существующие классы в


java.lang , или другие обычно используемые классы в библиотеке Java SE. Если вы это
сделаете, вы настроитесь на всевозможные неясные ошибки.

Pitfall - использование '==' для проверки логического

Иногда новый программист Java будет писать такой код:

public void check(boolean ok) {

https://riptutorial.com/ru/home 101
if (ok == true) { // Note 'ok == true'
System.out.println("It is OK");
}
}

Опытный программист заметил бы это как неуклюжий и хотел бы переписать его как:

public void check(boolean ok) {


if (ok) {
System.out.println("It is OK");
}
}

Тем не менее, с ошибкой ok == true чем просто неуклюжесть. Рассмотрим этот вариант:

public void check(boolean ok) {


if (ok = true) { // Oooops!
System.out.println("It is OK");
}
}

Здесь программист ошибся == as = ... и теперь код имеет тонкую ошибку. Выражение x =
true безоговорочно присваивает true x а затем оценивается как true . Другими словами,
теперь метод check будет печатать «Все в порядке» независимо от параметра.

Урок здесь состоит в том, чтобы избавиться от привычки использовать == false и == true . В
дополнение к тому, чтобы быть многословным, они делают ваше кодирование более
склонным к ошибкам.

Примечание. Возможная альтернатива ok == true которая позволяет избежать ошибок,


заключается в использовании условий Yoda ; т.е. поставить литерал в левой части
реляционного оператора, как в true == ok . Это работает, но большинство программистов,
вероятно, согласятся с тем, что условия Yoda выглядят странно. Конечно, ok (или !ok )
является более кратким и более естественным.

Pitfall - импорт подстановок может сделать ваш код хрупким

Рассмотрим следующий частичный пример:

import com.example.somelib.*;
import com.acme.otherlib.*;

public class Test {


private Context x = new Context(); // from com.example.somelib
...
}

Предположим, что когда вы впервые разработали код против версии 1.0 somelib и версии
1.0 otherlib . Затем в какой-то более поздний момент вам нужно обновить свои

https://riptutorial.com/ru/home 102
зависимости до более поздних версий, и вы решите использовать версию otherlib версии
2.0. Также предположим, что одно из изменений, которые они сделали для otherlib между
1.0 и 2.0, заключалось в том, чтобы добавить класс Context .

Теперь, когда вы перекомпилируете Test , вы получите ошибку компиляции, сообщающую


вам, что Context является неоднозначным импортом.

Если вы знакомы с кодовой базой, это, вероятно, всего лишь незначительные неудобства.
Если нет, то у вас есть некоторая работа, чтобы сделать, чтобы решить эту проблему,
здесь и потенциально в другом месте.

Проблема здесь в подстановочных импортах. С одной стороны, использование


подстановочных знаков может сделать ваши классы на несколько строк короче. С другой
стороны:

• Совместимые с обновлением изменения в других частях вашей кодовой базы,


стандартных библиотек Java или сторонних библиотек могут привести к ошибкам
компиляции.

• Читаемость страдает. Если вы не используете IDE, выяснить, какой из


подстановочных импортов тянет в названный класс, может быть сложно.

Урок состоит в том, что плохой идеей использовать подстановочный импорт в коде,
который должен быть долговечным. Конкретные (несимметричные) импорт не требуют
больших усилий для поддержки, если вы используете среду IDE, и это стоит того.

Pitfall: использование 'assert' для проверки аргумента или пользователя

Иногда вопрос о StackOverflow заключается в том, целесообразно ли использовать assert


для проверки аргументов, предоставляемых методу, или даже входов, предоставленных
пользователем.

Простой ответ заключается в том, что он не подходит.

Лучшие альтернативы включают:

• Выбрасывание исключения IllegalArgumentException с использованием


настраиваемого кода.
• Использование методов Preconditions доступных в библиотеке Google Guava.
• Используя Validate методы , доступные в библиотеке Apache Commons Lang3.

Это то, что предлагает Java Language Specification (JLS 14.10, для Java 8) по этому вопросу:

Как правило, проверка утверждения включена во время разработки и


тестирования программ и отключена для развертывания для повышения
производительности.

https://riptutorial.com/ru/home 103
Поскольку утверждения могут быть отключены, программы не должны
предполагать, что выражения, содержащиеся в утверждениях, будут
оцениваться. Таким образом, эти булевы выражения, как правило, не содержат
побочных эффектов. Оценка такого булевского выражения не должна влиять
на состояние, которое видно после завершения оценки. Это не является
незаконным, если логическое выражение, содержащееся в утверждении, имеет
побочный эффект, но оно, как правило, неприемлемо, поскольку это может
привести к изменению поведения программы в зависимости от того, были ли
включены или запрещены утверждения.

В свете этого утверждения не должны использоваться для проверки аргументов


в публичных методах. Проверка аргументов обычно является частью контракта
метода, и этот контракт должен быть подтвержден, если утверждения
включены или отключены.

Вторая проблема с использованием утверждений для проверки аргументов


заключается в том, что ошибочные аргументы должны приводить к
соответствующему исключению во время выполнения (например,
IllegalArgumentException , ArrayIndexOutOfBoundsException или NullPointerException ).
Ошибка утверждения не приведет к соответствующему исключению. Опять же,
не запрещено использовать утверждения для проверки аргументов в публичных
методах, но это, как правило, неуместно. Предполагается, что AssertionError
никогда не будет поймано, но это можно сделать, поэтому правила для
операторов try должны обрабатывать утверждения, появляющиеся в блоке try
так же, как и текущее обращение с инструкциями throw.

Pitfall авто-распаковки нулевых объектов в примитивы

public class Foobar {


public static void main(String[] args) {

// example:
Boolean ignore = null;
if (ignore == false) {
System.out.println("Do not ignore!");
}
}
}

Ловушка здесь заключается в том, что null сравнивается с false . Поскольку мы сравниваем
примитивное boolean с Boolean , Java пытается распаковать Boolean Object в примитивный
эквивалент, готовый для сравнения. Однако, поскольку это значение равно null ,
NullPointerException .

Java неспособна сравнивать примитивные типы с null значениями, что вызывает


NullPointerException во время выполнения. Рассмотрим примитивный случай условия false ==
null ; это создало бы ошибку времени компиляции incomparable types: int and <null> .

https://riptutorial.com/ru/home 104
Прочитайте Java Pitfalls - синтаксис языка онлайн:
https://riptutorial.com/ru/java/topic/5382/java-pitfalls---синтаксис-языка

https://riptutorial.com/ru/home 105
глава 20: JavaBean
Вступление
JavaBeans (TM) - это образец для разработки API классов Java, который позволяет
использовать экземпляры (бобы) в различных контекстах и использовать различные
инструменты без явного написания кода Java. Шаблоны состоят из соглашений для
определения геттеров и сеттеров для свойств , для определения конструкторов и для
определения API-интерфейсов слушателей событий.

Синтаксис
• Правила именования свойств JavaBean
• Если свойство не является логическим, следует использовать префикс метода getter.
Например, getSize () является допустимым именем получателя JavaBeans для
свойства с именем «размер». Имейте в виду, что вам не нужно иметь переменный
именованный размер. Имя свойства выводится из геттеров и сеттеров, а не через
любые переменные в вашем классе. То, что вы возвращаете из getSize (), зависит от
вас.
• Если свойство является логическим, префикс метода getter либо get, либо is.
Например, getStopped () или isStopped () являются действительными именами
JavaBeans для логического свойства.
• Должен быть установлен префикс метода setter. Например, setSize () является
допустимым именем JavaBean для свойства с именем size.
• Чтобы заполнить имя метода getter или setter, измените первую букву имени свойства
на верхний регистр и затем добавьте его в соответствующий префикс (get, is или set).
• Сигнатуры метода Setter должны быть помечены как public, с типом возвращаемого
типа и аргументом, который представляет тип свойства.
• Подписи метода Getter должны быть отмечены как public, не принимать аргументы и
иметь тип возвращаемого значения, который соответствует типу аргумента метода
setter для этого свойства.
• Правила именования слушателей JavaBean
• Имена методов прослушивателя, используемые для «регистрации» слушателя с
источником события, должны использовать префикс add, за которым следует тип
слушателя. Например, addActionListener () является допустимым именем для метода,
который источник события должен будет разрешить другим пользователям
регистрироваться для событий Action.
• В именах методов прослушивателя, используемых для удаления («отменить
регистрацию»), слушатель должен использовать префикс remove, за которым
следует тип слушателя (с использованием тех же правил, что и метод добавления
регистрации).

https://riptutorial.com/ru/home 106
• Тип слушателя, который нужно добавить или удалить, должен быть передан как
аргумент метода.
• Имена методов прослушивателя должны заканчиваться словом «Слушатель».

замечания
Для того чтобы класс был Java Bean, должен следовать этому стандарту - в целом:

• Все его свойства должны быть частными и доступны только через геттеры и сеттеры.
• Он должен иметь открытый конструктор без аргументов.
• Необходимо реализовать интерфейс java.io.Serializable .

Examples

Базовый Java-компонент

public class BasicJavaBean implements java.io.Serializable{

private int value1;


private String value2;
private boolean value3;

public BasicJavaBean(){}

public void setValue1(int value1){


this.value1 = value1;
}

public int getValue1(){


return value1;
}

public void setValue2(String value2){


this.value2 = value2;
}

public String getValue2(){


return value2;
}

public void setValue3(boolean value3){


this.value3 = value3;
}

public boolean isValue3(){


return value3;
}
}

Прочитайте JavaBean онлайн: https://riptutorial.com/ru/java/topic/8157/javabean

https://riptutorial.com/ru/home 107
глава 21: Java-агенты
Examples

Изменение классов с помощью агентов

Во-первых, убедитесь, что используемый агент имеет следующие атрибуты в Manifest.mf:

Can-Redefine-Classes: true
Can-Retransform-Classes: true

Запуск Java-агента позволит агенту получить доступ к классу Instrumentation. С помощью


Instrumentation вы можете вызвать addTransformer (трансформатор ClassFileTransformer) .
ClassFileTransformers позволит вам переписать байты классов. Класс имеет только один
метод, который поставляет ClassLoader, который загружает класс, имя класса, экземпляр
java.lang.Class, это ProtectionDomain и, наконец, байты самого класса.

Это выглядит так:

byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,


ProtectionDomain protectionDomain, byte[] classfileBuffer)

Модификация класса исключительно из байтов может занять возраст. Чтобы исправить


это, есть библиотеки, которые могут быть использованы для преобразования байтов
класса в нечто более пригодное для использования.

В этом примере я буду использовать ASM, но другие альтернативы, такие как Javassist и
BCEL, имеют схожие функции.

ClassNode getNode(byte[] bytes) {


// Create a ClassReader that will parse the byte array into a ClassNode
ClassReader cr = new ClassReader(bytes);
ClassNode cn = new ClassNode();
try {
// This populates the ClassNode
cr.accept(cn, ClassReader.EXPAND_FRAMES);
cr = null;
} catch (Exception e) {
e.printStackTrace();
}
return cn;
}

Отсюда можно внести изменения в объект ClassNode. Это позволяет невероятно легко
изменять доступ к полям / методам. Плюс с API-интерфейсом ASM, изменяющим байт-код
методов, это легкий ветерок.

https://riptutorial.com/ru/home 108
После завершения редактирования вы можете преобразовать ClassNode обратно в байты
со следующим методом и вернуть их в метод преобразования :

public static byte[] getNodeBytes(ClassNode cn, boolean useMaxs) {


ClassWriter cw = new ClassWriter(useMaxs ? ClassWriter.COMPUTE_MAXS :
ClassWriter.COMPUTE_FRAMES);
cn.accept(cw);
byte[] b = cw.toByteArray();
return b;
}

Добавление агента во время выполнения

Агенты могут быть добавлены в JVM во время выполнения. Чтобы загрузить агента, вам
нужно использовать VirtualMachine.attatch ( Attach API) Attach API (String id) . Затем вы
можете загрузить скомпилированную фразу агента следующим способом:

public static void loadAgent(String agentPath) {


String vmName = ManagementFactory.getRuntimeMXBean().getName();
int index = vmName.indexOf('@');
String pid = vmName.substring(0, index);
try {
File agentFile = new File(agentPath);
VirtualMachine vm = VirtualMachine.attach(pid);
vm.loadAgent(agentFile.getAbsolutePath(), "");
VirtualMachine.attach(vm.id());
} catch (Exception e) {
throw new RuntimeException(e);
}
}

Это не будет вызывать premain ((String agentArgs, Инструментарий INST) в загруженном


агенте, но вместо этого будет вызывать agentmain (String agentArgs, Инструментарий INST).
Это требует Агент-класс должны быть установлено в средстве manifest.mf.

Настройка базового агента

Класс Premain будет содержать метод «premain (String agentArgs Instrumentation inst)»

Вот пример:

import java.lang.instrument.Instrumentation;

public class PremainExample {


public static void premain(String agentArgs, Instrumentation inst) {
System.out.println(agentArgs);
}
}

Когда они скомпилированы в файл jar, откройте манифест и убедитесь, что он имеет
атрибут Premain-Class.

https://riptutorial.com/ru/home 109
Вот пример:

Premain-Class: PremainExample

Чтобы использовать агент с другой java-программой «myProgram», вы должны определить


агента в аргументах JVM:

java -javaagent:PremainAgent.jar -jar myProgram.jar

Прочитайте Java-агенты онлайн: https://riptutorial.com/ru/java/topic/1265/java-агенты

https://riptutorial.com/ru/home 110
глава 22: Java-версии, версии, выпуски и
дистрибутивы
Examples

Различия между Java SE JRE или Java SE JDK

Sun / Oracle выпуски Java SE представлены в двух формах: JRE и JDK. Говоря простыми
словами, JRE поддерживают запуск Java-приложений, а JDK также поддерживают
разработку Java.

Java Runtime Environment


Java Runtime Environment или JRE-дистрибутивы состоят из набора библиотек и
инструментов, необходимых для запуска и управления приложениями Java. Инструменты в
типичной современной JRE включают:

• java команда для запуска Java-программы в JVM (виртуальная машина Java)


• Команда jjs для запуска движка Nashorn Javascript.
• Команда keytool для манипуляции Java-хранилищами.
• Команда policytool для редактирования политик безопасности изолированной
policytool .
• Инструменты pack200 и unpack200 для упаковки и распаковки файла «pack200» для веб-
развертывания.
• orbd , rmid , rmiregistry и tnameserv которые поддерживают приложения Java CORBA и
RMI.

Установщики Desktop JRE включают плагин Java, подходящий для некоторых веб-
браузеров. Это преднамеренно исключено из «Server JRE» installers.linux syscall read
benchmarku

Начиная с версии Java 7 6, установщики JRE включили JavaFX (версия 2.2 или новее).

Java Development Kit


Набор Java Development Kit или JDK включает инструменты JRE и дополнительные
инструменты для разработки программного обеспечения Java. Дополнительные
инструменты обычно включают:

• Команда javac , которая компилирует исходный код Java («.java») в байт-код файлов
(«.class»).

https://riptutorial.com/ru/home 111
• Инструменты для создания JAR-файлов, таких как jar и jarsigner
• Средства разработки, такие как:
appletviewer для запуска апплетов

idlj компилятор CORBA IDL для Java


javah генератор-заглушка JNI


native2ascii для преобразования набора символов исходного кода Java


schemagen генератор схемы Java-XML (часть JAXB)


serialver генерирует строку версии Serialization Java Object.


инструменты поддержки wsgen и wsimport для JAX-WS


• Диагностические инструменты, такие как:


jdb базовый отладчик Java

jmap и jhat для демпинга и анализа кучи Java.


jstack для получения дампа потока потоков.


javap для изучения файлов «.class».


• Инструменты управления приложениями и мониторинга, такие как:


jconsole - консоль управления,

jstat , jstatd , jinfo и jps для мониторинга приложений


Типичная установка Sun / Oracle JDK также включает ZIP-файл с исходным кодом
библиотек Java. До появления Java 6 это был единственный общедоступный исходный код
Java.

Начиная с Java 6, полный исходный код для OpenJDK доступен для загрузки с сайта
OpenJDK. Обычно он не входит в пакеты JDK (Linux), но доступен как отдельный пакет.

В чем разница между Oracle Hotspot и OpenJDK

Ортогональная JRE по сравнению с JDK-дихотомией, есть два типа выпусков Java,


которые широко доступны:

• Релизы Oracle Hotspot - это те, которые вы загружаете с сайтов загрузки Oracle.
• Выпуски OpenJDK - это те, которые построены (как правило, сторонними
поставщиками) из исходных репозиториев OpenJDK.

В функциональных терминах существует небольшая разница между выпуском Hotspot и


выпуском OpenJDK. В Hotspot есть несколько дополнительных «корпоративных» функций,
которые могут использовать клиенты Oracle (оплачивающие) Java, но кроме того, одна и та
же технология присутствует как в Hotspot, так и в OpenJDK.

Еще одно преимущество Hotspot над OpenJDK заключается в том, что выпуски исправлений
для Hotspot, как правило, доступны чуть раньше. Это также зависит от того, насколько
гибким является ваш поставщик OpenJDK; например, сколько времени потребуется
команде разработчиков дистрибутива Linux для подготовки и QA новой сборки OpenJDK и
получить ее в своих публичных хранилищах.

https://riptutorial.com/ru/home 112
С другой стороны, выпуски Hotspot недоступны из репозиториев пакетов для большинства
дистрибутивов Linux. Это означает, что сохранение вашего программного обеспечения Java
на современном компьютере Linux обычно более эффективно, если вы используете
Hotspot.

Различия между Java EE, Java SE, Java ME и JavaFX

Технология Java - это язык программирования и платформа. Язык программирования Java -


это высокоуровневый объектно-ориентированный язык с особым синтаксисом и стилем.
Java-платформа - это особая среда, в которой работают приложения языка Java.

Существует несколько платформ Java. Многие разработчики, даже давние разработчики


языка Java, не понимают, как разные платформы связаны друг с другом.

Языковые платформы Java


Существует четыре платформы языка программирования Java:

• Платформа Java, стандартная версия (Java SE)

• Платформа Java, Enterprise Edition (Java EE)

• Java Platform, Micro Edition (Java ME)

• Java FX

Все платформы Java состоят из виртуальной машины Java (VM) и интерфейса прикладного
программирования (API). Виртуальная машина Java - это программа для конкретной
аппаратной и программной платформы, которая запускает приложения для Java-
технологий. API представляет собой набор программных компонентов, которые можно
использовать для создания других программных компонентов или приложений. Каждая
платформа Java предоставляет виртуальную машину и API, что позволяет приложениям,
написанным для этой платформы, работать на любой совместимой системе со всеми
преимуществами языка программирования Java: независимость от платформы, мощность,
стабильность, простота разработки и безопасность.

Java SE
Когда большинство людей думает о языке программирования Java, они думают о Java SE
API. API Java SE обеспечивает основные функциональные возможности языка
программирования Java. Он определяет все, от базовых типов и объектов языка
программирования Java до классов высокого уровня, которые используются для создания
сетей, обеспечения безопасности, доступа к базе данных, разработки графического

https://riptutorial.com/ru/home 113
интерфейса пользователя (GUI) и анализа XML.

В дополнение к основному API платформа Java SE состоит из виртуальной машины,


средств разработки, технологий развертывания и других библиотек классов и наборов
инструментов, обычно используемых в приложениях Java.

Java EE
Платформа Java EE построена поверх платформы Java SE. Платформа Java EE
обеспечивает среду API и среду выполнения для разработки и запуска широкомасштабных
многоуровневых, масштабируемых, надежных и безопасных сетевых приложений.

Java ME
Платформа Java ME предоставляет API и небольшую виртуальную машину для запуска
приложений Java для программирования на небольших устройствах, таких как мобильные
телефоны. API - это подмножество Java SE API, а также специальные библиотеки классов,
полезные для разработки небольших приложений. Приложения Java ME часто являются
клиентами служб платформы Java EE.

Java FX
Технология Java FX - это платформа для создания богатых интернет-приложений,
написанных на Java FX ScriptTM. Java FX Script - это статически типизированный
декларативный язык, который скомпилирован в байт-код Java-технологии, который затем
может быть запущен на виртуальной машине Java. Приложения, написанные для
платформы Java FX, могут включать и связываться с языковыми классами Java-
программирования и могут быть клиентами служб платформы Java EE.

• Взято из документации Oracle

Версии Java SE

История версий Java SE


В следующей таблице приведены сроки значительных основных версий платформы Java
SE.

https://riptutorial.com/ru/home 114
Окончание срока службы
Java SE Version 1 Кодовое имя Дата выхода
(бесплатно 2 )

Java SE 9 (ранний 2017-07-27 (по


Никто будущее
доступ) оценкам)

Java SE 8 Никто будущее 2014-03-18

Java SE 7 дельфин 2015-04-14 2011-07-28

Java SE 6 мустанг 2013-04-16 2006-12-23

Java SE 5 тигр 2009-11-04 2004-10-04

Java SE 1.4.2 Богомол до 2009-11-04 2003-06-26

Хоппер /
Java SE 1.4.1 до 2009-11-04 2002-09-16
Кузнечик

Java SE 1.4 Мерлин до 2009-11-04 2002-02-06

Java SE 1.3.1 Божья коровка до 2009-11-04 2001-05-17

Java SE 1.3 Пустельга до 2009-11-04 2000-05-08

Детская
Java SE 1.2 до 2009-11-04 1998-12-08
площадка

бенгальский
Java SE 1.1 до 2009-11-04 1997-02-19
огонь

Java SE 1.0 дуб до 2009-11-04 1996-01-21

Примечания:

1. Ссылки на онлайн-копии документации соответствующих выпусков на веб-сайте


Oracle. Документация для многих старых версий больше не доступна в Интернете,
хотя ее обычно можно загрузить из Oracle Java Archives.

2. Большинство исторических версий Java SE прошли официальные даты окончания


жизни. Когда версия Java проходит эту веху, Oracle перестает предоставлять для нее
бесплатные обновления. Обновления по-прежнему доступны для клиентов с
контрактами на поддержку.

Источник:

• Дата выпуска JDK от Roedy Green от Canadian Mind Products

https://riptutorial.com/ru/home 115
Основные сведения о версии Java SE

Версия
Особенности
Java SE

Лямбда-выражения и потоки, созданные с помощью MapReduce. Двигатель


Nashorn Javascript. Аннотации по типам и повторяющиеся аннотации.
Java SE
Неподписанные арифметические расширения. Новые API дат и времени.
8
Статически связанные библиотеки JNI. Пусковая установка JavaFX.
Удаление PermGen.

Строковые переключатели, try-with-resource , алмаз ( <> ), улучшенные


числовые литералы и улучшения обработки / восстановления исключений.
Java SE
Расширения библиотеки параллелизма. Расширенная поддержка для
7
родных файловых систем. Timsort. Криптографические алгоритмы ECC.
Улучшена поддержка 2D-графики (GPU). Вставляемые аннотации.

Значительные улучшения производительности платформы JVM и Swing.


Java SE
API языка сценариев и движок Javascript Mozilla Rhino. JDBC 4.0. API
6
компилятора. JAXB 2.0. Поддержка веб-сервисов (JAX-WS)

Generics, аннотации, авто-бокс, классы enum , varargs, улучшенные for


Java SE циклов и статический импорт. Спецификация модели памяти Java.
5 Улучшения Swing и RMI. Добавление пакета java.util.concurrent.* И Scanner
.

Ключевое слово assert . Классы регулярных выражений. Цепочка


исключений. NIO API - неблокирующий ввод-вывод, Buffer и Channel .
Java SE
java.util.logging.* API. API ввода-вывода изображений. Интегрированный
1.4
XML и XSLT (JAXP). Интегрированная безопасность и криптография (JCE,
JSSE, JAAS). Встроенный Java Web Start. API настроек.

Включен JVM HotSpot. Интеграция CORBA / RMI. Интерфейс именования и


Java SE
интерфейса Java (JNDI). Рамка отладчика (JPDA). API JavaSound. Proxy
1.3
API.

Java SE Ключевое слово strictfp . Swing API. Плагин Java (для веб-браузеров).
1.2 CORBA. Структура коллекций.

Внутренние классы. Отражение. JDBC. RMI. Unicode / символьные потоки.


Java SE
Поддержка интернационализации. Капитальный ремонт модели событий
1.1
AWT. JavaBeans.

Источник:

https://riptutorial.com/ru/home 116
• Википедия: история версий Java

Прочитайте Java-версии, версии, выпуски и дистрибутивы онлайн:


https://riptutorial.com/ru/java/topic/8973/java-версии--версии--выпуски-и-дистрибутивы

https://riptutorial.com/ru/home 117
глава 23: JAXB
Вступление
JAXB или Java Architecture for XML Binding (JAXB) - это программная среда, которая
позволяет разработчикам Java сопоставлять классы Java с представлениями XML. Эта
страница познакомит читателей с JAXB, используя подробные примеры о его функциях,
предоставляемых главным образом для маршалинга и неархивирования объектов Java в
xml-формате и наоборот.

Синтаксис
• JAXB.marshall (объект, fileObjOfXML);

• Object obj = JAXB.unmarshall (fileObjOfXML, className);

параметры

параметр подробности

fileObjOfXML File объект XML-файла

имя класса Имя класса с расширением .class

замечания
Используя инструмент XJC, доступный в JDK, java-код для структуры xml, описанный в xml-
схеме (файл .xsd ), может быть сгенерирован автоматически, см. Тему XJC .

Examples

Написание XML-файла (сортировка объекта)

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class User {

private long userID;


private String name;

// getters and setters


}

https://riptutorial.com/ru/home 118
Используя аннотацию XMLRootElement , мы можем пометить класс как корневой элемент XML-
файла.

import java.io.File;
import javax.xml.bind.JAXB;

public class XMLCreator {


public static void main(String[] args) {
User user = new User();
user.setName("Jon Skeet");
user.setUserID(8884321);

try {
JAXB.marshal(user, new File("UserDetails.xml"));
} catch (Exception e) {
System.err.println("Exception occurred while writing in XML!");
} finally {
System.out.println("XML created");
}
}
}

используется для записи содержимого объекта в файл XML. Здесь user объект и
marshal()
новый объект File передаются в качестве аргументов marshal() .

При успешном выполнении это создает XML-файл с именем UserDetails.xml в пути класса с
содержимым ниже.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>


<user>
<name>Jon Skeet</name>
<userID>8884321</userID>
</user>

Чтение XML-файла (unmarshalling)

Чтобы прочитать XML-файл с именем UserDetails.xml с приведенным ниже содержимым

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>


<user>
<name>Jon Skeet</name>
<userID>8884321</userID>
</user>

Нам нужен класс POJO с именем User.java как User.java ниже.

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class User {

private long userID;


private String name;

https://riptutorial.com/ru/home 119
// getters and setters
}

Здесь мы создали переменные и имя класса в соответствии с узлами XML. Чтобы


сопоставить их, мы используем аннотацию XmlRootElement в классе.

public class XMLReader {


public static void main(String[] args) {
try {
User user = JAXB.unmarshal(new File("UserDetails.xml"), User.class);
System.out.println(user.getName()); // prints Jon Skeet
System.out.println(user.getUserID()); // prints 8884321
} catch (Exception e) {
System.err.println("Exception occurred while reading the XML!");
}
}
}

Здесь метод unmarshal() используется для анализа XML-файла. В качестве двух аргументов
требуется имя файла XML и тип класса. Затем мы можем использовать методы getter
объекта для печати данных.

Использование XmlAdapter для генерации желаемого формата XML

Когда желаемый формат XML отличается от объектной модели Java, реализация


XmlAdapter может использоваться для преобразования объекта модели в объект XML-
формата и наоборот. В этом примере показано, как поместить значение поля в атрибут
элемента с именем поля.

public class XmlAdapterExample {

@XmlAccessorType(XmlAccessType.FIELD)
public static class NodeValueElement {

@XmlAttribute(name="attrValue")
String value;

public NodeValueElement() {
}

public NodeValueElement(String value) {


super();
this.value = value;
}

public String getValue() {


return value;
}

public void setValue(String value) {


this.value = value;
}
}

https://riptutorial.com/ru/home 120
public static class ValueAsAttrXmlAdapter extends XmlAdapter<NodeValueElement, String> {

@Override
public NodeValueElement marshal(String v) throws Exception {
return new NodeValueElement(v);
}

@Override
public String unmarshal(NodeValueElement v) throws Exception {
if (v==null) return "";
return v.getValue();
}
}

@XmlRootElement(name="DataObject")
@XmlAccessorType(XmlAccessType.FIELD)
public static class DataObject {

String elementWithValue;

@XmlJavaTypeAdapter(value=ValueAsAttrXmlAdapter.class)
String elementWithAttribute;
}

public static void main(String[] args) {


DataObject data = new DataObject();
data.elementWithValue="value1";
data.elementWithAttribute ="value2";

ByteArrayOutputStream baos = new ByteArrayOutputStream();


JAXB.marshal(data, baos);

String xmlString = new String(baos.toByteArray(), StandardCharsets.UTF_8);

System.out.println(xmlString);
}
}

Автоматическая конфигурация отображения XML / XML


(@XmlAccessorType)

Аннотация @XmlAccessorType определяет, будут ли поля / свойства автоматически


сериализованы в XML. Обратите внимание, что аннотации полей и методов @XmlElement ,
@XmlAttribute или @XmlTransient имеют приоритет над настройками по умолчанию.

public class XmlAccessTypeExample {

@XmlAccessorType(XmlAccessType.FIELD)
static class AccessorExampleField {
public String field="value1";

public String getGetter() {


return "getter";
}

public void setGetter(String value) {}

https://riptutorial.com/ru/home 121
}

@XmlAccessorType(XmlAccessType.NONE)
static class AccessorExampleNone {
public String field="value1";

public String getGetter() {


return "getter";
}

public void setGetter(String value) {}


}

@XmlAccessorType(XmlAccessType.PROPERTY)
static class AccessorExampleProperty {
public String field="value1";

public String getGetter() {


return "getter";
}

public void setGetter(String value) {}


}

@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
static class AccessorExamplePublic {
public String field="value1";

public String getGetter() {


return "getter";
}

public void setGetter(String value) {}


}

public static void main(String[] args) {


try {
System.out.println("\nField:");
JAXB.marshal(new AccessorExampleField(), System.out);
System.out.println("\nNone:");
JAXB.marshal(new AccessorExampleNone(), System.out);
System.out.println("\nProperty:");
JAXB.marshal(new AccessorExampleProperty(), System.out);
System.out.println("\nPublic:");
JAXB.marshal(new AccessorExamplePublic(), System.out);
} catch (Exception e) {
System.err.println("Exception occurred while writing in XML!");
}
}

} // outer class end

Выход

Field:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<accessorExampleField>
<field>value1</field>
</accessorExampleField>

https://riptutorial.com/ru/home 122
None:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<accessorExampleNone/>

Property:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<accessorExampleProperty>
<getter>getter</getter>
</accessorExampleProperty>

Public:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<accessorExamplePublic>
<field>value1</field>
<getter>getter</getter>
</accessorExamplePublic>

Конфигурация отображения XML вручную / свойства

Аннотации @XmlElement , @XmlAttribute или @XmlTransient и другие в пакете


javax.xml.bind.annotation позволяют программисту указать, какие и как помеченные поля
или свойства должны быть сериализованы.

@XmlAccessorType(XmlAccessType.NONE) // we want no automatic field/property marshalling


public class ManualXmlElementsExample {

@XmlElement
private String field="field value";

@XmlAttribute
private String attribute="attr value";

@XmlAttribute(name="differentAttribute")
private String oneAttribute="other attr value";

@XmlElement(name="different name")
private String oneName="different name value";

@XmlTransient
private String transientField = "will not get serialized ever";

@XmlElement
public String getModifiedTransientValue() {
return transientField.replace(" ever", ", unless in a getter");
}

public void setModifiedTransientValue(String val) {} // empty on purpose

public static void main(String[] args) {


try {
JAXB.marshal(new ManualXmlElementsExample(), System.out);
} catch (Exception e) {
System.err.println("Exception occurred while writing in XML!");
}
}
}

https://riptutorial.com/ru/home 123
Указание экземпляра XmlAdapter для (повторного) использования
существующих данных

Иногда необходимо использовать конкретные экземпляры данных. Отдых нежелателен, и


ссылка на static данные будет иметь запах кода.

Можно указать XmlAdapter экземпляр по Unmarshaller должен использовать, что позволяет


пользователю использовать XmlAdapter ей, не равна нулю-Arg конструктор и / или
передавать данные к адаптеру.

пример

Пользовательский класс

Следующий класс содержит имя и образ пользователя.

import java.awt.image.BufferedImage;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlRootElement
public class User {

private String name;


private BufferedImage image;

@XmlAttribute
public String getName() {
return name;
}

public void setName(String name) {


this.name = name;
}

@XmlJavaTypeAdapter(value=ImageCacheAdapter.class)
@XmlAttribute
public BufferedImage getImage() {
return image;
}

public void setImage(BufferedImage image) {


this.image = image;
}

public User(String name, BufferedImage image) {


this.name = name;
this.image = image;
}

public User() {
this("", null);
}

https://riptutorial.com/ru/home 124
}

адаптер

Чтобы избежать одновременного создания одного и того же изображения в памяти (а


также загрузки данных снова), адаптер сохраняет изображения на карте.

Java SE 7

Для действительного кода Java 7 замените метод getImage на

public BufferedImage getImage(URL url) {


BufferedImage image = imageCache.get(url);
if (image == null) {
try {
image = ImageIO.read(url);
} catch (IOException ex) {
Logger.getLogger(ImageCacheAdapter.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
imageCache.put(url, image);
reverseIndex.put(image, url);
}
return image;
}

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.xml.bind.annotation.adapters.XmlAdapter;

public class ImageCacheAdapter extends XmlAdapter<String, BufferedImage> {

private final Map<URL, BufferedImage> imageCache = new HashMap<>();


private final Map<BufferedImage, URL> reverseIndex = new HashMap<>();

public BufferedImage getImage(URL url) {


// using a single lookup using Java 8 methods
return imageCache.computeIfAbsent(url, s -> {
try {
BufferedImage img = ImageIO.read(s);
reverseIndex.put(img, s);
return img;
} catch (IOException ex) {
Logger.getLogger(ImageCacheAdapter.class.getName()).log(Level.SEVERE, null,
ex);
return null;
}
});
}

https://riptutorial.com/ru/home 125
@Override
public BufferedImage unmarshal(String v) throws Exception {
return getImage(new URL(v));
}

@Override
public String marshal(BufferedImage v) throws Exception {
return reverseIndex.get(v).toExternalForm();
}

Примеры XML

Следующие 2 xmls для Jon Skeet и его земля 2, которые выглядят одинаково и поэтому
используют один и тот же аватар.

<?xml version="1.0" encoding="UTF-8"?>

<user name="Jon Skeet"


image="https://www.gravatar.com/avatar/6d8ebb117e8d83d74ea95fbdd0f87e13?s=328&amp;d=identicon&amp;r=PG"

<?xml version="1.0" encoding="UTF-8"?>

<user name="Jon Skeet (Earth 2)"


image="https://www.gravatar.com/avatar/6d8ebb117e8d83d74ea95fbdd0f87e13?s=328&amp;d=identicon&amp;r=PG"

Использование адаптера

ImageCacheAdapter adapter = new ImageCacheAdapter();

JAXBContext context = JAXBContext.newInstance(User.class);

Unmarshaller unmarshaller = context.createUnmarshaller();

// specifiy the adapter instance to use for every


// @XmlJavaTypeAdapter(value=ImageCacheAdapter.class)
unmarshaller.setAdapter(ImageCacheAdapter.class, adapter);

User result1 = (User) unmarshaller.unmarshal(Main.class.getResource("user.xml"));

// unmarshal second xml using the same adapter instance


Unmarshaller unmarshaller2 = context.createUnmarshaller();
unmarshaller2.setAdapter(ImageCacheAdapter.class, adapter);
User result2 = (User) unmarshaller2.unmarshal(Main.class.getResource("user2.xml"));

System.out.println(result1.getName());
System.out.println(result2.getName());

// yields true, since image is reused


System.out.println(result1.getImage() == result2.getImage());

https://riptutorial.com/ru/home 126
Связывание пространства имен XML с сериализуемым классом Java.

Это пример файла package-info.java который связывает пространство имен XML с


сериализуемым классом Java. Это должно быть помещено в тот же пакет, что и классы
Java, которые должны быть сериализованы с использованием пространства имен.

/**
* A package containing serializable classes.
*/
@XmlSchema
(
xmlns =
{
@XmlNs(prefix = MySerializableClass.NAMESPACE_PREFIX, namespaceURI =
MySerializableClass.NAMESPACE)
},
namespace = MySerializableClass.NAMESPACE,
elementFormDefault = XmlNsForm.QUALIFIED
)
package com.test.jaxb;

import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;

Использование XmlAdapter для обрезки строки.

package com.example.xml.adapters;

import javax.xml.bind.annotation.adapters.XmlAdapter;

public class StringTrimAdapter extends XmlAdapter<String, String> {


@Override
public String unmarshal(String v) throws Exception {
if (v == null)
return null;
return v.trim();
}

@Override
public String marshal(String v) throws Exception {
if (v == null)
return null;
return v.trim();
}
}

А в package-info.java добавьте следующее объявление.

@XmlJavaTypeAdapter(value = com.example.xml.adapters.StringTrimAdapter.class, type =


String.class)
package com.example.xml.jaxb.bindings;// Packge where you intend to apply trimming filter

import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

https://riptutorial.com/ru/home 127
Прочитайте JAXB онлайн: https://riptutorial.com/ru/java/topic/147/jaxb

https://riptutorial.com/ru/home 128
глава 24: JAX-WS
Examples

Основная аутентификация

Способ вызова JAX-WS с базовой аутентификацией немного неочевиден.

Вот пример, где Service является представлением класса сервиса, а Port - это служебный
порт, к которому вы хотите получить доступ.

Service s = new Service();


Port port = s.getPort();

BindingProvider prov = (BindingProvider)port;


prov.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, "myusername");
prov.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, "mypassword");

port.call();

Прочитайте JAX-WS онлайн: https://riptutorial.com/ru/java/topic/4105/jax-ws

https://riptutorial.com/ru/home 129
глава 25: JMX
Вступление
Технология JMX предоставляет инструменты для создания распределенных, основанных
на Web, модульных и динамических решений для управления и мониторинга устройств,
приложений и сетей, основанных на услугах. По дизайну этот стандарт подходит для
адаптации устаревших систем, внедрения новых решений для управления и мониторинга и
подключения к будущим.

Examples

Простой пример с платформой MBean Server

Предположим, у нас есть сервер, который регистрирует новых пользователей и


приветствует их некоторым сообщением. И мы хотим контролировать этот сервер и
изменять некоторые его параметры.

Во-первых, нам нужен интерфейс с нашими методами контроля и контроля

public interface UserCounterMBean {


long getSleepTime();

void setSleepTime(long sleepTime);

int getUserCount();

void setUserCount(int userCount);

String getGreetingString();

void setGreetingString(String greetingString);

void stop();
}

И некоторая простая реализация, которая позволит нам увидеть, как она работает и как
мы ее влияем

public class UserCounter implements UserCounterMBean, Runnable {


private AtomicLong sleepTime = new AtomicLong(10000);
private AtomicInteger userCount = new AtomicInteger(0);
private AtomicReference<String> greetingString = new AtomicReference<>("welcome");
private AtomicBoolean interrupted = new AtomicBoolean(false);

@Override
public long getSleepTime() {
return sleepTime.get();
}

https://riptutorial.com/ru/home 130
@Override
public void setSleepTime(long sleepTime) {
this.sleepTime.set(sleepTime);
}

@Override
public int getUserCount() {
return userCount.get();
}

@Override
public void setUserCount(int userCount) {
this.userCount.set(userCount);
}

@Override
public String getGreetingString() {
return greetingString.get();
}

@Override
public void setGreetingString(String greetingString) {
this.greetingString.set(greetingString);
}

@Override
public void stop() {
this.interrupted.set(true);
}

@Override
public void run() {
while (!interrupted.get()) {
try {
System.out.printf("User %d, %s%n", userCount.incrementAndGet(),
greetingString.get());
Thread.sleep(sleepTime.get());
} catch (InterruptedException ignored) {
}
}
}
}

Для простого примера с локальным или удаленным управлением нам необходимо


зарегистрировать наш MBean:

import javax.management.InstanceAlreadyExistsException;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
import java.lang.management.ManagementFactory;

public class Main {


public static void main(String[] args) throws MalformedObjectNameException,
NotCompliantMBeanException, InstanceAlreadyExistsException, MBeanRegistrationException,
InterruptedException {

https://riptutorial.com/ru/home 131
final UserCounter userCounter = new UserCounter();
final MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
final ObjectName objectName = new ObjectName("ServerManager:type=UserCounter");
mBeanServer.registerMBean(userCounter, objectName);

final Thread thread = new Thread(userCounter);


thread.start();
thread.join();
}
}

После этого мы можем запустить наше приложение и подключиться к нему через jConsole,
который можно найти в каталоге $JAVA_HOME/bin . Во-первых, нам нужно найти наш
локальный процесс Java с нашим приложением

затем перейдите на вкладку MBeans и найдите MBean, который мы использовали в нашем


основном классе как ObjectName (в приведенном выше примере это ServerManager ). В разделе
« Attributes » мы видим атрибуты. Если вы указали только метод get, атрибут будет
доступен для чтения, но не может быть записан. Если вы указали методы get и set, атрибут
будет доступен для чтения и записи.

https://riptutorial.com/ru/home 132
Указанные методы могут быть вызваны в разделе « Operations ».

Если вы хотите использовать удаленное управление, вам понадобятся дополнительные


параметры JVM, например:

-Dcom.sun.management.jmxremote=true //true by default


-Dcom.sun.management.jmxremote.port=36006

https://riptutorial.com/ru/home 133
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false

Эти параметры можно найти в главе 2 руководств JMX . После этого вы сможете удаленно
подключиться к вашему приложению через jConsole с помощью jconsole host:port или с
указанием host:port или service:jmx:rmi:///jndi/rmi://hostName:portNum/jmxrmi в jConsole GUI.

Полезные ссылки:

• Руководства JMX
• Лучшие практики JMX

Прочитайте JMX онлайн: https://riptutorial.com/ru/java/topic/9278/jmx

https://riptutorial.com/ru/home 134
глава 26: JNDI
Examples

RMI через JNDI

В этом примере показано, как JNDI работает в RMI. Он имеет две роли:

• для предоставления серверу API-интерфейса bind / unbind / rebind в реестре RMI


• для предоставления клиенту API поиска / списка в реестре RMI.

Реестр RMI является частью RMI, а не JNDI.

Чтобы сделать это простым, мы будем использовать java.rmi.registry.CreateRegistry() для


создания реестра RMI.

1. Server.java (сервер JNDI)

package com.neohope.jndi.test;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.io.IOException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.util.Hashtable;

/**
* JNDI Server
* 1.create a registry on port 1234
* 2.bind JNDI
* 3.wait for connection
* 4.clean up and end
*/
public class Server {
private static Registry registry;
private static InitialContext ctx;

public static void initJNDI() {


try {
registry = LocateRegistry.createRegistry(1234);
final Hashtable jndiProperties = new Hashtable();
jndiProperties.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.rmi.registry.RegistryContextFactory");
jndiProperties.put(Context.PROVIDER_URL, "rmi://localhost:1234");
ctx = new InitialContext(jndiProperties);
} catch (NamingException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
}
}

https://riptutorial.com/ru/home 135
public static void bindJNDI(String name, Object obj) throws NamingException {
ctx.bind(name, obj);
}

public static void unbindJNDI(String name) throws NamingException {


ctx.unbind(name);
}

public static void unInitJNDI() throws NamingException {


ctx.close();
}

public static void main(String[] args) throws NamingException, IOException {


initJNDI();
NMessage msg = new NMessage("Just A Message");
bindJNDI("/neohope/jndi/test01", msg);
System.in.read();
unbindJNDI("/neohope/jndi/test01");
unInitJNDI();
}
}

2. Client.java (клиент JNDI)

package com.neohope.jndi.test;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.util.Hashtable;

/**
* 1.init context
* 2.lookup registry for the service
* 3.use the service
* 4.end
*/
public class Client {
public static void main(String[] args) throws NamingException {
final Hashtable jndiProperties = new Hashtable();
jndiProperties.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.rmi.registry.RegistryContextFactory");
jndiProperties.put(Context.PROVIDER_URL, "rmi://localhost:1234");

InitialContext ctx = new InitialContext(jndiProperties);


NMessage msg = (NeoMessage) ctx.lookup("/neohope/jndi/test01");
System.out.println(msg.message);
ctx.close();
}
}

3. NMessage.java (класс сервера RMI)

package com.neohope.jndi.test;

import java.io.Serializable;
import java.rmi.Remote;

https://riptutorial.com/ru/home 136
/**
* NMessage
* RMI server class
* must implements Remote and Serializable
*/
public class NMessage implements Remote, Serializable {
public String message = "";

public NMessage(String message)


{
this.message = message;
}
}

Как запустить eaxmple:

1. создавать и запускать сервер


2. создавать и запускать клиент

Вводить

Интерфейс именования и каталогов Java (JNDI) - это Java API для службы каталогов,
которая позволяет клиентам программного обеспечения Java обнаруживать и искать
данные и объекты через имя. Он разработан, чтобы быть независимым от какой-либо
конкретной реализации именования или службы каталогов.

Архитектура JNDI состоит из интерфейса API (Application Programming Interface) и SPI (


интерфейс поставщика услуг). Приложения Java используют этот API для доступа к
различным службам именования и каталогов. SPI позволяет подключать различные
службы имен и каталогов прозрачно, позволяя Java-приложению использовать API
технологии JNDI для доступа к своим службам.

https://riptutorial.com/ru/home 137
Как видно из рисунка выше, JNDI поддерживает LDAP, DNS, NIS, NDS, RMI и CORBA.
Конечно, вы можете продлить его.

Как это устроено

В этом примере Java RMI использует JNDI API для поиска объектов в сети. Если вы хотите
найти объект, вам нужно как минимум две части информации:

• Где найти объект

Реестр RMI управляет привязками имен, он сообщает вам, где найти объект.

• Имя объекта

Что такое имя объекта? Обычно это строка, она также может быть объектом, который
реализует интерфейс Name.

Шаг за шагом

1. Сначала вам нужен реестр, который управляет привязкой имени. В этом примере мы
используем java.rmi.registry.LocateRegistry .

//This will start a registry on localhost, port 1234


registry = LocateRegistry.createRegistry(1234);

2. И клиенту, и серверу нужен Контекст. Сервер использует контекст для привязки


имени и объекта. Клиент использует контекст для поиска имени и получения
объекта.

//We use com.sun.jndi.rmi.registry.RegistryContextFactory as the InitialContextFactory


final Hashtable jndiProperties = new Hashtable();
jndiProperties.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.rmi.registry.RegistryContextFactory");
//the registry usrl is "rmi://localhost:1234"
jndiProperties.put(Context.PROVIDER_URL, "rmi://localhost:1234");
InitialContext ctx = new InitialContext(jndiProperties);

3. Сервер связывает имя и объект

//The jndi name is "/neohope/jndi/test01"


bindJNDI("/neohope/jndi/test01", msg);

4. Клиент ищет объект по названию "/ neohope / jndi / test01"

//look up the object by name "java:com/neohope/jndi/test01"


NeoMessage msg = (NeoMessage) ctx.lookup("/neohope/jndi/test01");

5. Теперь клиент может использовать объект

https://riptutorial.com/ru/home 138
6. Когда сервер заканчивается, его необходимо очистить.

ctx.unbind("/neohope/jndi/test01");
ctx.close();

Прочитайте JNDI онлайн: https://riptutorial.com/ru/java/topic/5720/jndi

https://riptutorial.com/ru/home 139
глава 27: JShell
Вступление
JShell - это интерактивный REPL для Java, добавленный в JDK 9. Он позволяет
разработчикам мгновенно оценивать выражения, тестировать классы и
экспериментировать с языком Java. Ранний доступ для jdk 9 можно получить по адресу:
http://jdk.java.net/9/

Синтаксис
• $ jshell - Запустите JShell REPL
• jshell> / <command> - Запустить заданную команду JShell
• jshell> / exit - Выход JShell
• jshell> / help - список команд JShell
• jshell> <java_expression> - Оценить данное выражение Java (точка с запятой
необязательна)
• jshell> / vars OR / methods OR / types - См. список переменных, методов или классов,
соответственно.
• jshell> / open <файл> - читать файл в качестве ввода в оболочку
• jshell> / edit <идентификатор> - отредактируйте фрагмент в заданном редакторе
• jshell> / set editor <command> - установить команду, которая будет использоваться
для редактирования фрагментов с использованием / edit
• jshell> / drop <идентификатор> - удалить фрагмент
• jshell> / reset - Сбросить JVM и удалить все фрагменты

замечания
JShell требует Java 9 JDK, который в настоящее время (март 2017) можно загрузить как
ранние снимки доступа из jdk9.java.net . Если при попытке запустить команду jshell вы
получите сообщение об ошибке, начинающееся с « Unable to locate an executable ,
убедитесь, что JAVA_HOME установлен правильно.

Импорт по умолчанию
Следующие пакеты автоматически импортируются при запуске JShell:

import java.io.*
import java.math.*
import java.net.*
import java.nio.file.*
import java.util.*

https://riptutorial.com/ru/home 140
import java.util.concurrent.*
import java.util.function.*
import java.util.prefs.*
import java.util.regex.*
import java.util.stream.*

Examples

Вход и выход JShell

Запуск JShell
Прежде чем пытаться запустить JShell, убедитесь, что переменная окружения JAVA_HOME
указывает на установку JDK 9. Чтобы запустить JShell, выполните следующую команду:

$ jshell

Если все пойдет хорошо, вы увидите jshell> .

Выход из JShell
Чтобы выйти из JShell, запустите следующую команду из приглашения JShell:

jshell> /exit

Выражения

В JShell вы можете оценивать выражения Java с запятой или без нее. Они могут
варьироваться от базовых выражений и операторов до более сложных:

jshell> 4+2
jshell> System.out.printf("I am %d years old.\n", 421)

Петли и условные обозначения тоже прекрасны:

jshell> for (int i = 0; i<3; i++) {


...> System.out.println(i);
...> }

Важно отметить, что выражения внутри блоков должны иметь точки с запятой!

переменные

Вы можете объявлять локальные переменные в JShell:

https://riptutorial.com/ru/home 141
jshell> String s = "hi"
jshell> int i = s.length

Имейте в виду, что переменные могут быть переоформлены разными типами; это
совершенно справедливо в JShell:

jshell> String var = "hi"


jshell> int var = 3

Чтобы просмотреть список переменных, введите /vars в приглашении JShell.

Методы и классы

Вы можете определить методы и классы в JShell:

jshell> void speak() {


...> System.out.println("hello");
...> }

jshell> class MyClass {


...> void doNothing() {}
...> }

Не требуется модификаторов доступа. Как и в других блоках, точки с запятой требуются


внутри тел метода. Имейте в виду, что, как и в случае с переменными, можно
переопределить методы и классы. Чтобы просмотреть список методов или классов,
введите /methods или /types в приглашении JShell, соответственно.

Редактирование фрагментов

Основной единицей кода, используемой JShell, является фрагмент или исходная запись .
Каждый раз, когда вы объявляете локальную переменную или определяете локальный
метод или класс, вы создаете фрагмент, чье имя является идентификатором переменной /
метода / класса. В любой момент вы можете отредактировать фрагмент, который вы
создали с помощью команды /edit . Например, допустим, я создал класс Foo с помощью
одного метода, bar :

jshell> class Foo {


...> void bar() {
...> }
...> }

Теперь я хочу заполнить тело моего метода. Вместо того, чтобы переписывать весь класс,
я могу его отредактировать:

jshell> /edit Foo

https://riptutorial.com/ru/home 142
По умолчанию редактор swing появится с наиболее доступными функциями. Однако вы
можете изменить редактор, который использует JShell:

jshell> /set editor emacs


jshell> /set editor vi
jshell> /set editor nano
jshell> /set editor -default

Обратите внимание, что если новая версия фрагмента содержит любые


синтаксические ошибки, она может быть не сохранена. Аналогично, фрагмент
создается только в том случае, если оригинальное объявление / определение является
синтаксически правильным; следующее не работает:

jshell> String st = String 3


//error omitted
jshell> /edit st
| No such snippet: st

Тем не менее, фрагменты могут быть скомпилированы и, следовательно, доступны для


редактирования, несмотря на некоторые ошибки времени компиляции, такие как
несогласованные типы - следующие работы:

jshell> int i = "hello"


//error omitted
jshell> /edit i

Наконец, фрагменты могут быть удалены с помощью команды /drop :

jshell> int i = 13
jshell> /drop i
jshell> System.out.println(i)
| Error:
| cannot find symbol
| symbol: variable i
| System.out.println(i)
|

Чтобы удалить все фрагменты, тем самым переиздав состояние JVM, используйте \reset :

jshell> int i = 2

jshell> String s = "hi"

jshell> /reset
| Resetting state.

jshell> i
| Error:
| cannot find symbol
| symbol: variable i
| i
| ^

https://riptutorial.com/ru/home 143
jshell> s
| Error:
| cannot find symbol
| symbol: variable s
| s
| ^

Прочитайте JShell онлайн: https://riptutorial.com/ru/java/topic/9511/jshell

https://riptutorial.com/ru/home 144
глава 28: JSON в Java
Вступление
JSON (JavaScript Object Notation) представляет собой легкий, текстовый, независимый от
языка формат обмена данными, который легко людям и машинам читать и писать. JSON
может представлять два структурированных типа: объекты и массивы. JSON часто
используется в приложениях Ajax, конфигурациях, базах данных и веб-службах RESTful.
Java API для JSON Processing предоставляет портативные API для анализа, генерации,
преобразования и запроса JSON.

замечания
В этом примере основное внимание уделяется разбору и созданию JSON в Java с
использованием различных библиотек, таких как библиотека Google Gson , Jackson Object
Mapper и другие.

Примеры использования других библиотек можно найти здесь: Как разбирать JSON в Java

Examples

Кодирование данных как JSON

Если вам нужно создать JSONObject и поместить в него данные, рассмотрите следующий
пример:

// Create a new javax.json.JSONObject instance.


JSONObject first = new JSONObject();

first.put("foo", "bar");
first.put("temperature", 21.5);
first.put("year", 2016);

// Add a second object.


JSONObject second = new JSONObject();
second.put("Hello", "world");
first.put("message", second);

// Create a new JSONArray with some values


JSONArray someMonths = new JSONArray(new String[] { "January", "February" });
someMonths.put("March");
// Add another month as the fifth element, leaving the 4th element unset.
someMonths.put(4, "May");

// Add the array to our object


object.put("months", someMonths);

// Encode

https://riptutorial.com/ru/home 145
String json = object.toString();

// An exercise for the reader: Add pretty-printing!


/* {
"foo":"bar",
"temperature":21.5,
"year":2016,
"message":{"Hello":"world"},
"months":["January","February","March",null,"May"]
}
*/

Декодирование данных JSON

Если вам нужно получить данные из JSONObject , рассмотрите следующий пример:

String json =
"{\"foo\":\"bar\",\"temperature\":21.5,\"year\":2016,\"message\":{\"Hello\":\"world\"},\"months\":[\"Ja

// Decode the JSON-encoded string


JSONObject object = new JSONObject(json);

// Retrieve some values


String foo = object.getString("foo");
double temperature = object.getDouble("temperature");
int year = object.getInt("year");

// Retrieve another object


JSONObject secondary = object.getJSONObject("message");
String world = secondary.getString("Hello");

// Retrieve an array
JSONArray someMonths = object.getJSONArray("months");
// Get some values from the array
int nMonths = someMonths.length();
String february = someMonths.getString(1);

optXXX vs getXXX

и JSONArray есть несколько методов, которые очень полезны при работе с


JSONObject
возможностью того, что значение, которое вы пытаетесь получить, не существует или
имеет другой тип.

JSONObject obj = new JSONObject();


obj.putString("foo", "bar");

// For existing properties of the correct type, there is no difference


obj.getString("foo"); // returns "bar"
obj.optString("foo"); // returns "bar"
obj.optString("foo", "tux"); // returns "bar"

// However, if a value cannot be coerced to the required type, the behavior differs
obj.getInt("foo"); // throws JSONException
obj.optInt("foo"); // returns 0
obj.optInt("foo", 123); // returns 123

https://riptutorial.com/ru/home 146
// Same if a property does not exist
obj.getString("undefined"); // throws JSONException
obj.optString("undefined"); // returns ""
obj.optString("undefined", "tux"); // returns "tux"

Те же правила применяются к getXXX / optXXX JSONArray .

Объект для JSON (библиотека Gson)

Допустим, у вас есть класс под названием Person с просто name

private class Person {


public String name;

public Person(String name) {


this.name = name;
}
}

Код:

Gson g = new Gson();

Person person = new Person("John");


System.out.println(g.toJson(person)); // {"name":"John"}

Конечно, банда Gson должна быть на пути к классу .

JSON To Object (Библиотека Gson)

Допустим, у вас есть класс под названием Person с просто name

private class Person {


public String name;

public Person(String name) {


this.name = name;
}
}

Код:

Gson gson = new Gson();


String json = "{\"name\": \"John\"}";

Person person = gson.fromJson(json, Person.class);


System.out.println(person.name); //John

У вас должна быть библиотека gson в вашем пути к классам.

https://riptutorial.com/ru/home 147
Извлечение одного элемента из JSON

String json = "{\"name\": \"John\", \"age\":21}";

JsonObject jsonObject = new JsonParser().parse(json).getAsJsonObject();

System.out.println(jsonObject.get("name").getAsString()); //John
System.out.println(jsonObject.get("age").getAsInt()); //21

Использование Mapper объекта Jackson

Модель Pojo

public class Model {


private String firstName;
private String lastName;
private int age;
/* Getters and setters not shown for brevity */
}

Пример: String to Object

Model outputObject = objectMapper.readValue(


"{\"firstName\":\"John\",\"lastName\":\"Doe\",\"age\":23}",
Model.class);
System.out.println(outputObject.getFirstName());
//result: John

Пример: объект для строки

String jsonString = objectMapper.writeValueAsString(inputObject));


//result: {"firstName":"John","lastName":"Doe","age":23}

подробности
Необходима операция импорта:

import com.fasterxml.jackson.databind.ObjectMapper;

Зависимость Maven: jackson-databind

Экземпляр ObjectMapper

//creating one
ObjectMapper objectMapper = new ObjectMapper();

• ObjectMapper является поточно

https://riptutorial.com/ru/home 148
• рекомендуется: иметь общий статический экземпляр

Десериализация:

<T> T readValue(String content, Class<T> valueType)

• valueType необходимо указать - возврат будет такого типа


• Броски
○ IOException - в случае проблемы ввода-вывода низкого уровня
○ JsonParseException - если базовый ввод содержит недопустимый контент
○ JsonMappingException - если входная структура JSON не соответствует структуре
объекта

Пример использования (jsonString - входная строка):

Model fromJson = objectMapper.readValue(jsonString, Model.class);

Метод сериализации:
String writeValueAsString (значение объекта)

• Броски
○ в случае ошибки
JsonProcessingException
○ Примечание: до версии 2.1 предложение бросков включено в IOException; 2.1
удалили его.

Итерация JSON

JSONObject над свойствами JSONObject

JSONObject obj = new JSONObject("{\"isMarried\":\"true\", \"name\":\"Nikita\",


\"age\":\"30\"}");
Iterator<String> keys = obj.keys();//all keys: isMarried, name & age
while (keys.hasNext()) { //as long as there is another key
String key = keys.next(); //get next key
Object value = obj.get(key); //get next value by key
System.out.println(key + " : " + value);//print key : value
}

Итерировать значения JSONArray

JSONArray arr = new JSONArray(); //Initialize an empty array


//push (append) some values in:
arr.put("Stack");
arr.put("Over");
arr.put("Flow");
for (int i = 0; i < arr.length(); i++) {//iterate over all values

https://riptutorial.com/ru/home 149
Object value = arr.get(i); //get value
System.out.println(value); //print each value
}

JSON Builder - методы цепочки

Вы можете использовать цепочку методов при работе с JSONObject и JSONArray .

Пример JSONObject

JSONObject obj = new JSONObject();//Initialize an empty JSON object


//Before: {}
obj.put("name","Nikita").put("age","30").put("isMarried","true");
//After: {"name":"Nikita","age":30,"isMarried":true}

JSONArray

JSONArray arr = new JSONArray();//Initialize an empty array


//Before: []
arr.put("Stack").put("Over").put("Flow");
//After: ["Stack","Over","Flow"]

JSONObject.NULL

Если вам нужно добавить свойство с null значением, вы должны использовать


предопределенный статический конечный JSONObject.NULL а не стандартную Java- null
ссылку.

- это контрольное значение, используемое для явного определения


JSONObject.NULL
свойства с пустым значением.

JSONObject obj = new JSONObject();


obj.put("some", JSONObject.NULL); //Creates: {"some":null}
System.out.println(obj.get("some"));//prints: null

Заметка

JSONObject.NULL.equals(null); //returns true

Что является явным нарушением контракта Java.equals() :

Для любого ненулевого опорного значения х, x.equals (NULL) должен


возвращать ложь

JsonArray в список Java (Gson Library)

Вот простой JsonArray, который вы хотели бы преобразовать в Java ArrayList :

https://riptutorial.com/ru/home 150
{
"list": [
"Test_String_1",
"Test_String_2"
]
}

Теперь передайте список JsonArray 'следующему методу, который возвращает


соответствующий Java ArrayList :

public ArrayList<String> getListString(String jsonList){


Type listType = new TypeToken<List<String>>() {}.getType();
//make sure the name 'list' matches the name of 'JsonArray' in your 'Json'.
ArrayList<String> list = new Gson().fromJson(jsonList, listType);
return list;
}

Вы должны добавить следующую зависимость maven к вашему файлу POM.xml :

<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->


<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.7</version>
</dependency>

Или у вас должен быть jar com.google.code.gson:gson:jar:<version> в вашем пути к классам.

Уничтожьте коллекцию JSON в коллекции объектов, используя Jackson

Предположим , у вас есть класс POJO Person

public class Person {


public String name;

public Person(String name) {


this.name = name;
}
}

И вы хотите разобрать его в массив JSON или карту объектов Person. Из-за стирания типа
вы не можете создавать классы List<Person> и Map<String, Person> непосредственно во время
выполнения (и, следовательно, использовать их для десериализации JSON) . Чтобы
преодолеть это ограничение, Джексон предлагает два подхода - TypeFactory и TypeReference
.

TypeFactory

Подход, использованный здесь, заключается в использовании фабрики (и ее статической


функции полезности) для создания вашего типа для вас. Требуемые параметры - это
коллекция, которую вы хотите использовать (список, набор и т. Д.) И класс, который вы

https://riptutorial.com/ru/home 151
хотите сохранить в этой коллекции.

TypeReference

Тип ссылочного подхода кажется более простым, поскольку он экономит вам немного
ввода и выглядит более чистым. TypeReference принимает параметр типа, в котором вы
передаете желаемый тип List<Person> . Вы просто создаете экземпляр объекта
TypeReference и используете его в качестве контейнера типа.

Теперь давайте посмотрим, как фактически десериализовать JSON в объект Java. Если
ваш JSON отформатирован как массив, вы можете десериализовать его как список. Если
существует более сложная вложенная структура, вам необходимо десериализовать карту.
Мы рассмотрим примеры обоих.

Удаление десериализации массива JSON


String jsonString = "[{\"name\": \"Alice\"}, {\"name\": \"Bob\"}]"

Подход TypeFactory

CollectionType listType =
factory.constructCollectionType(List.class, Person.class);
List<Preson> list = mapper.readValue(jsonString, listType);

Подход типа Type

TypeReference<Person> listType = new TypeReference<List<Person>>() {};


List<Person> list = mapper.readValue(jsonString, listType);

Десериализация карты JSON


String jsonString = "{\"0\": {\"name\": \"Alice\"}, \"1\": {\"name\": \"Bob\"}}"

Подход TypeFactory

CollectionType mapType =
factory.constructMapLikeType(Map.class, String.class, Person.class);
List<Person> list = mapper.readValue(jsonString, mapType);

Подход типа Type

https://riptutorial.com/ru/home 152
TypeReference<Person> mapType = new TypeReference<Map<String, Person>>() {};
Map<String, Person> list = mapper.readValue(jsonString, mapType);

подробности
Используемая инструкция импорта:

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.CollectionType;

Используемые экземпляры:

ObjectMapper mapper = new ObjectMapper();


TypeFactory factory = mapper.getTypeFactory();

Заметка
Хотя подход TypeReference может выглядеть лучше, он имеет несколько недостатков:

1. TypeReference должен быть TypeReference с использованием анонимного класса


2. Вы должны предоставить общую экспликацию

Несоблюдение этого может привести к потере аргумента общего типа, что приведет к
неудаче десериализации.

Прочитайте JSON в Java онлайн: https://riptutorial.com/ru/java/topic/840/json-в-java

https://riptutorial.com/ru/home 153
глава 29: LinkedHashMap
Вступление
Класс LinkedHashMap - это таблица Hash и реализация Linked list интерфейса Map с
предсказуемым порядком итерации. Он наследует класс HashMap и реализует интерфейс
карты.

Важными моментами для класса Java LinkedHashMap являются: LinkedHashMap содержит


значения, основанные на ключе. Он содержит только уникальные элементы. Он может
иметь один нулевой ключ и несколько нулевых значений. Это то же самое, что и HashMap,
поддерживает порядок вставки.

Examples

Класс Java LinkedHashMap

Ключевые моменты: -

• Является ли таблица Hash и связанный список интерфейсом Map с предсказуемым


порядком итерации.

• наследует класс HashMap и реализует интерфейс карты.

• содержит значения на основе ключа.

• только уникальные элементы.

• может иметь один нулевой ключ и несколько нулевых значений.

• то же, что и HashMap, поддерживает порядок вставки.

Методы: -

• void clear ().


• boolean containsKey (ключ объекта).
• Объект get (ключ объекта).
• protected boolean removeEldestEntry (Map.Entry старший)

Пример :-

public static void main(String arg[])


{
LinkedHashMap<String, String> lhm = new LinkedHashMap<String, String>();
lhm.put("Ramesh", "Intermediate");

https://riptutorial.com/ru/home 154
lhm.put("Shiva", "B-Tech");
lhm.put("Santosh", "B-Com");
lhm.put("Asha", "Msc");
lhm.put("Raghu", "M-Tech");

Set set = lhm.entrySet();


Iterator i = set.iterator();
while (i.hasNext()) {
Map.Entry me = (Map.Entry) i.next();
System.out.println(me.getKey() + " : " + me.getValue());
}

System.out.println("The Key Contains : " + lhm.containsKey("Shiva"));


System.out.println("The value to the corresponding to key : " + lhm.get("Asha"));
}

Прочитайте LinkedHashMap онлайн: https://riptutorial.com/ru/java/topic/10750/linkedhashmap

https://riptutorial.com/ru/home 155
глава 30: log4j / log4j2
Вступление
Apache Log4j - это утилита ведения журнала на основе Java, это одна из нескольких
фреймворков регистрации Java. В этом разделе показано, как настроить и настроить Log4j
на Java с подробными примерами по всем возможным аспектам использования.

Синтаксис
• Logger.debug («текст для журнала»); // Регистрация информации об отладке
• Logger.info («текст для регистрации»); // Регистрация общей информации
• Logger.error («текст для регистрации»); // Запись информации об ошибке
• Logger.warn («текст для регистрации»); // Предупреждения о регистрации
• Logger.trace («текст для регистрации»); // Запись информации о трассировке
• Logger.fatal («текст для регистрации»); // Регистрация фатальных ошибок
• Использование Log4j2 с протоколированием параметров:
• Logger.debug («Debug params {} {} {}", param1, param2, param3); // Регистрация отладки
с параметрами
• Logger.info («Info params {} {} {}", param1, param2, param3); // Запись информации с
параметрами
• Logger.error («Параметры ошибки {} {} {}", param1, param2, param3); // Ошибка
регистрации с параметрами
• Logger.warn ("Warn params {} {} {}", param1, param2, param3); // Запись предупреждений
с параметрами
• Logger.trace («Параметры трассировки {} {} {}", param1, param2, param3); // Ведение
журнала с параметрами
• Logger.fatal («Фатальные параметры {} {} {}", param1, param2, param3); // Регистрация
фатальных данных с параметрами
• Logger.error («Caught Exception:», ex); // Исключение журнала с сообщением и
stacktrace (будет автоматически добавлено)

замечания

Конец жизни для Log4j 1 достигнут


5 августа 2015 года Комитет по управлению проектами в области лесозаготовок
объявил, что Log4j 1.x достигло конца жизни. Полный текст объявления можно
найти в блоге Apache. Пользователям Log4j 1 рекомендуется обновить до
Apache Log4j 2 .

https://riptutorial.com/ru/home 156
От: http://logging.apache.org/log4j/1.2/

Examples

Как получить Log4j

Текущая версия (log4j2)

Использование Maven:
Добавьте в свой файл POM.xml следующую зависимость:

<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.6.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.6.2</version>
</dependency>
</dependencies>

Использование Айви:

<dependencies>
<dependency org="org.apache.logging.log4j" name="log4j-api" rev="2.6.2" />
<dependency org="org.apache.logging.log4j" name="log4j-core" rev="2.6.2" />
</dependencies>

Использование Gradle:

dependencies {
compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.6.2'
compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.6.2'
}

Получение log4j 1.x

Примечание: Log4j 1.x достигло конца жизни (EOL) (см. Примечания).

Использование Maven:

Объявите эту зависимость в файле POM.xml :

https://riptutorial.com/ru/home 157
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>

Использование Айви:

<dependency org="log4j" name="log4j" rev="1.2.17"/>

Usign Gradle:

compile group: 'log4j', name: 'log4j', version: '1.2.17'

Использование Buildr:

'log4j:log4j:jar:1.2.17'

Добавление вручную в сборку пути:

Загрузить с веб-сайта проекта Log4j

Как использовать Log4j в Java-коде

Сначала необходимо создать final static logger объект final static logger :

final static Logger logger = Logger.getLogger(classname.class);

Затем вызовите методы ведения журнала:

//logs an error message


logger.info("Information about some param: " + parameter); // Note that this line could throw
a NullPointerException!

//in order to improve performance, it is advised to use the `isXXXEnabled()` Methods


if( logger.isInfoEnabled() ){
logger.info("Information about some param: " + parameter);
}

// In log4j2 parameter substitution is preferable due to readability and performance


// The parameter substitution only takes place if info level is active which obsoletes the use
of isXXXEnabled().
logger.info("Information about some param: {}" , parameter);

//logs an exception
logger.error("Information about some error: ", exception);

Настройка файла свойств

Log4j дает вам возможность записывать данные в консоль и файл одновременно.

https://riptutorial.com/ru/home 158
Создайте файл log4j.properties и вставьте эту базовую конфигурацию:

# Root logger option


log4j.rootLogger=DEBUG, stdout, file

# Redirect log messages to console


log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

# Redirect log messages to a log file, support file rolling.


log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=C:\\log4j-application.log
log4j.appender.file.MaxFileSize=5MB
log4j.appender.file.MaxBackupIndex=10
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

Если вы используете maven, поместите этот файл свойства в путь:

/ProjectFolder/src/java/resources

Базовый файл конфигурации log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>


<Configuration>
<Appenders>
<Console name="STDOUT" target="SYSTEM_OUT">
<PatternLayout pattern="%d %-5p [%t] %C{2} %m%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="debug">
<AppenderRef ref="STDOUT"/>
</Root>
</Loggers>
</Configuration>

Это базовая конфигурация log4j2.xml с консольным приложением и корневым


регистратором. В макете шаблона указывается, какой шаблон следует использовать для
регистрации операторов.
Чтобы отладить загрузку log4j2.xml, вы можете добавить status = <WARN | DEBUG | ERROR |
FATAL | TRACE | INFO> атрибута status = <WARN | DEBUG | ERROR | FATAL | TRACE | INFO> в теге
конфигурации вашего log4j2.xml.
Вы также можете добавить интервал монитора, чтобы он снова загрузил конфигурацию
после указанного интервала времени. Интервал мониторинга может быть добавлен в тег
конфигурации следующим образом: monitorInterval = 30 . Это означает, что конфигурация
будет загружаться каждые 30 секунд.

Миграция с log4j 1.x на 2.x

https://riptutorial.com/ru/home 159
Если вы хотите перенести из существующего log4j 1.x в свой проект на log4j 2.x, удалите
все существующие зависимости log4j 1.x и добавьте следующую зависимость:

Log4j 1.x API Bridge

Maven Build

<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-1.2-api</artifactId>
<version>2.6.2</version>
</dependency>
</dependencies>

Ivy Build

<dependencies>
<dependency org="org.apache.logging.log4j" name="log4j-1.2-api" rev="2.6.2" />
</dependencies>

Gradle Build

dependencies {
compile group: 'org.apache.logging.log4j', name: 'log4j-1.2-api', version: '2.6.2'
}

Мост ведения журнала Apache Commons Если ваш проект использует журнал
регистрации Apache, который использует log4j 1.x, и вы хотите перенести его на log4j 2.x,
то добавьте следующие зависимости:

Maven Build

<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jcl</artifactId>
<version>2.6.2</version>
</dependency>
</dependencies>

Ivy Build

<dependencies>
<dependency org="org.apache.logging.log4j" name="log4j-jcl" rev="2.6.2" />
</dependencies>

Gradle Build

dependencies {
compile group: 'org.apache.logging.log4j', name: 'log4j-jcl', version: '2.6.2'

https://riptutorial.com/ru/home 160
}

Примечание. Не удаляйте никаких существующих зависимостей записи в архивах Apache

Ссылка: https://logging.apache.org/log4j/2.x/maven-artifacts.html

Свойства-Файл для входа в БД

Для этого примера вам понадобится драйвер JDBC, совместимый с системой, в которой
работает база данных. С открытым исходным кодом, который позволяет подключаться к
базам данных DB2 в системе IBM, можно найти здесь: JT400

Несмотря на то, что этот пример специфичен для DB2, он работает практически для любой
другой системы, если вы меняете драйвер и адаптируете URL JDBC.

# Root logger option


log4j.rootLogger= ERROR, DB

# Redirect log messages to a DB2


# Define the DB appender
log4j.appender.DB=org.apache.log4j.jdbc.JDBCAppender

# Set JDBC URL (!!! adapt to your target system !!!)


log4j.appender.DB.URL=jdbc:as400://10.10.10.1:446/DATABASENAME;naming=system;errors=full;

# Set Database Driver (!!! adapt to your target system !!!)


log4j.appender.DB.driver=com.ibm.as400.access.AS400JDBCDriver

# Set database user name and password


log4j.appender.DB.user=USER
log4j.appender.DB.password=PASSWORD

# Set the SQL statement to be executed.


log4j.appender.DB.sql=INSERT INTO DB.TABLENAME VALUES('%d{yyyy-MM-
dd}','%d{HH:mm:ss}','%C','%p','%m')

# Define the layout for file appender


log4j.appender.DB.layout=org.apache.log4j.PatternLayout

Выйти из фильтра по уровню (log4j 1.x)

Вы можете использовать фильтр для регистрации только сообщений «ниже», чем,


например, уровень ERROR . Но фильтр не поддерживается PropertyConfigurator. Поэтому
вы должны перейти на конфигурацию XML, чтобы использовать его . См. Log4j-Wiki об
фильтрах .

Пример "конкретный уровень"

<appender name="info-out" class="org.apache.log4j.FileAppender">


<param name="File" value="info.log"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%m%n"/>

https://riptutorial.com/ru/home 161
</layout>
<filter class="org.apache.log4j.varia.LevelMatchFilter">
<param name="LevelToMatch" value="info" />
<param name="AcceptOnMatch" value="true"/>
</filter>
<filter class="org.apache.log4j.varia.DenyAllFilter" />
</appender>

Или "Диапазон уровней"

<appender name="info-out" class="org.apache.log4j.FileAppender">


<param name="File" value="info.log"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%m%n"/>
</layout>
<filter class="org.apache.log4j.varia.LevelRangeFilter">
<param name="LevelMax" value="info"/>
<param name="LevelMin" value="info"/>
<param name="AcceptOnMatch" value="true"/>
</filter>
</appender>

Прочитайте log4j / log4j2 онлайн: https://riptutorial.com/ru/java/topic/2472/log4j---log4j2

https://riptutorial.com/ru/home 162
глава 31: NIO - Сеть
замечания
определяет различные выбираемые операции и информацию между его
SelectionKey
Селектором и Каналом . В частности, вложение может использоваться для хранения
связанной с подключением информации.

Обработка OP_READ довольно прямолинейна. Однако следует соблюдать осторожность при


работе с OP_WRITE : большую часть времени данные могут быть записаны в сокеты, чтобы
событие продолжало стрелять. Обязательно зарегистрируйте OP_WRITE только до того, как
вы захотите записать данные (см. OP_WRITE ответ ).

Кроме того , OP_CONNECT должен быть отменен после того , как канал был подключен (потому
что, ну, это связано. См это и что ответы на SO). Следовательно, удаление OP_CONNECT после
finishConnect() преуспело.

Examples

Использование Selector для ожидания событий (пример с OP_CONNECT)

NIO появился на Java 1.4 и представил концепцию «Каналы», которые должны быть
быстрее, чем обычные входы / выходы. По сетевому интерфейсу SelectableChannel является
самым интересным, поскольку он позволяет контролировать различные состояния канала.
Он работает так же, как и системный вызов C select() : мы пробуждаемся, когда
происходят определенные типы событий:

• полученное соединение ( OP_ACCEPT )


• реализовано соединение ( OP_CONNECT )
• данные доступны в считываемом FIFO ( OP_READ )
• данные могут быть OP_WRITE для записи FIFO ( OP_WRITE )

Он позволяет разделить между обнаружением ввода-вывода сокетов (что-то можно


прочитать / записать / ...) и выполнить ввод-вывод (чтение / запись / ...). В частности, все
обнаружение ввода-вывода может выполняться в одном потоке для нескольких сокетов
(клиентов), в то время как операции ввода-вывода могут обрабатываться в пуле потоков
или в другом месте. Это позволяет легко масштабировать приложение до количества
подключенных клиентов.

В следующем примере показаны основы:

1. Создать Selector
2. Создание SocketChannel

https://riptutorial.com/ru/home 163
3. Зарегистрируйте SocketChannel для Selector
4. Цикл с Selector для обнаружения событий

Selector sel = Selector.open(); // Create the Selector


SocketChannel sc = SocketChannel.open(); // Create a SocketChannel
sc.configureBlocking(false); // ... non blocking
sc.setOption(StandardSocketOptions.SO_KEEPALIVE, true); // ... set some options

// Register the Channel to the Selector for wake-up on CONNECT event and use some description
as an attachement
sc.register(sel, SelectionKey.OP_CONNECT, "Connection to google.com"); // Returns a
SelectionKey: the association between the SocketChannel and the Selector
System.out.println("Initiating connection");
if (sc.connect(new InetSocketAddress("www.google.com", 80)))
System.out.println("Connected"); // Connected right-away: nothing else to do
else {
boolean exit = false;
while (!exit) {
if (sel.select(100) == 0) // Did something happen on some registered Channels during
the last 100ms?
continue; // No, wait some more

// Something happened...
Set<SelectionKey> keys = sel.selectedKeys(); // List of SelectionKeys on which some
registered operation was triggered
for (SelectionKey k : keys) {
System.out.println("Checking "+k.attachment());
if (k.isConnectable()) { // CONNECT event
System.out.print("Connected through select() on "+k.channel()+" -> ");
if (sc.finishConnect()) { // Finish connection process
System.out.println("done!");
k.interestOps(k.interestOps() & ~SelectionKey.OP_CONNECT); // We are
already connected: remove interest in CONNECT event
exit = true;
} else
System.out.println("unfinished...");
}
// TODO: else if (k.isReadable()) { ...
}
keys.clear(); // Have to clear the selected keys set once processed!
}
}
System.out.print("Disconnecting ... ");
sc.shutdownOutput(); // Initiate graceful disconnection
// TODO: emtpy receive buffer
sc.close();
System.out.println("done");

Дала бы следующий результат:

Initiating connection
Checking Connection to google.com
Connected through 'select()' on java.nio.channels.SocketChannel[connection-pending
remote=www.google.com/216.58.208.228:80] -> done!
Disconnecting ... done

Прочитайте NIO - Сеть онлайн: https://riptutorial.com/ru/java/topic/5513/nio---сеть

https://riptutorial.com/ru/home 164
глава 32: NumberFormat
Examples
NumberFormat

В разных странах существуют разные форматы чисел, и, учитывая это, мы можем


использовать разные форматы, используя язык Java. Использование языка может помочь
в форматировании

Locale locale = new Locale("en", "IN");


NumberFormat numberFormat = NumberFormat.getInstance(locale);

используя вышеуказанный формат, вы можете выполнять различные задачи

1. Номер формата

numberFormat.format(10000000.99);

2. Формат валюты

NumberFormat currencyFormat = NumberFormat.getCurrencyInstance(locale);


currencyFormat.format(10340.999);

3. Формат Процент

NumberFormat percentageFormat = NumberFormat.getPercentInstance(locale);


percentageFormat.format(10929.999);

4. Контрольное число цифр

numberFormat.setMinimumIntegerDigits(int digits)
numberFormat.setMaximumIntegerDigits(int digits)
numberFormat.setMinimumFractionDigits(int digits)
numberFormat.setMaximumFractionDigits(int digits)

Прочитайте NumberFormat онлайн: https://riptutorial.com/ru/java/topic/7399/numberformat

https://riptutorial.com/ru/home 165
глава 33: ServiceLoader
замечания
может использоваться для получения экземпляров классов, расширяющих
ServiceLoader
данный тип (= служба), которые указаны в файле, упакованном в файл .jar . Сервис,
который расширен / реализован, часто является интерфейсом, но это не требуется.

Расширяющиеся / реализующие классы должны предоставить конструктор нулевого


аргумента для ServiceLoader для их создания.

Чтобы быть обнаруженным ServiceLoader текстовый файл с именем полного имени типа
внедренной службы должен храниться внутри каталога META-INF/services в файле jar. Этот
файл содержит одно полное имя класса, реализующего службу на строку.

Examples

Служба регистрации

В следующем примере показано, как создать экземпляр класса для ведения журнала через
ServiceLoader .

обслуживание
package servicetest;

import java.io.IOException;

public interface Logger extends AutoCloseable {

void log(String message) throws IOException;


}

Реализация услуги
Следующая реализация просто записывает сообщение в System.err

package servicetest.logger;

import servicetest.Logger;

public class ConsoleLogger implements Logger {

@Override
public void log(String message) {

https://riptutorial.com/ru/home 166
System.err.println(message);
}

@Override
public void close() {
}

Следующая реализация записывает сообщения в текстовый файл:

package servicetest.logger;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import servicetest.Logger;

public class FileLogger implements Logger {

private final BufferedWriter writer;

public FileLogger() throws IOException {


writer = new BufferedWriter(new FileWriter("log.txt"));
}

@Override
public void log(String message) throws IOException {
writer.append(message);
writer.newLine();
}

@Override
public void close() throws IOException {
writer.close();
}

META-INF / услуги / servicetest.Logger


В файле META-INF/services/servicetest.Logger перечислены имена реализации Logger .

servicetest.logger.ConsoleLogger
servicetest.logger.FileLogger

использование
Следующий main метод записывает сообщение всем доступным регистраторам.
Регистраторы создаются с использованием ServiceLoader .

https://riptutorial.com/ru/home 167
public static void main(String[] args) throws Exception {
final String message = "Hello World!";

// get ServiceLoader for Logger


ServiceLoader<Logger> loader = ServiceLoader.load(servicetest.Logger.class);

// iterate through instances of available loggers, writing the message to each one
Iterator<Logger> iterator = loader.iterator();
while (iterator.hasNext()) {
try (Logger logger = iterator.next()) {
logger.log(message);
}
}
}

Простой пример ServiceLoader

ServiceLoader - простой и простой в использовании встроенный механизм динамической


загрузки реализаций интерфейса. С помощью сервис-загрузчика - обеспечения средств
для создания (но не для проводки) - в Java SE может быть встроен простой механизм
впрыска зависимостей. Интерфейс ServiceLoader и разделение реализации становятся
естественными, и программы могут быть удобно расширены. На самом деле многие Java
API внедрены на основе ServiceLoader

Основные понятия

• Работа на интерфейсах услуг


• Получение реализации (-ов) службы через ServiceLoader
• Обеспечение внедрения сервисов

Давайте начнем с интерфейса и поместим его в банку, названную, например, accounting-


api.jar

package example;

public interface AccountingService {

long getBalance();
}

Теперь мы предоставляем реализацию этой службы в банке с именем accounting-impl.jar ,


содержащей реализацию услуги

package example.impl;
import example.AccountingService;

public interface DefaultAccountingService implements AccouningService {

public long getBalance() {


return balanceFromDB();
}

private long balanceFromDB(){

https://riptutorial.com/ru/home 168
...
}
}

далее, accounting-impl.jar содержит файл, объявляющий, что эта банка обеспечивает


реализацию AccountingService . Файл должен иметь путь, начинающийся с META-INF/services/
и должен иметь то же имя, что и полное имя интерфейса:

• META-INF/services/example.AccountingService

Содержимое файла является полностью qualfified имя реализации:

example.impl.DefaultAccountingService

Поскольку обе банки находятся в пути к классам программы, которая потребляет


AccountingService , экземпляр службы может быть получен с помощью ServiceLauncher

ServiceLoader<AccountingService> loader = ServiceLoader.load(AccountingService.class)


AccountingService service = loader.next();
long balance = service.getBalance();

Поскольку ServiceLoader является Iterable , он поддерживает несколько поставщиков


реализации, в которых программа может выбирать:

ServiceLoader<AccountingService> loader = ServiceLoader.load(AccountingService.class)


for(AccountingService service : loader) {
//...
}

Обратите внимание, что при вызове next() создан новый экземпляр. Если вы хотите
повторно использовать экземпляр, вы должны использовать метод iterator() для
ServiceLoader или для каждого цикла, как показано выше.

Прочитайте ServiceLoader онлайн: https://riptutorial.com/ru/java/topic/5433/serviceloader

https://riptutorial.com/ru/home 169
глава 34: SortedMap
Вступление
Введение в отсортированную карту.

Examples

Введение в отсортированную карту.

Ключевой момент :-

• Интерфейс SortedMap расширяет карту.


• записи сохраняются в порядке возрастания ключа.

Методы сортированной карты:

• Компаратор компаратора ().


• Объект firstKey ().
• SortedMap headMap (конец объекта).
• Объект lastKey ().
• Подмножество SortedMap (начало объекта, конец объекта).
• SortedMap tailMap (Начало объекта).

пример

public static void main(String args[]) {


// Create a hash map
TreeMap tm = new TreeMap();

// Put elements to the map


tm.put("Zara", new Double(3434.34));
tm.put("Mahnaz", new Double(123.22));
tm.put("Ayan", new Double(1378.00));
tm.put("Daisy", new Double(99.22));
tm.put("Qadir", new Double(-19.08));

// Get a set of the entries


Set set = tm.entrySet();

// Get an iterator
Iterator i = set.iterator();

// Display elements
while(i.hasNext()) {
Map.Entry me = (Map.Entry)i.next();
System.out.print(me.getKey() + ": ");
System.out.println(me.getValue());
}

https://riptutorial.com/ru/home 170
System.out.println();

// Deposit 1000 into Zara's account


double balance = ((Double)tm.get("Zara")).doubleValue();
tm.put("Zara", new Double(balance + 1000));
System.out.println("Zara's new balance: " + tm.get("Zara"));
}

Прочитайте SortedMap онлайн: https://riptutorial.com/ru/java/topic/10748/sortedmap

https://riptutorial.com/ru/home 171
глава 35: Streams
Вступление
Streamпредставляет последовательность элементов и поддерживает различные виды
операций для выполнения вычислений по этим элементам. С Java 8 интерфейс Collection
имеет два метода для генерации Stream : stream() и parallelStream() . Операции Stream
являются промежуточными или конечными. Промежуточные операции возвращают Stream
поэтому несколько промежуточных операций могут быть привязаны до того, как Stream
будет закрыт. Операции с терминалом либо недействительны, либо возвращают результат
без потока.

Синтаксис
• collection.stream ()
• Arrays.stream (массив)
• Stream.iterate (firstValue, currentValue -> nextValue)
• Stream.generate (() -> value)
• Stream.of (elementOfT [, elementOfT, ...])
• Stream.empty ()
• StreamSupport.stream (iterable.spliterator (), false)

Examples

Использование потоков

Streamпредставляет собой последовательность элементов, на которых могут выполняться


последовательные и параллельные операции агрегации. Любой данный Stream может
потенциально иметь неограниченное количество данных, проходящих через него. В
результате данные, полученные от Stream , обрабатываются индивидуально по мере их
поступления, в отличие от пакетной обработки данных в целом. В сочетании с лямбда-
выражениями они обеспечивают краткий способ выполнения операций над
последовательностями данных с использованием функционального подхода.

Пример: ( см. Работу над Ideone )

Stream<String> fruitStream = Stream.of("apple", "banana", "pear", "kiwi", "orange");

fruitStream.filter(s -> s.contains("a"))


.map(String::toUpperCase)
.sorted()
.forEach(System.out::println);

https://riptutorial.com/ru/home 172
Выход:

ЯБЛОКО
БАНАН
ОРАНЖЕВЫЙ
ГРУША

Операции, выполняемые вышеуказанным кодом, можно суммировать следующим образом:

1. Создайте Stream<String> содержащий упорядоченный упорядоченный Stream элементов


String для фруктов, используя статический заводский метод Stream.of(values) .

2. Операция filter() сохраняет только элементы, которые соответствуют заданному


предикату (элементы, которые при проверке предикатом возвращают true). В этом
случае он сохраняет элементы, содержащие "a" . Предикат задается как лямбда-
выражение .

3. Операция map() преобразует каждый элемент с помощью заданной функции,


называемой mapper. В этом случае каждая String фруктов преобразуется в его
строчную версию String с использованием ссылки на метод String::toUppercase .

Обратите внимание, что операция map() вернет поток с другим общим


типом, если функция сопоставления возвращает тип, отличный от его
входного параметра. Например, в Stream<String> вызов .map(String::isEmpty)
возвращает Stream<Boolean>

4. Операция sorted() сортирует элементы Stream соответствии с их естественным


упорядочением (лексикографически, в случае String ).

5. Наконец, операция forEach(action) выполняет действие, действующее на каждый


элемент Stream , передавая его потребителю . В этом примере каждый элемент просто
печатается на консоли. Эта операция является терминальной операцией, что делает
невозможным ее повторное использование.

Обратите внимание, что операции, определенные в Stream , выполняются


из- за операции терминала. Без операции с терминалом поток не
обрабатывается. Потоки нельзя использовать повторно. После вызова
терминальной операции объект Stream становится непригодным.

https://riptutorial.com/ru/home 173
Операции (как показано выше) соединены вместе, чтобы сформировать то, что можно
рассматривать как запрос данных.

Закрытие потоков
Обратите внимание, что Stream как правило, не нужно закрывать. Требуется
только закрыть потоки, которые работают на каналах ввода-вывода.
Большинство типов Stream не работают на ресурсах и поэтому не требуют
закрытия.

Интерфейс Stream расширяет AutoCloseable . Потоки могут быть закрыты вызовом метода
close или с помощью операторов try-with-resource.

Пример использования, когда Stream должен быть закрыт, - это когда вы создаете Stream
строк из файла:

try (Stream<String> lines = Files.lines(Paths.get("somePath"))) {


lines.forEach(System.out::println);
}

Интерфейс Stream также объявляет метод Stream.onClose() который позволяет вам


регистрировать обработчики Runnable которые будут вызываться, когда поток закрыт.
Пример использования - это то, где код, который создает поток, должен знать, когда он
потребляется, чтобы выполнить некоторую очистку.

public Stream<String>streamAndDelete(Path path) throws IOException {


return Files.lines(path).onClose(() -> someClass.deletePath(path));
}

Обработчик запуска будет выполняться только в том случае, если метод close()
вызывается, явно или неявно, с помощью инструкции try-with-resources.

Порядок обработки
Обработка объекта Stream может быть последовательной или параллельной .

В последовательном режиме элементы обрабатываются в порядке источника Stream . Если


Stream упорядочен (например, реализация SortedMap или List ), то гарантируется, что
обработка будет соответствовать порядку источника. В других случаях, однако, следует
соблюдать осторожность, чтобы не зависеть от порядка (см. keySet() порядок итераций
Java HashMap keySet() ? ).

Пример:

https://riptutorial.com/ru/home 174
List<Integer> integerList = Arrays.asList(0, 1, 2, 3, 42);

// sequential
long howManyOddNumbers = integerList.stream()
.filter(e -> (e % 2) == 1)
.count();

System.out.println(howManyOddNumbers); // Output: 2

Живой на Ideone

Параллельный режим позволяет использовать несколько потоков на нескольких ядрах, но


нет гарантии того, в каком порядке обрабатываются элементы.

Если вызывается несколько методов в последовательном Stream , не каждый метод должен


быть вызван. Например, если Stream фильтруется и количество элементов сводится к
единице, последующий вызов метода, такого как sort , не будет выполняться. Это может
увеличить производительность последовательного Stream - оптимизация, которая
невозможна при параллельном Stream .

Пример:

// parallel
long howManyOddNumbersParallel = integerList.parallelStream()
.filter(e -> (e % 2) == 1)
.count();

System.out.println(howManyOddNumbersParallel); // Output: 2

Живой на Ideone

Отличия от контейнеров (или коллекций )


Хотя некоторые действия могут выполняться как в контейнерах, так и в потоках, они в
конечном итоге служат различным целям и поддерживают разные операции. Контейнеры
больше сосредоточены на том, как хранятся элементы и как эти элементы могут быть
доступны эффективно. С другой стороны, Stream не обеспечивает прямого доступа и
манипулирования его элементами; он больше предназначен для группы объектов как
коллективного объекта и выполняет операции над этим объектом в целом. Stream и
Collection - это отдельные абстракции высокого уровня для этих различных целей.

Соберите элементы потока в коллекцию

Собирайте с помощью toList() и toSet()


Элементы из Stream можно легко собрать в контейнер с помощью операции Stream.collect :

https://riptutorial.com/ru/home 175
System.out.println(Arrays
.asList("apple", "banana", "pear", "kiwi", "orange")
.stream()
.filter(s -> s.contains("a"))
.collect(Collectors.toList())
);
// prints: [apple, banana, pear, orange]

Другие экземпляры коллекции, такие как Set , могут быть сделаны с использованием
других встроенных методов Collectors . Например, Collectors.toSet() собирает элементы
Stream в Set .

Явный контроль над реализацией List или Set


Согласно документации Collectors#toList() и Collectors#toSet() , нет никаких гарантий по
типу, изменчивости, сериализуемости или потокобезопасности возвращаемого List или Set .

Для явного контроля над возвращаемой реализацией вместо этого можно использовать
Collectors#toCollection(Supplier) , где данный поставщик возвращает новую и пустую
коллекцию.

// syntax with method reference


System.out.println(strings
.stream()
.filter(s -> s != null && s.length() <= 3)
.collect(Collectors.toCollection(ArrayList::new))
);

// syntax with lambda


System.out.println(strings
.stream()
.filter(s -> s != null && s.length() <= 3)
.collect(Collectors.toCollection(() -> new LinkedHashSet<>()))
);

Сбор элементов с помощью toMap

Коллекционер накапливает элементы на карте, где ключ - это идентификатор студента, а


значение - значение ученика.

List<Student> students = new ArrayList<Student>();


students.add(new Student(1,"test1"));
students.add(new Student(2,"test2"));
students.add(new Student(3,"test3"));

Map<Integer, String> IdToName = students.stream()


.collect(Collectors.toMap(Student::getId, Student::getName));
System.out.println(IdToName);

Выход :

https://riptutorial.com/ru/home 176
{1=test1, 2=test2, 3=test3}

У Collectors.toMap есть другая реализация Collector<T, ?, Map<K,U>> toMap(Function<? super T,


? extends K> keyMapper, Function<? super T, ? extends U> valueMapper, BinaryOperator<U>
. Функция mergeFunction используется в основном для выбора нового
mergeFunction)
значения или сохранения старого значения, если ключ повторяется при добавлении нового
члена в Map из списка.

Функция mergeFunction часто выглядит так: (s1, s2) -> s1 чтобы сохранить значение,
соответствующее повторенному ключу, или (s1, s2) -> s2 чтобы добавить новое значение
для повторного ключа.

Сбор элементов на карте коллекций

Пример: от ArrayList до Map <String, List <>>

Часто для этого требуется сделать карту списка из основного списка. Пример: от ученика
списка, нам нужно составить карту списка предметов для каждого ученика.

List<Student> list = new ArrayList<>();


list.add(new Student("Davis", SUBJECT.MATH, 35.0));
list.add(new Student("Davis", SUBJECT.SCIENCE, 12.9));
list.add(new Student("Davis", SUBJECT.GEOGRAPHY, 37.0));

list.add(new Student("Sascha", SUBJECT.ENGLISH, 85.0));


list.add(new Student("Sascha", SUBJECT.MATH, 80.0));
list.add(new Student("Sascha", SUBJECT.SCIENCE, 12.0));
list.add(new Student("Sascha", SUBJECT.LITERATURE, 50.0));

list.add(new Student("Robert", SUBJECT.LITERATURE, 12.0));

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


list.stream().forEach(s -> {
map.computeIfAbsent(s.getName(), x -> new ArrayList<>()).add(s.getSubject());
});
System.out.println(map);

Выход:

{ Robert=[LITERATURE],
Sascha=[ENGLISH, MATH, SCIENCE, LITERATURE],
Davis=[MATH, SCIENCE, GEOGRAPHY] }

Пример: от ArrayList до Map <String, Map <>>

List<Student> list = new ArrayList<>();


list.add(new Student("Davis", SUBJECT.MATH, 1, 35.0));
list.add(new Student("Davis", SUBJECT.SCIENCE, 2, 12.9));
list.add(new Student("Davis", SUBJECT.MATH, 3, 37.0));
list.add(new Student("Davis", SUBJECT.SCIENCE, 4, 37.0));

list.add(new Student("Sascha", SUBJECT.ENGLISH, 5, 85.0));


list.add(new Student("Sascha", SUBJECT.MATH, 1, 80.0));

https://riptutorial.com/ru/home 177
list.add(new Student("Sascha", SUBJECT.ENGLISH, 6, 12.0));
list.add(new Student("Sascha", SUBJECT.MATH, 3, 50.0));

list.add(new Student("Robert", SUBJECT.ENGLISH, 5, 12.0));

Map<String, Map<SUBJECT, List<Double>>> map = new HashMap<>();

list.stream().forEach(student -> {
map.computeIfAbsent(student.getName(), s -> new HashMap<>())
.computeIfAbsent(student.getSubject(), s -> new ArrayList<>())
.add(student.getMarks());
});

System.out.println(map);

Выход:

{ Robert={ENGLISH=[12.0]},
Sascha={MATH=[80.0, 50.0], ENGLISH=[85.0, 12.0]},
Davis={MATH=[35.0, 37.0], SCIENCE=[12.9, 37.0]} }

Чит-лист

Цель Код

Сбор в List Collectors.toList()

Собирать в ArrayList с заранее Collectors.toCollection(() -> new


ArrayList<>(size))
заданным размером

Собрать Set Collectors.toSet()

Собрать в Set с лучшей Collectors.toCollection(() -> new


LinkedHashSet<>())
итерационной производительностью

Собрать в нечувствительный к Collectors.toCollection(() -> new


TreeSet<>(String.CASE_INSENSITIVE_ORDER))
регистру Set<String>

Соберите в EnumSet<AnEnum> (
Collectors.toCollection(() ->
наилучшая производительность для EnumSet.noneOf(AnEnum.class))
перечислений)

Соберите Map<K,V> с уникальными


Collectors.toMap(keyFunc,valFunc)
ключами

Карта MyObject.getter () для Collectors.toMap(MyObject::getter,


Function.identity())
уникального объекта MyObject

Карта MyObject.getter () для Collectors.groupingBy(MyObject::getter)

https://riptutorial.com/ru/home 178
Цель Код

нескольких объектов MyObjects

Бесконечные потоки

Можно создать Stream , который не заканчивается. Вызов метода терминала в бесконечном


Stream приводит к тому, что Stream вводит бесконечный цикл. Метод limit Stream может
использоваться для ограничения количества терминов Stream которые обрабатывает Java.

В этом примере генерируется Stream всех натуральных чисел, начиная с номера 1. Каждый
последующий член Stream является одним выше предыдущего. Вызывая метод ограничения
этого Stream , рассматриваются и печатаются только первые пять членов Stream .

// Generate infinite stream - 1, 2, 3, 4, 5, 6, 7, ...


IntStream naturalNumbers = IntStream.iterate(1, x -> x + 1);

// Print out only the first 5 terms


naturalNumbers.limit(5).forEach(System.out::println);

Выход:

1
2
3
4
5

Другой способ генерации бесконечного потока - использовать метод Stream.generate .


Этот метод принимает лямбда типа Поставщик .

// Generate an infinite stream of random numbers


Stream<Double> infiniteRandomNumbers = Stream.generate(Math::random);

// Print out only the first 10 random numbers


infiniteRandomNumbers.limit(10).forEach(System.out::println);

Потребительские потоки

Stream будет пройден только тогда, когда есть операция терминала , например count() ,
collect() или forEach() . В противном случае операция Stream не будет выполнена.

В следующем примере терминальная операция не добавляется в Stream , поэтому операция


filter() не будет вызываться и не будет выводиться вывод, потому что peek() НЕ является
терминальной операцией .

IntStream.range(1, 10).filter(a -> a % 2 == 0).peek(System.out::println);

https://riptutorial.com/ru/home 179
Живой на Ideone

Это последовательность Stream с действительной работой терминала , поэтому


производится выход.

Вы также можете использовать forEach вместо peek :

IntStream.range(1, 10).filter(a -> a % 2 == 0).forEach(System.out::println);

Живой на Ideone

Выход:

2
4
6
8

После выполнения операции терминала Stream потребляется и не может быть повторно


использован.

Хотя данный объект потока нельзя использовать повторно, легко создать многоразовый
Iterable который делегирует потоковый конвейер. Это может быть полезно для
возвращения измененного представления живого набора данных без необходимости
собирать результаты во временную структуру.

List<String> list = Arrays.asList("FOO", "BAR");


Iterable<String> iterable = () -> list.stream().map(String::toLowerCase).iterator();

for (String str : iterable) {


System.out.println(str);
}
for (String str : iterable) {
System.out.println(str);
}

Выход:

Foo
бар
Foo
бар

Это работает, потому что Iterable объявляет один абстрактный метод Iterator<T> iterator()
. Это делает его эффективным функциональным интерфейсом, реализованным лямбдой,
которая создает новый поток для каждого вызова.

https://riptutorial.com/ru/home 180
В общем, Stream работает, как показано на следующем изображении:

ПРИМЕЧАНИЕ . Проверки аргументов всегда выполняются даже без операции терминала :

try {
IntStream.range(1, 10).filter(null);
} catch (NullPointerException e) {
System.out.println("We got a NullPointerException as null was passed as an argument to
filter()");
}

Живой на Ideone

Выход:

Мы получили исключение NullPointerException, поскольку значение null было


передано как аргумент filter ()

Создание карты частоты

Сборщик groupingBy(classifier, downstream) позволяет собирать элементы Stream в Map ,


классифицируя каждый элемент в группе и выполняя нисходящую операцию над
элементами, классифицированными в той же группе.

Классическим примером этого принципа является использование Map для подсчета


появления элементов в Stream . В этом примере классификатор - это просто функция
идентификации, которая возвращает элемент as-is. Операция downstream подсчитывает
количество равных элементов, используя counting() .

Stream.of("apple", "orange", "banana", "apple")


.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet()
.forEach(System.out::println);

Операция нисходящего потока сама является сборщиком ( Collectors.counting() ), который


работает с элементами типа String и производит результат типа Long . Результатом вызова
метода collect является Map<String, Long> .

Это приведет к следующему результату:

банан = 1

https://riptutorial.com/ru/home 181
оранжевый = 1
яблоко = 2

Параллельный поток

Примечание. Перед тем, как решить, какой Stream использовать, пожалуйста, взгляните на
поведение ParallelStream vs Sequential Stream .

Если вы хотите одновременно выполнять операции Stream , вы можете использовать любой


из этих способов.

List<String> data = Arrays.asList("One", "Two", "Three", "Four", "Five");


Stream<String> aParallelStream = data.stream().parallel();

Или же:

Stream<String> aParallelStream = data.parallelStream();

Чтобы выполнить операции, определенные для параллельного потока, вызовите оператор


терминала:

aParallelStream.forEach(System.out::println);

(Возможен) выход из параллельного Stream :

Три
четыре
Один
Два
5

Порядок может измениться, поскольку все элементы обрабатываются параллельно (что


может ускорить выполнение). При заказе используйте параметр parallelStream .

Эффективное воздействие
В случае задействования сети параллельный Stream s может ухудшить общую
производительность приложения, поскольку все параллельные Stream используют общий
пул потоков fork-join для сети.

С другой стороны, параллельный Stream s может значительно повысить


производительность во многих других случаях, в зависимости от количества доступных
ядер в текущем CPU на данный момент.

Преобразование потока необязательно в поток значений

https://riptutorial.com/ru/home 182
Возможно, вам потребуется конвертировать Stream излучающий Optional для Stream
значений, испускающий только значения из существующего Optional . (т. е. без null
значения и не имея дело с Optional.empty() ).

Optional<String> op1 = Optional.empty();


Optional<String> op2 = Optional.of("Hello World");

List<String> result = Stream.of(op1, op2)


.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());

System.out.println(result); //[Hello World]

Создание потока

Все java Collection<E> имеют методы stream() и parallelStream() из которых можно построить
Stream<E> :

Collection<String> stringList = new ArrayList<>();


Stream<String> stringStream = stringList.parallelStream();

Stream<E> может быть создан из массива с использованием одного из двух методов:

String[] values = { "aaa", "bbbb", "ddd", "cccc" };


Stream<String> stringStream = Arrays.stream(values);
Stream<String> stringStreamAlternative = Stream.of(values);

Разница между Arrays.stream() и Stream.of() заключается в том, что Stream.of() имеет


параметр varargs, поэтому его можно использовать как:

Stream<Integer> integerStream = Stream.of(1, 2, 3);

Есть также примитивные Stream которые вы можете использовать. Например:

IntStream intStream = IntStream.of(1, 2, 3);


DoubleStream doubleStream = DoubleStream.of(1.0, 2.0, 3.0);

Эти примитивные потоки также могут быть построены с использованием Arrays.stream() :

IntStream intStream = Arrays.stream(new int[]{ 1, 2, 3 });

Можно создать Stream из массива с указанным диапазоном.

int[] values= new int[]{1, 2, 3, 4, 5};


IntStream intStram = Arrays.stream(values, 1, 3);

Обратите внимание, что любой примитивный поток может быть преобразован в поток с

https://riptutorial.com/ru/home 183
коротким типом, используя метод boxed :

Stream<Integer> integerStream = intStream.boxed();

Это может быть полезно в некоторых случаях, если вы хотите собирать данные, поскольку
примитивный поток не имеет никакого метода collect который принимает Collector
качестве аргумента.

Повторное использование промежуточных операций цепочки потоков

Поток закрывается, когда вызывается операция терминала. Повторное использование


потока промежуточных операций, когда только операция терминала изменяется только.
мы могли бы создать поставщика потока для создания нового потока со всеми уже
созданными промежуточными операциями.

Supplier<Stream<String>> streamSupplier = () -> Stream.of("apple", "banana","orange",


"grapes", "melon","blueberry","blackberry")
.map(String::toUpperCase).sorted();

streamSupplier.get().filter(s -> s.startsWith("A")).forEach(System.out::println);

// APPLE

streamSupplier.get().filter(s -> s.startsWith("B")).forEach(System.out::println);

// BANANA
// BLACKBERRY
// BLUEBERRY

int[] массивы могут быть преобразованы в List<Integer> с использованием потоков

int[] ints = {1,2,3};


List<Integer> list = IntStream.of(ints).boxed().collect(Collectors.toList());

Поиск статистики о числовых потоках

Java 8 предоставляет классы, называемые IntSummaryStatistics , DoubleSummaryStatistics и


LongSummaryStatistics которые предоставляют объект состояния для сбора статистики,
такой как count , min , max , sum и average .

Java SE 8

List<Integer> naturalNumbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);


IntSummaryStatistics stats = naturalNumbers.stream()
.mapToInt((x) -> x)
.summaryStatistics();
System.out.println(stats);

Это приведет к:

Java SE 8

https://riptutorial.com/ru/home 184
IntSummaryStatistics{count=10, sum=55, min=1, max=10, average=5.500000}

Получить фрагмент потока

Пример. Получите Stream из 30 элементов, содержащий от 21 до 50 (включительно)


элемент коллекции.

final long n = 20L; // the number of elements to skip


final long maxSize = 30L; // the number of elements the stream should be limited to
final Stream<T> slice = collection.stream().skip(n).limit(maxSize);

Заметки:

• IllegalArgumentException выбрасывается, если n отрицательно или maxSize


отрицательный
• обе skip(long) и limit(long) промежуточные операции
• если поток содержит менее n элементов, то skip(n) возвращает пустой поток
• как skip(long) и limit(long) являются дешевыми операциями на последовательных
поточных трубопроводах, но могут быть довольно дорогими на упорядоченных
параллельных трубопроводах

Конкатенация потоков

Объявление переменной для примеров:

Collection<String> abc = Arrays.asList("a", "b", "c");


Collection<String> digits = Arrays.asList("1", "2", "3");
Collection<String> greekAbc = Arrays.asList("alpha", "beta", "gamma");

Пример 1 - Объединение двух Stream s

final Stream<String> concat1 = Stream.concat(abc.stream(), digits.stream());

concat1.forEach(System.out::print);
// prints: abc123

Пример 2 - Конкатенация более двух Stream s

final Stream<String> concat2 = Stream.concat(


Stream.concat(abc.stream(), digits.stream()),
greekAbc.stream());

System.out.println(concat2.collect(Collectors.joining(", ")));
// prints: a, b, c, 1, 2, 3, alpha, beta, gamma

В качестве альтернативы , чтобы упростить вложенный concat() синтаксис Stream ы также


могут быть объединены с flatMap() :

https://riptutorial.com/ru/home 185
final Stream<String> concat3 = Stream.of(
abc.stream(), digits.stream(), greekAbc.stream())
.flatMap(s -> s);
// or `.flatMap(Function.identity());` (java.util.function.Function)

System.out.println(concat3.collect(Collectors.joining(", ")));
// prints: a, b, c, 1, 2, 3, alpha, beta, gamma

Будьте осторожны при построении Stream из повторной конкатенации, потому что доступ к
элементу глубоко конкатенированного Stream может привести к глубоким цепочкам вызовов
или даже StackOverflowException .

IntStream to String

Java не имеет Char Stream , поэтому при работе со String s и построении Stream of Character
s, опция должна получить IntStream кодовых точек с использованием String.codePoints() .
Таким образом, IntStream можно получить следующим образом:

public IntStream stringToIntStream(String in) {


return in.codePoints();
}

Это немного больше, чтобы сделать конверсию другим способом, то есть IntStreamToString.
Это можно сделать следующим образом:

public String intStreamToString(IntStream intStream) {


return intStream.collect(StringBuilder::new, StringBuilder::appendCodePoint,
StringBuilder::append).toString();
}

Сортировка по потоку

List<String> data = new ArrayList<>();


data.add("Sydney");
data.add("London");
data.add("New York");
data.add("Amsterdam");
data.add("Mumbai");
data.add("California");

System.out.println(data);

List<String> sortedData = data.stream().sorted().collect(Collectors.toList());

System.out.println(sortedData);

Выход:

[Sydney, London, New York, Amsterdam, Mumbai, California]


[Amsterdam, California, London, Mumbai, New York, Sydney]

https://riptutorial.com/ru/home 186
Также возможно использовать другой механизм сравнения, так как существует
перегруженная sorted версия, которая принимает в качестве аргумента компаратор.

Кроме того, вы можете использовать выражение лямбда для сортировки:

List<String> sortedData2 = data.stream().sorted((s1,s2) ->


s2.compareTo(s1)).collect(Collectors.toList());

Это вывело бы [Sydney, New York, Mumbai, London, California, Amsterdam]

Вы можете использовать Comparator.reverseOrder() чтобы иметь компаратор, который


налагает reverse сторону естественного упорядочения.

List<String> reverseSortedData =
data.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());

Потоки примитивов

Java предоставляет специализированные Stream s для трех типов примитивов IntStream (для
int s), LongStream (для long s) и DoubleStream (для double s). Помимо оптимизации реализаций
их соответствующих примитивов, они также предоставляют несколько конкретных
терминальных методов, как правило, для математических операций. Например:

IntStream is = IntStream.of(10, 20, 30);


double average = is.average().getAsDouble(); // average is 20.0

Соберите результаты потока в массив

Аналоговый, чтобы получить коллекцию для Stream методом collect() , массив может быть
получен методом Stream.toArray() :

List<String> fruits = Arrays.asList("apple", "banana", "pear", "kiwi", "orange");

String[] filteredFruits = fruits.stream()


.filter(s -> s.contains("a"))
.toArray(String[]::new);

// prints: [apple, banana, pear, orange]


System.out.println(Arrays.toString(filteredFruits));

String[]::new - это особый вид ссылки на метод: ссылка на конструктор.

Поиск первого элемента, который соответствует предикату

Можно найти первый элемент Stream который соответствует условию.

В этом примере мы найдем первое Integer , квадрат которого превышает 50000 .

https://riptutorial.com/ru/home 187
IntStream.iterate(1, i -> i + 1) // Generate an infinite stream 1,2,3,4...
.filter(i -> (i*i) > 50000) // Filter to find elements where the square is >50000
.findFirst(); // Find the first filtered element

Это выражение вернет OptionalInt с результатом.

Обратите внимание, что с бесконечным Stream Java будет проверять каждый элемент до
тех пор, пока не найдет результат. С конечным Stream , если Java исчерпывает элементы,
но все равно не может найти результат, он возвращает пустой OptionalInt .

Использование IntStream для перебора индексов

Stream s элементов обычно не позволяет получить доступ к значению индекса текущего


элемента. Чтобы перебирать массив или ArrayList , имея доступ к индексам, используйте
IntStream.range(start, endExclusive) .

String[] names = { "Jon", "Darin", "Bauke", "Hans", "Marc" };

IntStream.range(0, names.length)
.mapToObj(i -> String.format("#%d %s", i + 1, names[i]))
.forEach(System.out::println);

Метод range(start, endExclusive) возвращает другой ÌntStream а mapToObj(mapper) возвращает


поток String .

Выход:

# 1 Jon
# 2 Дарин
# 3 Бауке
# 4 Ханс
# 5 Марк

Это очень похоже на использование нормального for цикла со счетчиком, но с выгодой


конвейерных и распараллеливания:

for (int i = 0; i < names.length; i++) {


String newName = String.format("#%d %s", i + 1, names[i]);
System.out.println(newName);
}

Сгладить потоки с помощью flatMap ()

Streamпредметов, которые в свою очередь могут быть потоковыми, может быть сплющен в
один непрерывный Stream :

Массив списка элементов можно преобразовать в один список.

https://riptutorial.com/ru/home 188
List<String> list1 = Arrays.asList("one", "two");
List<String> list2 = Arrays.asList("three","four","five");
List<String> list3 = Arrays.asList("six");
List<String> finalList = Stream.of(list1, list2,
list3).flatMap(Collection::stream).collect(Collectors.toList());
System.out.println(finalList);

// [one, two, three, four, five, six]

Карта, содержащая Список элементов как значений, может быть сглажена в


комбинированный список

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


map.put("a", Arrays.asList(1, 2, 3));
map.put("b", Arrays.asList(4, 5, 6));

List<Integer> allValues = map.values() // Collection<List<Integer>>


.stream() // Stream<List<Integer>>
.flatMap(List::stream) // Stream<Integer>
.collect(Collectors.toList());

System.out.println(allValues);
// [1, 2, 3, 4, 5, 6]

List Map может быть сплющен в один непрерывный Stream

List<Map<String, String>> list = new ArrayList<>();


Map<String,String> map1 = new HashMap();
map1.put("1", "one");
map1.put("2", "two");

Map<String,String> map2 = new HashMap();


map2.put("3", "three");
map2.put("4", "four");
list.add(map1);
list.add(map2);

Set<String> output= list.stream() // Stream<Map<String, String>>


.map(Map::values) // Stream<List<String>>
.flatMap(Collection::stream) // Stream<String>
.collect(Collectors.toSet()); //Set<String>
// [one, two, three,four]

Создание карты на основе потока

Простой случай без дубликатов ключей

Stream<String> characters = Stream.of("A", "B", "C");

Map<Integer, String> map = characters


.collect(Collectors.toMap(element -> element.hashCode(), element -> element));
// map = {65=A, 66=B, 67=C}

Чтобы сделать вещи более декларативными, мы можем использовать статический метод в

https://riptutorial.com/ru/home 189
интерфейсе - Function.identity() . Мы можем заменить этот element
Function -> element
лямбда- element -> element Function.identity() .

Случай, когда могут быть дубликаты ключей

В javadoc для Collectors.toMap указано:

Если отображаемые ключи содержат дубликаты (в соответствии с


Object.equals(Object) ), при выполнении операции сбора генерируется
IllegalStateException . Если отображаемые ключи могут иметь дубликаты,
toMap(Function, Function, BinaryOperator) используйте toMap(Function, Function,
BinaryOperator) .

Stream<String> characters = Stream.of("A", "B", "B", "C");

Map<Integer, String> map = characters


.collect(Collectors.toMap(
element -> element.hashCode(),
element -> element,
(existingVal, newVal) -> (existingVal + newVal)));

// map = {65=A, 66=BB, 67=C}

передается в Collectors.toMap(...) генерирует значение, которое нужно


BinaryOperator
сохранить в случае столкновения. Оно может:

• возвращает старое значение, так что первое значение в потоке имеет приоритет,
• вернуть новое значение, так что последнее значение в потоке имеет приоритет или
• объединить старые и новые значения

Группировка по значению

Вы можете использовать Collectors.groupingBy когда вам нужно выполнить эквивалент


операции каскадирования базы данных «по группам». Чтобы проиллюстрировать это,
создается следующая карта, в которой имена людей сопоставляются с фамилиями:

List<Person> people = Arrays.asList(


new Person("Sam", "Rossi"),
new Person("Sam", "Verdi"),
new Person("John", "Bianchi"),
new Person("John", "Rossi"),
new Person("John", "Verdi")
);

Map<String, List<String>> map = people.stream()


.collect(
// function mapping input elements to keys
Collectors.groupingBy(Person::getName,
// function mapping input elements to values,
// how to store values
Collectors.mapping(Person::getSurname, Collectors.toList()))
);

https://riptutorial.com/ru/home 190
// map = {John=[Bianchi, Rossi, Verdi], Sam=[Rossi, Verdi]}

Живой на Ideone

Генерация случайных строк с использованием потоков

Иногда бывает полезно создавать случайные Strings , возможно, как идентификатор


сеанса для веб-службы или начальный пароль после регистрации для приложения. Это
может быть легко достигнуто с помощью Stream s.

Сначала нам нужно инициализировать генератор случайных чисел. Чтобы повысить


безопасность созданных String s, рекомендуется использовать SecureRandom .

Примечание . Создание SecureRandom довольно дорогое, поэтому лучше всего сделать это
только один раз и время от времени вызывать один из методов setSeed() для его setSeed() .

private static final SecureRandom rng = new SecureRandom(SecureRandom.generateSeed(20));


//20 Bytes as a seed is rather arbitrary, it is the number used in the JavaDoc example

При создании случайных String s мы обычно хотим, чтобы они использовали только
определенные символы (например, только буквы и цифры). Поэтому мы можем создать
метод, возвращающий boolean которое впоследствии может быть использовано для
фильтрации Stream .

//returns true for all chars in 0-9, a-z and A-Z


boolean useThisCharacter(char c){
//check for range to avoid using all unicode Letter (e.g. some chinese symbols)
return c >= '0' && c <= 'z' && Character.isLetterOrDigit(c);
}

Затем мы сможем использовать RNG для генерации случайной строки определенной


длины, содержащей кодировку, которая передает нашу проверку useThisCharacter .

public String generateRandomString(long length){


//Since there is no native CharStream, we use an IntStream instead
//and convert it to a Stream<Character> using mapToObj.
//We need to specify the boundaries for the int values to ensure they can safely be cast
to char
Stream<Character> randomCharStream = rng.ints(Character.MIN_CODE_POINT,
Character.MAX_CODE_POINT).mapToObj(i -> (char)i).filter(c ->
this::useThisCharacter).limit(length);

//now we can use this Stream to build a String utilizing the collect method.
String randomString = randomCharStream.collect(StringBuilder::new, StringBuilder::append,
StringBuilder::append).toString();
return randomString;
}

Использование потоков для реализации математических функций

https://riptutorial.com/ru/home 191
Streamс, и особенно IntStream с, является элегантным способом реализации суммирования
условий (a). Диапазоны Stream могут использоваться как границы суммирования.

Например, приближение Мадхавы к Pi дается формулой (Источник: wikipedia ):

Это можно вычислить с произвольной точностью. Например, на 101 срок:

double pi = Math.sqrt(12) *
IntStream.rangeClosed(0, 100)
.mapToDouble(k -> Math.pow(-3, -1 * k) / (2 * k + 1))
.sum();

Примечание: с double точностью, выбирая верхнюю границу 29, достаточно, чтобы


получить результат, который неотличим от Math.Pi

Использование потоков и ссылок на методы для записи


самодокументирующих процессов

Ссылки на методы делают отличный самодокументирующий код, а использование ссылок


на методы с помощью Stream делает сложные процессы простыми для чтения и понимания.
Рассмотрим следующий код:

public interface Ordered {


default int getOrder(){
return 0;
}
}

public interface Valued<V extends Ordered> {


boolean hasPropertyTwo();
V getValue();
}

public interface Thing<V extends Ordered> {


boolean hasPropertyOne();
Valued<V> getValuedProperty();
}

public <V extends Ordered> List<V> myMethod(List<Thing<V>> things) {


List<V> results = new ArrayList<V>();
for (Thing<V> thing : things) {
if (thing.hasPropertyOne()) {
Valued<V> valued = thing.getValuedProperty();
if (valued != null && valued.hasPropertyTwo()){
V value = valued.getValue();
if (value != null){
results.add(value);
}
}
}
}

https://riptutorial.com/ru/home 192
results.sort((a, b)->{
return Integer.compare(a.getOrder(), b.getOrder());
});
return results;
}

Этот последний метод, переписанный с использованием ссылок Stream и методов, намного


читабельнее, и каждый шаг процесса быстро и легко понятен - он не просто короче, он
также показывает с первого взгляда, какие интерфейсы и классы отвечают за код на
каждом шаге:

public <V extends Ordered> List<V> myMethod(List<Thing<V>> things) {


return things.stream()
.filter(Thing::hasPropertyOne)
.map(Thing::getValuedProperty)
.filter(Objects::nonNull)
.filter(Valued::hasPropertyTwo)
.map(Valued::getValue)
.filter(Objects::nonNull)
.sorted(Comparator.comparing(Ordered::getOrder))
.collect(Collectors.toList());
}

Использование потоков Map.Entry для сохранения начальных значений


после сопоставления

Когда у вас есть Stream вам нужно сопоставить, но вы хотите сохранить начальные
значения, вы можете сопоставить Stream с Map.Entry<K,V> с помощью утилиты, например:

public static <K, V> Function<K, Map.Entry<K, V>> entryMapper(Function<K, V> mapper){
return (k)->new AbstractMap.SimpleEntry<>(k, mapper.apply(k));
}

Затем вы можете использовать свой конвертер для обработки Stream имеющего доступ к
исходным и отображаемым значениям:

Set<K> mySet;
Function<K, V> transformer = SomeClass::transformerMethod;
Stream<Map.Entry<K, V>> entryStream = mySet.stream()
.map(entryMapper(transformer));

Затем вы можете продолжить обработку этого Stream как обычно. Это позволяет избежать
накладных расходов на создание промежуточной коллекции.

Категории операций по потоку

Операции потоков делятся на две основные категории: промежуточные и терминальные


операции и две подкатегории, без гражданства и состояния.

https://riptutorial.com/ru/home 193
Промежуточные операции:
Промежуточная операция всегда ленива , например простой Stream.map . Он не вызывается
до тех пор, пока поток фактически не будет потреблен. Это легко проверить:

Arrays.asList(1, 2 ,3).stream().map(i -> {


throw new RuntimeException("not gonna happen");
return i;
});

Промежуточные операции являются общими строительными блоками потока,


закодированными после источника, и за ними обычно следует операция терминала,
запускающая цепочку потоков.

Терминальные операции
Операции терминала - это то, что вызывает потребление потока. Некоторые из наиболее
распространенных - Stream.forEach или Stream.collect . Они обычно размещаются после
цепочки промежуточных операций и почти всегда стремятся .

Операции без гражданства


Безгражданство означает, что каждый элемент обрабатывается без контекста других
элементов. Операции бездействия позволяют эффективно обрабатывать потоки с
использованием памяти. Такие операции, как Stream.map и Stream.filter которые не требуют
информации о других элементах потока, считаются апатридами.

Операции со штатом
Стойкость означает, что операция по каждому элементу зависит от (некоторых) других
элементов потока. Для этого требуется сохранение состояния. Операции состояния могут
прерываться с длинными или бесконечными потоками. Такие операции, как Stream.sorted
требуют, чтобы весь поток обрабатывался до того, как Stream.sorted какой-либо элемент,
который сломается в достаточно длинном потоке элементов. Это может быть
продемонстрировано длинным потоком ( выполняется на свой страх и риск ):

// works - stateless stream


long BIG_ENOUGH_NUMBER = 999999999;

https://riptutorial.com/ru/home 194
IntStream.iterate(0, i -> i + 1).limit(BIG_ENOUGH_NUMBER).forEach(System.out::println);

Это вызовет Stream.sorted памяти из-за Stream.sorted :

// Out of memory - stateful stream


IntStream.iterate(0, i -> i +
1).limit(BIG_ENOUGH_NUMBER).sorted().forEach(System.out::println);

Преобразование итератора в поток

Используйте Spliterators.spliterator() или Spliterators.spliteratorUnknownSize() для


преобразования итератора в поток:

Iterator<String> iterator = Arrays.asList("A", "B", "C").iterator();


Spliterator<String> spliterator = Spliterators.spliteratorUnknownSize(iterator, 0);
Stream<String> stream = StreamSupport.stream(spliterator, false);

Сокращение потока

Сокращение - это процесс применения бинарного оператора к каждому элементу потока,


чтобы привести к одному значению.

Метод sum() для IntStream является примером сокращения; он применяет дополнение к


каждому члену потока, что приводит к одному окончательному значению:

https://riptutorial.com/ru/home 195
Это эквивалентно (((1+2)+3)+4)

Метод reduce Stream позволяет создать индивидуальное сокращение. Для реализации


метода sum() можно использовать метод reduce :

IntStream istr;

//Initialize istr

OptionalInt istr.reduce((a,b)->a+b);

версия возвращается, так что пустые потоки могут обрабатываться


Optional
соответствующим образом.

https://riptutorial.com/ru/home 196
Другим примером сокращения является объединение Stream<LinkedList<T>> в один
LinkedList<T> :

Stream<LinkedList<T>> listStream;

//Create a Stream<LinkedList<T>>

Optional<LinkedList<T>> bigList = listStream.reduce((LinkedList<T> list1, LinkedList<T>


list2)->{
LinkedList<T> retList = new LinkedList<T>();
retList.addAll(list1);
retList.addAll(list2);
return retList;
});

Вы также можете предоставить элемент идентификации . Например, элемент


идентификации для сложения равен 0, как x+0==x . Для умножения единичный элемент
равен 1, так как x*1==x . В вышеприведенном случае элемент идентификации представляет
собой пустой LinkedList<T> , потому что если вы добавляете пустой список в другой список,
список, который вы добавляете, не изменяется:

Stream<LinkedList<T>> listStream;

//Create a Stream<LinkedList<T>>

LinkedList<T> bigList = listStream.reduce(new LinkedList<T>(), (LinkedList<T> list1,


LinkedList<T> list2)->{
LinkedList<T> retList = new LinkedList<T>();
retList.addAll(list1);
retList.addAll(list2);
return retList;
});

Обратите внимание, что, когда предоставляется элемент идентификации, возвращаемое


значение не обернуто в Optional -if, вызываемый в пустом потоке, reduce() вернет элемент
идентификации.

Бинарный оператор также должен быть ассоциативным , что означает (a+b)+c==a+(b+c) .


Это связано с тем, что элементы могут быть уменьшены в любом порядке. Например,
приведенное выше сведение может быть выполнено следующим образом:

https://riptutorial.com/ru/home 197
Это сокращение эквивалентно записи ((1+2)+(3+4)) . Свойство ассоциативности также
позволяет Java сокращать Stream параллельно - часть потока может быть уменьшена
каждым процессором, причем сокращение объединяет результат каждого процессора в
конце.

Присоединение потока к одной строке

Часто используемый прецедент, создающий String из потока, где элементы потока


разделяются определенным символом. Для этого можно использовать метод
Collectors.joining() , как в следующем примере:

Stream<String> fruitStream = Stream.of("apple", "banana", "pear", "kiwi", "orange");

String result = fruitStream.filter(s -> s.contains("a"))


.map(String::toUpperCase)
.sorted()
.collect(Collectors.joining(", "));

System.out.println(result);

Выход:

APPLE, BANANA, ORANGE, PEAR

https://riptutorial.com/ru/home 198
Метод Collectors.joining() может также обслуживать pre- и postfixes:

String result = fruitStream.filter(s -> s.contains("e"))


.map(String::toUpperCase)
.sorted()
.collect(Collectors.joining(", ", "Fruits: ", "."));

System.out.println(result);

Выход:

Фрукты: APPLE, ORANGE, PEAR.

Живой на Ideone

Прочитайте Streams онлайн: https://riptutorial.com/ru/java/topic/88/streams

https://riptutorial.com/ru/home 199
глава 36: StringBuffer
Вступление
Введение в класс Java StringBuffer.

Examples

Класс буфера String

Ключевые моменты: -

• используется для создания изменяемой (модифицируемой) строки.

• Mutable : - Что можно изменить.

• является потокобезопасным, т. е. несколько потоков не могут получить к нему доступ


одновременно.

Методы: -

• публичный синхронизированный StringBuffer append (String s)

• общедоступная синхронизированная вставка StringBuffer (int offset, String s)

• public synchronized StringBuffer replace (int startIndex, int endIndex, String str)

• public synchronized StringBuffer delete (int startIndex, int endIndex)

• открытый синхронизированный реверс StringBuffer ()

• public int capacity ()

• public void secureCapacity (int minimumCapacity)

• public char charAt (индекс int)

• public int length ()

• public String substring (int beginIndex)

• public String substring (int beginIndex, int endIndex)

Пример Отображение различий между реализацией String и String Buffer:

class Test {
public static void main(String args[])

https://riptutorial.com/ru/home 200
{
String str = "study";
str.concat("tonight");
System.out.println(str); // Output: study

StringBuffer strB = new StringBuffer("study");


strB.append("tonight");
System.out.println(strB); // Output: studytonight
}
}

Прочитайте StringBuffer онлайн: https://riptutorial.com/ru/java/topic/10757/stringbuffer

https://riptutorial.com/ru/home 201
глава 37: StringBuilder
Вступление
Класс Java StringBuilder используется для создания изменяемой (модифицируемой) строки.
Класс Java StringBuilder аналогичен классу StringBuffer, за исключением того, что он не
синхронизирован. Он доступен с JDK 1.5.

Синтаксис
• новый StringBuilder ()

• новый StringBuilder (int capacity)

• новый StringBuilder (CharSequence seq)

• новый StringBuilder (построитель StringBuilder)

• новый StringBuilder (строка строки)

• новый StringJoiner (разделитель CharSequence)

• новый StringJoiner (разделитель CharSequence, префикс CharSequence, суффикс


CharSequence)

замечания
Создание нового StringBuilder с типом char в качестве параметра приведет к вызывая
конструктор с аргументом int capacity , а не один с аргументом String string :

StringBuilder v = new StringBuilder('I'); //'I' is a character, "I" is a String.


System.out.println(v.capacity()); --> output 73
System.out.println(v.toString()); --> output nothing

Examples

Повторить строку n раз

Задача: создать String содержащую n повторений String s .

Тривиальный подход будет многократно конкатенировать String

final int n = ...

https://riptutorial.com/ru/home 202
final String s = ...
String result = "";

for (int i = 0; i < n; i++) {


result += s;
}

Это создает n новых экземпляров строк, содержащих от 1 до n повторений s приводит к


времени выполнения O(s.length() * n²) = O(s.length() * (1+2+...+(n-1)+n)) .

Чтобы избежать этого StringBuilder следует использовать, что позволяет создавать String
в O(s.length() * n) :

final int n = ...


final String s = ...

StringBuilder builder = new StringBuilder();

for (int i = 0; i < n; i++) {


builder.append(s);
}

String result = builder.toString();

Сравнение StringBuffer, StringBuilder, Formatter и StringJoiner

В StringBuffer , StringBuilder , Formatter и StringJoiner классы классы утилиты Java SE,


которые используются в основном для сборки строк из другой информации:

• Класс StringBuffer присутствует с Java 1.0 и предоставляет множество методов для


создания и модификации «буфера», содержащего последовательность символов.

• Класс StringBuilder был добавлен в Java 5 для решения проблем производительности


с исходным классом StringBuffer . API-интерфейсы для двух кланов по существу
одинаковы. Основное различие между StringBuffer и StringBuilder заключается в том,
что первое является потокобезопасным и синхронизированным, а второе - нет.

В этом примере показано, как можно использовать StringBuilder :

int one = 1;
String color = "red";
StringBuilder sb = new StringBuilder();
sb.append("One=").append(one).append(", Color=").append(color).append('\n');
System.out.print(sb);
// Prints "One=1, Colour=red" followed by an ASCII newline.

(Класс StringBuffer используется одинаково: просто измените StringBuilder на StringBuffer в


приведенном выше)

Классы StringBuffer и StringBuilder подходят как для сборки, так и для изменения строк; т.е.

https://riptutorial.com/ru/home 203
они предоставляют методы для замены и удаления символов, а также их добавления в
различные. Восстановление двух классов зависит от задачи сборки строк.

• Класс Formatter был добавлен в Java 5 и свободно моделируется функцией sprintf в


стандартной библиотеке C. Он принимает строку формата со встроенными
спецификаторами формата и последовательности других аргументов и генерирует
строку путем преобразования аргументов в текст и замены их вместо
спецификаторов формата. Подробности спецификаторов формата говорят о том, как
аргументы преобразуются в текст.

• Класс StringJoiner был добавлен в Java 8. Это специальный форматир специального


назначения, который лаконично форматирует последовательность строк с
разделителями между ними. Он разработан с полным API и может использоваться с
потоками Java 8.

Вот некоторые типичные примеры использования Formatter :

// This does the same thing as the StringBuilder example above


int one = 1;
String color = "red";
Formatter f = new Formatter();
System.out.print(f.format("One=%d, colour=%s%n", one, color));
// Prints "One=1, Colour=red" followed by the platform's line separator

// The same thing using the `String.format` convenience method


System.out.print(String.format("One=%d, color=%s%n", one, color));

Класс StringJoiner не идеален для вышеуказанной задачи, поэтому здесь приведен пример
форматирования массива строк.

StringJoiner sj = new StringJoiner(", ", "[", "]");


for (String s : new String[]{"A", "B", "C"}) {
sj.add(s);
}
System.out.println(sj);
// Prints "[A, B, C]"

Варианты использования для 4 классов можно суммировать:

• подходит для любой задачи сборки строки или изменения строки.


StringBuilder
• StringBuffer использует (только), когда вам нужна потоковая версия StringBuilder .
• Formatter предоставляет гораздо более богатые функции форматирования строк, но
не так эффективен, как StringBuilder . Это связано с тем, что каждый вызов
Formatter.format(...) влечет за собой:
○разбор строки format ,
○создание и заполнение массива varargs и
○autoboxing любые примитивные аргументы типа.
• StringJoiner обеспечивает StringJoiner и эффективное форматирование

https://riptutorial.com/ru/home 204
последовательности строк с разделителями, но не подходит для других задач
форматирования.

Прочитайте StringBuilder онлайн: https://riptutorial.com/ru/java/topic/1037/stringbuilder

https://riptutorial.com/ru/home 205
глава 38: sun.misc.Unsafe
замечания
Класс Unsafe позволяет программе выполнять действия, которые не допускаются
компилятором Java. Обычным программам следует избегать использования Unsafe .

ПРЕДУПРЕЖДЕНИЯ

1. Если вы ошиблись, используя Unsafe API, ваши приложения могут привести к сбою и /
или выявлению симптомов, которые трудно диагностировать.

2. Unsafe API может быть изменен без предварительного уведомления. Если вы


используете его в своем коде, вам может потребоваться переписать код при
изменении версий Java.

Examples

Выполнение sun.misc.Unsafe через отражение

public static Unsafe getUnsafe() {


try {
Field unsafe = Unsafe.class.getDeclaredField("theUnsafe");
unsafe.setAccessible(true);
return (Unsafe) unsafe.get(null);
} catch (IllegalAccessException e) {
// Handle
} catch (IllegalArgumentException e) {
// Handle
} catch (NoSuchFieldException e) {
// Handle
} catch (SecurityException e) {
// Handle
}
}

имеет частный конструктор, а статический getUnsafe() проверкой загрузчика


sun.misc.Unsafe
классов, чтобы обеспечить загрузку кода с помощью загрузчика основного класса. Поэтому
одним из способов загрузки экземпляра является использование отражения для получения
статического поля.

Выполнение sun.misc.Unsafe через bootclasspath

public class UnsafeLoader {


public static Unsafe loadUnsafe() {
return Unsafe.getUnsafe();
}

https://riptutorial.com/ru/home 206
}

Хотя этот пример будет скомпилирован, он, скорее всего, потерпит неудачу во время
выполнения, если класс Unsafe не будет загружен с помощью основного загрузчика
классов. Чтобы убедиться, что JVM должен быть загружен с соответствующими
аргументами, например:

java -Xbootclasspath:$JAVA_HOME/jre/lib/rt.jar:./UnsafeLoader.jar foo.bar.MyApp

Затем класс foo.bar.MyApp может использовать UnsafeLoader.loadUnsafe() .

Получение экземпляра небезопасного

Небезопасно хранится как частное поле, к которому невозможно получить доступ


напрямую. Конструктор является закрытым и единственным способом доступа к public
static Unsafe getUnsafe() имеет привилегированный доступ. Используя рефлексию, можно
сделать доступными частные поля:

public static final Unsafe UNSAFE;

static {
Unsafe unsafe = null;

try {
final PrivilegedExceptionAction<Unsafe> action = () -> {
final Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);

return (Unsafe) f.get(null);


};

unsafe = AccessController.doPrivileged(action);
} catch (final Throwable t) {
throw new RuntimeException("Exception accessing Unsafe", t);
}

UNSAFE = unsafe;
}

Использование небезопасных

Ниже перечислены некоторые виды использования небезопасных:

использование API

Отключение кучи / прямой памяти, allocateMemory(bytes) ,


перераспределение и освобождение reallocateMemory(address, bytes) и
памяти freeMemory(address)

Запонки памяти loadFence() , storeFence() , fullFence()

https://riptutorial.com/ru/home 207
использование API

Стоянка тока park(isAbsolute, time) , unpark(thread)

Прямой доступ к полю и памяти get* и put* семейство методов

Выброс исключенных исключений throwException(e)

CAS и атомные операции compareAndSwap* семейство методов

Настройка памяти setMemory

Неустойчивые или параллельные


get*Volatile , put*Volatile , putOrdered*
операции

Получаемое семейство методов относится к данному объекту. Если объект имеет значение
null, он рассматривается как абсолютный адрес.

// Putting a value to a field


protected static long fieldOffset = UNSAFE.objectFieldOffset(getClass().getField("theField"));
UNSAFE.putLong(this, fieldOffset , newValue);

// Puting an absolute value


UNSAFE.putLong(null, address, newValue);
UNSAFE.putLong(address, newValue);

Некоторые методы определены только для int и longs. Вы можете использовать эти методы
для поплавков и удвоений, используя floatToRawIntBits , intBitsToFloat,
doubleToRawLongBits , longBitsToDouble`

Прочитайте sun.misc.Unsafe онлайн: https://riptutorial.com/ru/java/topic/6771/sun-misc-unsafe

https://riptutorial.com/ru/home 208
глава 39: ThreadLocal
замечания
Лучше всего использовать объекты, зависящие от внутренних элементов при вызове
вызова, но в противном случае они не имеют аналогов, например SimpleDateFormat ,
Marshaller

Для использования Random ThreadLocal рассмотрите возможность использования


ThreadLocalRandom

Examples

Функциональная инициализация ThreadLocal Java 8

public static class ThreadLocalExample


{
private static final ThreadLocal<SimpleDateFormat> format =
ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyyMMdd_HHmm"));

public String formatDate(Date date)


{
return format.get().format(date);
}
}

Основное использование ThreadLocal

Java ThreadLocal используется для создания локальных переменных потока. Известно, что
потоки объекта разделяют его переменные, поэтому переменная не является
потокобезопасной. Мы можем использовать синхронизацию для безопасности потоков, но
если мы хотим избежать синхронизации, ThreadLocal позволяет нам создавать
переменные, которые являются локальными для потока, то есть только этот поток может
читать или записывать эти переменные, поэтому другие потоки, выполняющие один и тот
же фрагмент кода не смогут обращаться к другим переменным ThreadLocal.

Это можно использовать, мы можем использовать переменные ThreadLocal . в ситуациях,


когда у вас есть пул потоков, например, в веб-службе. Например, создание объекта
SimpleDateFormat каждый раз для каждого запроса занимает много времени, а статический
не может быть создан, поскольку SimpleDateFormat не является потокобезопасным, поэтому
мы можем создать ThreadLocal, чтобы мы могли выполнять поточно-безопасные операции
без накладных расходов на создание SimpleDateFormat каждый время.

Следующий фрагмент кода показывает, как его можно использовать:

https://riptutorial.com/ru/home 209
Каждый поток имеет собственную переменную ThreadLocal и они могут использовать
методы get() и set() для получения значения по умолчанию или изменения локального
значения для Thread.

обычно являются частные статические поля в классах, которые хотят связать


ThreadLocal
состояние с потоком.

Вот небольшой пример, показывающий использование ThreadLocal в java-программе и


доказательство того, что каждый поток имеет свою собственную копию переменной
ThreadLocal .

package com.examples.threads;

import java.text.SimpleDateFormat;
import java.util.Random;

public class ThreadLocalExample implements Runnable{

// SimpleDateFormat is not thread-safe, so give one to each thread


// SimpleDateFormat is not thread-safe, so give one to each thread
private static final ThreadLocal<SimpleDateFormat> formatter = new
ThreadLocal<SimpleDateFormat>(){
@Override
protected SimpleDateFormat initialValue()
{
return new SimpleDateFormat("yyyyMMdd HHmm");
}
};

public static void main(String[] args) throws InterruptedException {


ThreadLocalExample obj = new ThreadLocalExample();
for(int i=0 ; i<10; i++){
Thread t = new Thread(obj, ""+i);
Thread.sleep(new Random().nextInt(1000));
t.start();
}
}

@Override
public void run() {
System.out.println("Thread Name= "+Thread.currentThread().getName()+" default
Formatter = "+formatter.get().toPattern());
try {
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}

formatter.set(new SimpleDateFormat());

System.out.println("Thread Name= "+Thread.currentThread().getName()+" formatter =


"+formatter.get().toPattern());
}

Выход:

https://riptutorial.com/ru/home 210
Thread Name= 0 default Formatter = yyyyMMdd HHmm

Thread Name= 1 default Formatter = yyyyMMdd HHmm

Thread Name= 0 formatter = M/d/yy h:mm a

Thread Name= 2 default Formatter = yyyyMMdd HHmm

Thread Name= 1 formatter = M/d/yy h:mm a

Thread Name= 3 default Formatter = yyyyMMdd HHmm

Thread Name= 4 default Formatter = yyyyMMdd HHmm

Thread Name= 4 formatter = M/d/yy h:mm a

Thread Name= 5 default Formatter = yyyyMMdd HHmm

Thread Name= 2 formatter = M/d/yy h:mm a

Thread Name= 3 formatter = M/d/yy h:mm a

Thread Name= 6 default Formatter = yyyyMMdd HHmm

Thread Name= 5 formatter = M/d/yy h:mm a

Thread Name= 6 formatter = M/d/yy h:mm a

Thread Name= 7 default Formatter = yyyyMMdd HHmm

Thread Name= 8 default Formatter = yyyyMMdd HHmm

Thread Name= 8 formatter = M/d/yy h:mm a

Thread Name= 7 formatter = M/d/yy h:mm a

Thread Name= 9 default Formatter = yyyyMMdd HHmm

Thread Name= 9 formatter = M/d/yy h:mm a

Как видно из вывода, Thread-0 изменил значение форматирования, но форматир по


умолчанию по-умолчанию-нить-то же, что и инициализированное значение.

Несколько потоков с одним общим объектом

В этом примере у нас есть только один объект, но он разделяется между / выполняется на
разных потоках. Обычное использование полей для сохранения состояния было бы
невозможно, потому что другой поток тоже увидит это (или, вероятно, не увидит).

public class Test {


public static void main(String[] args) {
Foo foo = new Foo();
new Thread(foo, "Thread 1").start();
new Thread(foo, "Thread 2").start();
}
}

В Foo мы начинаем отсчет с нуля. Вместо сохранения состояния в поле мы сохраняем наше

https://riptutorial.com/ru/home 211
текущее число в объекте ThreadLocal, который статически доступен. Обратите внимание,
что синхронизация в этом примере не связана с использованием ThreadLocal, а скорее
обеспечивает лучший выход на консоль.

public class Foo implements Runnable {


private static final int ITERATIONS = 10;
private static final ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return 0;
}
};

@Override
public void run() {
for (int i = 0; i < ITERATIONS; i++) {
synchronized (threadLocal) {
//Although accessing a static field, we get our own (previously saved) value.
int value = threadLocal.get();
System.out.println(Thread.currentThread().getName() + ": " + value);

//Update our own variable


threadLocal.set(value + 1);

try {
threadLocal.notifyAll();
if (i < ITERATIONS - 1) {
threadLocal.wait();
}
} catch (InterruptedException ex) {
}
}
}
}
}

Из вывода видно, что каждый поток подсчитывает для себя и не использует значение
другого:

Thread 1: 0
Thread 2: 0
Thread 1: 1
Thread 2: 1
Thread 1: 2
Thread 2: 2
Thread 1: 3
Thread 2: 3
Thread 1: 4
Thread 2: 4
Thread 1: 5
Thread 2: 5
Thread 1: 6
Thread 2: 6
Thread 1: 7
Thread 2: 7
Thread 1: 8
Thread 2: 8
Thread 1: 9

https://riptutorial.com/ru/home 212
Thread 2: 9

Прочитайте ThreadLocal онлайн: https://riptutorial.com/ru/java/topic/2001/threadlocal

https://riptutorial.com/ru/home 213
глава 40: TreeMap и TreeSet
Вступление
и TreeSet являются базовыми TreeSet Java, добавленными в Java 1.2. TreeMap -
TreeMap
измененная , упорядоченная реализация Map . Аналогично, TreeSet является изменяемой ,
упорядоченной реализацией Set .

TreeMap реализован как дерево Red-Black, которое обеспечивает время доступа O(log n) .
TreeSet реализуется с использованием TreeMap с фиктивными значениями.

Обе коллекции не являются потокобезопасными.

Examples

TreeMap простого типа Java

Сначала мы создаем пустую карту и вставляем в нее некоторые элементы:

Java SE 7

TreeMap<Integer, String> treeMap = new TreeMap<>();

Java SE 7

TreeMap<Integer, String> treeMap = new TreeMap<Integer, String>();

treeMap.put(10, "ten");
treeMap.put(4, "four");
treeMap.put(1, "one");
treeSet.put(12, "twelve");

Когда у нас есть несколько элементов на карте, мы можем выполнить некоторые операции:

System.out.println(treeMap.firstEntry()); // Prints 1=one


System.out.println(treeMap.lastEntry()); // Prints 12=twelve
System.out.println(treeMap.size()); // Prints 4, since there are 4 elemens in the map
System.out.println(treeMap.get(12)); // Prints twelve
System.out.println(treeMap.get(15)); // Prints null, since the key is not found in the map

Мы также можем перебирать элементы карты, используя либо Iterator, либо цикл foreach.
Обратите внимание, что записи печатаются в соответствии с их естественным порядком , а
не в порядке ввода:

Java SE 7

https://riptutorial.com/ru/home 214
for (Entry<Integer, String> entry : treeMap.entrySet()) {
System.out.print(entry + " "); //prints 1=one 4=four 10=ten 12=twelve
}

Iterator<Entry<Integer, String>> iter = treeMap.entrySet().iterator();


while (iter.hasNext()) {
System.out.print(iter.next() + " "); //prints 1=one 4=four 10=ten 12=twelve
}

TreeSet простого типа Java

Сначала мы создаем пустой набор и вставляем в него некоторые элементы:

Java SE 7

TreeSet<Integer> treeSet = new TreeSet<>();

Java SE 7

TreeSet<Integer> treeSet = new TreeSet<Integer>();

treeSet.add(10);
treeSet.add(4);
treeSet.add(1);
treeSet.add(12);

Когда у нас есть несколько элементов в наборе, мы можем выполнить некоторые


операции:

System.out.println(treeSet.first()); // Prints 1
System.out.println(treeSet.last()); // Prints 12
System.out.println(treeSet.size()); // Prints 4, since there are 4 elemens in the set
System.out.println(treeSet.contains(12)); // Prints true
System.out.println(treeSet.contains(15)); // Prints false

Мы также можем перебирать элементы карты, используя либо Iterator, либо цикл foreach.
Обратите внимание, что записи печатаются в соответствии с их естественным порядком , а
не в порядке ввода:

Java SE 7

for (Integer i : treeSet) {


System.out.print(i + " "); //prints 1 4 10 12
}

Iterator<Integer> iter = treeSet.iterator();


while (iter.hasNext()) {
System.out.print(iter.next() + " "); //prints 1 4 10 12
}

https://riptutorial.com/ru/home 215
TreeMap / TreeSet настраиваемого типа Java

Поскольку TreeMap s и TreeSet сохраняют ключи / элементы в соответствии с их


естественным порядком . Для этого ключи TreeMap и элементы TreeSet должны
сопоставляться друг с другом.

Скажем, у нас есть пользовательский класс Person :

public class Person {

private int id;


private String firstName, lastName;
private Date birthday;

//... Constuctors, getters, setters and various methods


}

Если мы сохраним его как-есть в TreeSet (или ключ в TreeMap):

TreeSet<Person2> set = ...


set.add(new Person(1,"first","last",Date.from(Instant.now())));

Тогда мы столкнулись бы с Исключением, таким как этот:

Exception in thread "main" java.lang.ClassCastException: Person cannot be cast to


java.lang.Comparable
at java.util.TreeMap.compare(TreeMap.java:1294)
at java.util.TreeMap.put(TreeMap.java:538)
at java.util.TreeSet.add(TreeSet.java:255)

Чтобы исправить это, предположим, что мы хотим заказать экземпляры Person на основе
порядка их идентификаторов ( private int id ). Мы могли бы сделать это одним из двух
способов:

1. Одним из решений является изменение Person чтобы он реализовал интерфейс


Comparable :

public class Person implements Comparable<Person> {


private int id;
private String firstName, lastName;
private Date birthday;

//... Constuctors, getters, setters and various methods

@Override
public int compareTo(Person o) {
return Integer.compare(this.id, o.id); //Compare by id
}
}

2. Еще одно решение - предоставить TreeSet компаратору :

https://riptutorial.com/ru/home 216
Java SE 8

TreeSet<Person> treeSet = new TreeSet<>((personA, personB) -> Integer.compare(personA.getId(),


personB.getId()));

TreeSet<Person> treeSet = new TreeSet<>(new Comparator<Person>(){


@Override
public int compare(Person personA, Person personB) {
return Integer.compare(personA.getId(), personB.getId());
}
});

Однако есть два оговорки к обоим подходам:

1. Очень важно не изменять какие-либо поля, используемые для упорядочения, как


только экземпляр был вставлен в TreeSet / TreeMap . В приведенном выше примере, если
мы изменим id человека, который уже вставлен в коллекцию, мы можем столкнуться с
неожиданным поведением.

2. Важно правильно и последовательно выполнять сравнение. Согласно Джавадоку :

Разработчик должен обеспечить sgn(x.compareTo(y)) == -sgn(y.compareTo(x)) для


всех x и y. (Это означает, что x.compareTo(y) должен генерировать исключение,
если y.compareTo(x) генерирует исключение).

Разработчик должен также гарантировать, что отношение транзитивно:


(x.compareTo(y)>0 && y.compareTo(z)>0) подразумевает x.compareTo(z)>0 .

Наконец, разработчик должен убедиться, что x.compareTo(y)==0 означает, что


sgn(x.compareTo(z)) == sgn(y.compareTo(z)) для всех z.

Безопасность TreeMap и TreeSet

и TreeSet не являются потокобезопасными коллекциями, поэтому необходимо


TreeMap
соблюдать осторожность при использовании в многопоточных программах.

Оба TreeMap и TreeSet безопасны при чтении, даже одновременно, несколькими потоками.
Поэтому, если они были созданы и заполнены одним потоком (скажем, в начале
программы), и только после этого будут прочитаны, но не изменены несколькими потоками,
нет причин для синхронизации или блокировки.

Однако, если чтение и изменение одновременно или изменено одновременно более чем
одним потоком, сбор может вызывать исключение ConcurrentModificationException или
вести себя неожиданно. В этих случаях настоятельно необходимо синхронизировать /
заблокировать доступ к коллекции, используя один из следующих подходов:

1. Использование Collections.synchronizedSorted.. :

https://riptutorial.com/ru/home 217
SortedSet<Integer> set = Collections.synchronizedSortedSet(new TreeSet<Integer>());
SortedMap<Integer,String> map = Collections.synchronizedSortedMap(new
TreeMap<Integer,String>());

Это обеспечит реализацию SortedSet / SortedMap, поддерживаемую фактической


коллекцией, и синхронизируется с некоторым объектом mutex. Обратите внимание,
что это синхронизирует весь доступ на чтение и запись к коллекции на одном замке,
поэтому даже одновременные чтения не будут возможны.

2. Ручная синхронизация на каком-либо объекте, как и сама коллекция:

TreeSet<Integer> set = new TreeSet<>();

...

//Thread 1
synchronized (set) {
set.add(4);
}

...

//Thread 2
synchronized (set) {
set.remove(5);
}

3. Используя блокировку, такую как ReentrantReadWriteLock :

TreeSet<Integer> set = new TreeSet<>();


ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

...

//Thread 1
lock.writeLock().lock();
set.add(4);
lock.writeLock().unlock();

...

//Thread 2
lock.readLock().lock();
set.contains(5);
lock.readLock().unlock();

В отличие от предыдущих методов синхронизации, использование ReadWriteLock


позволяет одновременно просматривать несколько потоков с карты.

https://riptutorial.com/ru/home 218
Прочитайте TreeMap и TreeSet онлайн: https://riptutorial.com/ru/java/topic/9905/treemap-и-
treeset

https://riptutorial.com/ru/home 219
глава 41: Varargs (переменный аргумент)
замечания
Аргумент метода «varargs» позволяет вызывающим сторонам этого метода указывать
несколько аргументов назначенного типа, каждый из которых является отдельным
аргументом. Он указан в объявлении метода тремя периодами ASCII ( ... ) после базового
типа.

Сам метод получает эти аргументы как один массив, тип элемента которого является типом
аргумента varargs. Массив создается автоматически (хотя вызывающим абонентам по-
прежнему разрешено передавать явный массив вместо передачи нескольких значений в
виде отдельных аргументов метода).

Правила для варгаров:

1. Варанг должен быть последним аргументом.


2. В методе может быть только один Varargs.

Вы должны следовать выше правилам, иначе программа даст ошибку компиляции.

Examples

Указание параметра varargs

void doSomething(String... strings) {


for (String s : strings) {
System.out.println(s);
}
}

Три периода после окончательного параметра указывают, что последний аргумент может
быть передан как массив или как последовательность аргументов. Варгары могут
использоваться только в конечной позиции аргумента.

Работа с параметрами Varargs

Используя varargs в качестве параметра для определения метода, можно передать либо
массив, либо последовательность аргументов. Если последовательность аргументов
передана, они автоматически преобразуются в массив.

В этом примере показан как массив, так и последовательность аргументов, передаваемых


в метод printVarArgArray() , и то, как они обрабатываются одинаково в коде внутри метода:

https://riptutorial.com/ru/home 220
public class VarArgs {

// this method will print the entire contents of the parameter passed in

void printVarArgArray(int... x) {
for (int i = 0; i < x.length; i++) {
System.out.print(x[i] + ",");
}
}

public static void main(String args[]) {


VarArgs obj = new VarArgs();

//Using an array:
int[] testArray = new int[]{10, 20};
obj.printVarArgArray(testArray);

System.out.println(" ");

//Using a sequence of arguments


obj.printVarArgArray(5, 6, 5, 8, 6, 31);
}
}

Выход:

10,20,
5,6,5,8,6,31

Если вы определите метод, подобный этому, он даст ошибки времени компиляции.

void method(String... a, int... b , int c){} //Compile time error (multiple varargs )

void method(int... a, String b){} //Compile time error (varargs must be the last argument

Прочитайте Varargs (переменный аргумент) онлайн:


https://riptutorial.com/ru/java/topic/1948/varargs--переменный-аргумент-

https://riptutorial.com/ru/home 221
глава 42: WeakHashMap
Вступление
Концепции слабого хашмапа

Examples

Концепции WeakHashmap

Ключевые моменты: -

• Реализация карты.
• хранит только слабые ссылки на его ключи.

Слабые ссылки : объекты, на которые ссылаются только слабые ссылки, - это мусор,
собранный с нетерпением; GC не будет ждать, пока в этом случае ему понадобится
память.

Разница между Hashmap и WeakHashMap: -

Если диспетчер памяти Java больше не имеет ссылки на объект, указанный в качестве
ключа, то запись на карте будет удалена в WeakHashMap.

Пример :-

public class WeakHashMapTest {


public static void main(String[] args) {
Map hashMap= new HashMap();

Map weakHashMap = new WeakHashMap();

String keyHashMap = new String("keyHashMap");


String keyWeakHashMap = new String("keyWeakHashMap");

hashMap.put(keyHashMap, "Ankita");
weakHashMap.put(keyWeakHashMap, "Atul");
System.gc();
System.out.println("Before: hash map value:"+hashMap.get("keyHashMap")+" and weak hash
map value:"+weakHashMap.get("keyWeakHashMap"));

keyHashMap = null;
keyWeakHashMap = null;

System.gc();

System.out.println("After: hash map value:"+hashMap.get("keyHashMap")+" and weak hash


map value:"+weakHashMap.get("keyWeakHashMap"));
}

https://riptutorial.com/ru/home 222
Различия в размерах (HashMap vs WeakHashMap):

Метод calling size () для объекта HashMap возвращает одинаковое количество пар ключ-
значение. размер будет уменьшаться только в том случае, если метод remove () явно
указан в объекте HashMap.

Поскольку сборщик мусора может отменить ключи в любое время, WeakHashMap может
вести себя так, как если бы неизвестный поток молча удалял записи. Таким образом, метод
size может возвращать меньшие значения с течением времени. Таким образом,
уменьшение WeakHashMap происходит автоматически .

Прочитайте WeakHashMap онлайн: https://riptutorial.com/ru/java/topic/10749/weakhashmap

https://riptutorial.com/ru/home 223
глава 43: XJC
Вступление
XJC - это инструмент Java SE, который компилирует файл схемы XML в полностью
аннотированные классы Java.

Он распространяется в пакете JDK и находится по пути /bin/xjc .

Синтаксис
• xjc [options] файл схемы / URL / dir / jar ... [-b bindinfo] ...

параметры

параметр подробности

файл схемы Файл схемы xsd для преобразования в java

замечания
Инструмент XJC доступен как часть JDK. Он позволяет создавать java-код,
аннотированный аннотациями JAXB, подходящими для (un) сортировки.

Examples

Создание Java-кода из простого XSD-файла

Схема XSD (schema.xsd)


Следующая xml-схема (xsd) определяет список пользователей с name атрибутов и reputation
.

<?xml version="1.0"?>

<xs:schema version="1.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:ns="http://www.stackoverflow.com/users"
elementFormDefault="qualified"
targetNamespace="http://www.stackoverflow.com/users">
<xs:element name="users" type="ns:Users"/>

https://riptutorial.com/ru/home 224
<xs:complexType name="Users">
<xs:sequence>
<xs:element type="ns:User" name="user" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>

<xs:complexType name="User">
<xs:attribute name="name" use="required" type="xs:string"/>
<xs:attribute name="reputation" use="required">
<xs:simpleType>
<xs:restriction base="xs:int">
<xs:minInclusive value="1"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:schema>

Используя xjc
Для этого требуется, чтобы путь к инструменту xjc (двоичные файлы JDK) находился в
переменной пути ОС.

Генерация кода может быть запущена с использованием

xjc schema.xsd

Это приведет к созданию java-файлов в рабочем каталоге.

Файлы результатов
Будут некоторые дополнительные комментарии, но в основном созданные файлы java
выглядят следующим образом:

package com.stackoverflow.users;

import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Users", propOrder = {
"user"
})
public class Users {

protected List<User> user;

public List<User> getUser() {


if (user == null) {

https://riptutorial.com/ru/home 225
user = new ArrayList<User>();
}
return this.user;
}

package com.stackoverflow.users;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlType;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "User")
public class User {

@XmlAttribute(name = "name", required = true)


protected String name;
@XmlAttribute(name = "reputation", required = true)
protected int reputation;

public String getName() {


return name;
}

public void setName(String value) {


this.name = value;
}

public int getReputation() {


return reputation;
}

public void setReputation(int value) {


this.reputation = value;
}

package com.stackoverflow.users;

import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlElementDecl;
import javax.xml.bind.annotation.XmlRegistry;
import javax.xml.namespace.QName;

@XmlRegistry
public class ObjectFactory {

private final static QName _Users_QNAME = new QName("http://www.stackoverflow.com/users",


"users");

public ObjectFactory() {
}

public Users createUsers() {


return new Users();
}

https://riptutorial.com/ru/home 226
public User createUser() {
return new User();
}

@XmlElementDecl(namespace = "http://www.stackoverflow.com/users", name = "users")


public JAXBElement<Users> createUsers(Users value) {
return new JAXBElement<Users>(_Users_QNAME, Users.class, null, value);
}

package-info.java

@javax.xml.bind.annotation.XmlSchema(namespace = "http://www.stackoverflow.com/users",
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package com.stackoverflow.users;

Прочитайте XJC онлайн: https://riptutorial.com/ru/java/topic/4538/xjc

https://riptutorial.com/ru/home 227
глава 44: XOM - Объектная модель XML
Examples

Чтение XML-файла

Чтобы загрузить XML-данные с помощью XOM, вам нужно будет создать Builder из
которого вы можете создать его в Document .

Builder builder = new Builder();


Document doc = builder.build(file);

Чтобы получить корневой элемент, самый старший родитель в файле xml, вам нужно
использовать getRootElement() в экземпляре Document .

Element root = doc.getRootElement();

Теперь класс Element имеет множество удобных методов, которые упрощают чтение xml.
Ниже перечислены некоторые из наиболее полезных:

• getChildElements(String name) - возвращает экземпляр Elements который действует как


массив элементов
• getFirstChildElement(String name) - возвращает первый дочерний элемент с этим тегом.
• getValue() - возвращает значение внутри элемента.
• getAttributeValue(String name) - возвращает значение атрибута с указанным именем.

Когда вы вызываете getChildElements() вы получаете экземпляр Elements . Из этого вы


можете выполнить цикл и вызвать метод get(int index) чтобы получить все элементы
внутри.

Elements colors = root.getChildElements("color");


for (int q = 0; q < colors.size(); q++){
Element color = colors.get(q);
}

Пример: Вот пример чтения XML-файла:

Файл XML:

https://riptutorial.com/ru/home 228
Код для чтения и печати:

import java.io.File;
import java.io.IOException;
import nu.xom.Builder;
import nu.xom.Document;
import nu.xom.Element;
import nu.xom.Elements;
import nu.xom.ParsingException;

public class XMLReader {

public static void main(String[] args) throws ParsingException, IOException{


File file = new File("insert path here");
// builder builds xml data
Builder builder = new Builder();
Document doc = builder.build(file);

// get the root element <example>


Element root = doc.getRootElement();

// gets all element with tag <person>


Elements people = root.getChildElements("person");

for (int q = 0; q < people.size(); q++){


// get the current person element
Element person = people.get(q);

// get the name element and its children: first and last
Element nameElement = person.getFirstChildElement("name");
Element firstNameElement = nameElement.getFirstChildElement("first");
Element lastNameElement = nameElement.getFirstChildElement("last");

// get the age element

https://riptutorial.com/ru/home 229
Element ageElement = person.getFirstChildElement("age");

// get the favorite color element


Element favColorElement = person.getFirstChildElement("fav_color");

String fName, lName, ageUnit, favColor;


int age;

try {
fName = firstNameElement.getValue();
lName = lastNameElement.getValue();
age = Integer.parseInt(ageElement.getValue());
ageUnit = ageElement.getAttributeValue("unit");
favColor = favColorElement.getValue();

System.out.println("Name: " + lName + ", " + fName);


System.out.println("Age: " + age + " (" + ageUnit + ")");
System.out.println("Favorite Color: " + favColor);
System.out.println("----------------");

} catch (NullPointerException ex){


ex.printStackTrace();
} catch (NumberFormatException ex){
ex.printStackTrace();
}
}
}

Это выведет на консоль:

Name: Smith, Dan


Age: 23 (years)
Favorite Color: green
----------------
Name: Autry, Bob
Age: 3 (months)
Favorite Color: N/A
----------------

Запись в файл XML

Запись в XML-файл с использованием XOM очень похожа на его чтение, но в этом случае
мы делаем экземпляры вместо того, чтобы извлекать их из корня.

Чтобы создать новый элемент, используйте конструктор Element(String name) . Вы захотите


создать корневой элемент, чтобы его можно было легко добавить в Document .

Element root = new Element("root");

Класс Element имеет несколько удобных методов редактирования элементов. Они


перечислены ниже:

https://riptutorial.com/ru/home 230
• appendChild(String name) - это будет в основном устанавливать значение имени
элемента.
• - это сделает node элементами parent. (Элементы являются
appendChild(Node node)
узлами, поэтому вы можете анализировать элементы).
• addAttribute(Attribute attribute) - добавит атрибут к элементу.

Класс Attribute имеет несколько разных конструкторов. Самый простой - это


Attribute(String name, String value) .

Когда вы добавите все свои элементы в свой корневой элемент, вы можете превратить его
в Document . Document примет Element в качестве аргумента в его конструкторе.

можно использовать для записи XML в файл. Вам нужно будет создать новый
Serializer
выходной поток для анализа в конструкторе Serializer .

FileOutputStream fileOutputStream = new FileOutputStream(file);


Serializer serializer = new Serializer(fileOutputStream, "UTF-8");
serializer.setIndent(4);
serializer.write(doc);

пример

Код:

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import nu.xom.Attribute;
import nu.xom.Builder;
import nu.xom.Document;
import nu.xom.Element;
import nu.xom.Elements;
import nu.xom.ParsingException;
import nu.xom.Serializer;

public class XMLWriter{

public static void main(String[] args) throws UnsupportedEncodingException,


IOException{
// root element <example>
Element root = new Element("example");

// make a array of people to store


Person[] people = {new Person("Smith", "Dan", "years", "green", 23),
new Person("Autry", "Bob", "months", "N/A", 3)};

// add all the people


for (Person person : people){

// make the main person element <person>


Element personElement = new Element("person");

https://riptutorial.com/ru/home 231
// make the name element and it's children: first and last
Element nameElement = new Element("name");
Element firstNameElement = new Element("first");
Element lastNameElement = new Element("last");

// make age element


Element ageElement = new Element("age");

// make favorite color element


Element favColorElement = new Element("fav_color");

// add value to names


firstNameElement.appendChild(person.getFirstName());
lastNameElement.appendChild(person.getLastName());

// add names to name


nameElement.appendChild(firstNameElement);
nameElement.appendChild(lastNameElement);

// add value to age


ageElement.appendChild(String.valueOf(person.getAge()));

// add unit attribute to age


ageElement.addAttribute(new Attribute("unit", person.getAgeUnit()));

// add value to favColor


favColorElement.appendChild(person.getFavoriteColor());

// add all contents to person


personElement.appendChild(nameElement);
personElement.appendChild(ageElement);
personElement.appendChild(favColorElement);

// add person to root


root.appendChild(personElement);
}

// create doc off of root


Document doc = new Document(root);

// the file it will be stored in


File file = new File("out.xml");
if (!file.exists()){
file.createNewFile();
}

// get a file output stream ready


FileOutputStream fileOutputStream = new FileOutputStream(file);

// use the serializer class to write it all


Serializer serializer = new Serializer(fileOutputStream, "UTF-8");
serializer.setIndent(4);
serializer.write(doc);
}

private static class Person {

private String lName, fName, ageUnit, favColor;


private int age;

https://riptutorial.com/ru/home 232
public Person(String lName, String fName, String ageUnit, String favColor, int age){
this.lName = lName;
this.fName = fName;
this.age = age;
this.ageUnit = ageUnit;
this.favColor = favColor;
}

public String getLastName() { return lName; }


public String getFirstName() { return fName; }
public String getAgeUnit() { return ageUnit; }
public String getFavoriteColor() { return favColor; }
public int getAge() { return age; }
}

Это будет содержимое «out.xml»:

Прочитайте XOM - Объектная модель XML онлайн:


https://riptutorial.com/ru/java/topic/5091/xom---объектная-модель-xml

https://riptutorial.com/ru/home 233
глава 45: Альтернативные коллекции
замечания
Этот раздел о коллекциях Java из guava, apache, eclipse: Multiset, Bag, Multimap, utils
работает из этой библиотеки и так далее.

Examples

Apache HashBag, Guava HashMultiset и Eclipse HashBag

Сумка / ultiset хранит каждый объект в коллекции вместе с количеством вхождений.


Дополнительные методы интерфейса позволяют одновременно добавлять или удалять
несколько копий объекта. JDK-аналог - это HashMap <T, Integer>, когда значения являются
количеством копий этого ключа.

Коллекции
Тип гуайява коллекционеров Коллекции GS JD
Apache

Заказ не
HashMultiset HashBag HashBag Ha
определен

отсортированный TreeMultiset TreeBag TreeBag Tr

Вносимые заказ LinkedHashMultiset - - Lin

Параллельный
ConcurrentHashMultiset SynchronizedBag SynchronizedBag Co
вариант

Параллельные и
- SynchronizedSortedBag SynchronizedSortedBag Co
сортированные

Неизменяемая
ImmutableMultiset UnmodifiableBag UnmodifiableBag Co
коллекция

Неизменяемость Co
ImmutableSortedMultiset UnmodifiableSortedBag UnmodifiableSortedBag
и сортировка )

Примеры :

1. Использование SynchronizedSortedBag из Apache :

https://riptutorial.com/ru/home 234
// Parse text to separate words
String INPUT_TEXT = "Hello World! Hello All! Hi World!";
// Create Multiset
Bag bag = SynchronizedSortedBag.synchronizedBag(new
TreeBag(Arrays.asList(INPUT_TEXT.split(" "))));

// Print count words


System.out.println(bag); // print [1:All!,2:Hello,1:Hi,2:World!]- in natural (alphabet)
order
// Print all unique words
System.out.println(bag.uniqueSet()); // print [All!, Hello, Hi, World!]- in natural
(alphabet) order

// Print count occurrences of words


System.out.println("Hello = " + bag.getCount("Hello")); // print 2
System.out.println("World = " + bag.getCount("World!")); // print 2
System.out.println("All = " + bag.getCount("All!")); // print 1
System.out.println("Hi = " + bag.getCount("Hi")); // print 1
System.out.println("Empty = " + bag.getCount("Empty")); // print 0

// Print count all words


System.out.println(bag.size()); //print 6

// Print count unique words


System.out.println(bag.uniqueSet().size()); //print 4

2. Использование TreeBag из Eclipse (GC) :

// Parse text to separate words


String INPUT_TEXT = "Hello World! Hello All! Hi World!";
// Create Multiset
MutableSortedBag<String> bag = TreeBag.newBag(Arrays.asList(INPUT_TEXT.split(" ")));

// Print count words


System.out.println(bag); // print [All!, Hello, Hello, Hi, World!, World!]- in natural
order
// Print all unique words
System.out.println(bag.toSortedSet()); // print [All!, Hello, Hi, World!]- in natural
order

// Print count occurrences of words


System.out.println("Hello = " + bag.occurrencesOf("Hello")); // print 2
System.out.println("World = " + bag.occurrencesOf("World!")); // print 2
System.out.println("All = " + bag.occurrencesOf("All!")); // print 1
System.out.println("Hi = " + bag.occurrencesOf("Hi")); // print 1
System.out.println("Empty = " + bag.occurrencesOf("Empty")); // print 0

// Print count all words


System.out.println(bag.size()); //print 6

// Print count unique words


System.out.println(bag.toSet().size()); //print 4

3. Использование LinkedHashMultiset из Guava :

// Parse text to separate words

https://riptutorial.com/ru/home 235
String INPUT_TEXT = "Hello World! Hello All! Hi World!";
// Create Multiset
Multiset<String> multiset = LinkedHashMultiset.create(Arrays.asList(INPUT_TEXT.split("
")));

// Print count words


System.out.println(multiset); // print [Hello x 2, World! x 2, All!, Hi]- in predictable
iteration order
// Print all unique words
System.out.println(multiset.elementSet()); // print [Hello, World!, All!, Hi] - in
predictable iteration order

// Print count occurrences of words


System.out.println("Hello = " + multiset.count("Hello")); // print 2
System.out.println("World = " + multiset.count("World!")); // print 2
System.out.println("All = " + multiset.count("All!")); // print 1
System.out.println("Hi = " + multiset.count("Hi")); // print 1
System.out.println("Empty = " + multiset.count("Empty")); // print 0

// Print count all words


System.out.println(multiset.size()); //print 6

// Print count unique words


System.out.println(multiset.elementSet().size()); //print 4

Дополнительные примеры:
I. Коллекция Apache:

1. HashBag - заказ не определен


2. SynchronizedBag - одновременный и не заданный порядок
3. SynchronizedSortedBag - - одновременный и отсортированный порядок
4. TreeBag - отсортированный порядок

II. Коллекция GS / Eclipse

5. MutableBag - порядок не определен


6. MutableSortedBag - отсортированный порядок

III. гуайява

7. HashMultiset - порядок не определен


8. TreeMultiset - отсортированный порядок
9. LinkedHashMultiset - порядок вставки
10. ConcurrentHashMultiset - одновременный и не заданный порядок

Мультимап в коллекциях Guava, Apache и Eclipse

Эта многоадресная карта позволяет дублировать пары ключ-значение. Аналогами JDK


являются HashMap <K, List>, HashMap <K, Set> и т. Д.

https://riptutorial.com/ru/home 236
Заказ Аналоговый Аналоговое
Заказ ключа дублировать гуайява
стоимости ключ значение

не определен Вносимые заказ да HashMap ArrayList ArrayList

не определен не определен нет HashMap HashSet HashMu

Multimaps
newMultim
не определен отсортированный нет HashMap TreeSet HashMap,
<TreeSet>

Вносимые заказ Вносимые заказ да LinkedHashMap ArrayList LinkedLi

Вносимые заказ Вносимые заказ нет LinkedHashMap LinkedHashSet LinkedHa

отсортированный отсортированный нет TreeMap TreeSet TreeMult

Примеры использования Multimap

Задача : проанализировать «Hello World! Hello All! Hi World!» string для разделения слов и
печати всех индексов каждого слова с помощью MultiMap (например, Hello = [0, 2], World! =
[1, 5] и т. д.),

1. MultiValueMap из Apache

String INPUT_TEXT = "Hello World! Hello All! Hi World!";


// Parse text to words and index
List<String> words = Arrays.asList(INPUT_TEXT.split(" "));
// Create Multimap
MultiMap<String, Integer> multiMap = new MultiValueMap<String, Integer>();

// Fill Multimap
int i = 0;
for(String word: words) {
multiMap.put(word, i);
i++;
}

// Print all words


System.out.println(multiMap); // print {Hi=[4], Hello=[0, 2], World!=[1, 5], All!=[3]} -
in random orders
// Print all unique words
System.out.println(multiMap.keySet()); // print [Hi, Hello, World!, All!] - in random

https://riptutorial.com/ru/home 237
orders

// Print all indexes


System.out.println("Hello = " + multiMap.get("Hello")); // print [0, 2]
System.out.println("World = " + multiMap.get("World!")); // print [1, 5]
System.out.println("All = " + multiMap.get("All!")); // print [3]
System.out.println("Hi = " + multiMap.get("Hi")); // print [4]
System.out.println("Empty = " + multiMap.get("Empty")); // print null

// Print count unique words


System.out.println(multiMap.keySet().size()); //print 4

2. HashBiMap из коллекции GS / Eclipse

String[] englishWords = {"one", "two", "three","ball","snow"};


String[] russianWords = {"jeden", "dwa", "trzy", "kula", "snieg"};

// Create Multiset
MutableBiMap<String, String> biMap = new HashBiMap(englishWords.length);
// Create English-Polish dictionary
int i = 0;
for(String englishWord: englishWords) {
biMap.put(englishWord, russianWords[i]);
i++;
}

// Print count words


System.out.println(biMap); // print {two=dwa, ball=kula, one=jeden, snow=snieg,
three=trzy} - in random orders
// Print all unique words
System.out.println(biMap.keySet()); // print [snow, two, one, three, ball] - in random
orders
System.out.println(biMap.values()); // print [dwa, kula, jeden, snieg, trzy] - in
random orders

// Print translate by words


System.out.println("one = " + biMap.get("one")); // print one = jeden
System.out.println("two = " + biMap.get("two")); // print two = dwa
System.out.println("kula = " + biMap.inverse().get("kula")); // print kula = ball
System.out.println("snieg = " + biMap.inverse().get("snieg")); // print snieg = snow
System.out.println("empty = " + biMap.get("empty")); // print empty = null

// Print count word's pair


System.out.println(biMap.size()); //print 5

3. HashMultiMap из Гуавы

String INPUT_TEXT = "Hello World! Hello All! Hi World!";


// Parse text to words and index
List<String> words = Arrays.asList(INPUT_TEXT.split(" "));
// Create Multimap
Multimap<String, Integer> multiMap = HashMultimap.create();

// Fill Multimap
int i = 0;
for(String word: words) {
multiMap.put(word, i);
i++;

https://riptutorial.com/ru/home 238
}

// Print all words


System.out.println(multiMap); // print {Hi=[4], Hello=[0, 2], World!=[1, 5], All!=[3]} -
keys and values in random orders
// Print all unique words
System.out.println(multiMap.keySet()); // print [Hi, Hello, World!, All!] - in random
orders

// Print all indexes


System.out.println("Hello = " + multiMap.get("Hello")); // print [0, 2]
System.out.println("World = " + multiMap.get("World!")); // print [1, 5]
System.out.println("All = " + multiMap.get("All!")); // print [3]
System.out.println("Hi = " + multiMap.get("Hi")); // print [4]
System.out.println("Empty = " + multiMap.get("Empty")); // print []

// Print count all words


System.out.println(multiMap.size()); //print 6

// Print count unique words


System.out.println(multiMap.keySet().size()); //print 4

Примеры Nore:
I. Коллекция Apache:

1. MultiValueMap
2. MultiValueMapLinked
3. MultiValueMapTree

II. Коллекция GS / Eclipse

1. FastListMultimap
2. HashBagMultimap
3. TreeSortedSetMultimap
4. UnifiedSetMultimap

III. гуайява

1. HashMultiMap
2. LinkedHashMultimap
3. LinkedListMultimap
4. TreeMultimap
5. ArrayListMultimap

Сравнить операции с коллекциями - Создание коллекций

Сравнить операции с коллекциями - Создание коллекций

1. Создать список

https://riptutorial.com/ru/home 239
Описание JDK гуайява GS-коллекции

Создать
new ArrayList<> () Lists.newArrayList() FastList.newList()
пустой список

Создать
Arrays.asList("1", "2", FastList.newListWith("
список из "3")
Lists.newArrayList("1", "2", "3")
"2", "3")
значений

Создать
список с
new ArrayList<>(100) Lists.newArrayListWithCapacity(100) FastList.newList(100)
емкостью =
100

Создать
список из new
Lists.newArrayList(collection) FastList.newList(colle
ArrayList<>(collection)
любого
собрания

Создать
список из
- Lists.newArrayList(iterable) FastList.newList(itera
любого
Итерабельного

Создать
список из - Lists.newArrayList(iterator) -
Iterator

Создать
список из Arrays.asList(array) Lists.newArrayList(array) FastList.newListWith(a

массива

Создать
список, FastList.newWithNValue
- - () -> "1")
используя
заводские

Примеры:

System.out.println("createArrayList start");
// Create empty list
List<String> emptyGuava = Lists.newArrayList(); // using guava
List<String> emptyJDK = new ArrayList<>(); // using JDK
MutableList<String> emptyGS = FastList.newList(); // using gs

// Create list with 100 element


List < String > exactly100 = Lists.newArrayListWithCapacity(100); // using guava
List<String> exactly100JDK = new ArrayList<>(100); // using JDK

https://riptutorial.com/ru/home 240
MutableList<String> empty100GS = FastList.newList(100); // using gs

// Create list with about 100 element


List<String> approx100 = Lists.newArrayListWithExpectedSize(100); // using guava
List<String> approx100JDK = new ArrayList<>(115); // using JDK
MutableList<String> approx100GS = FastList.newList(115); // using gs

// Create list with some elements


List<String> withElements = Lists.newArrayList("alpha", "beta", "gamma"); // using guava
List<String> withElementsJDK = Arrays.asList("alpha", "beta", "gamma"); // using JDK
MutableList<String> withElementsGS = FastList.newListWith("alpha", "beta", "gamma"); //
using gs

System.out.println(withElements);
System.out.println(withElementsJDK);
System.out.println(withElementsGS);

// Create list from any Iterable interface (any collection)


Collection<String> collection = new HashSet<>(3);
collection.add("1");
collection.add("2");
collection.add("3");

List<String> fromIterable = Lists.newArrayList(collection); // using guava


List<String> fromIterableJDK = new ArrayList<>(collection); // using JDK
MutableList<String> fromIterableGS = FastList.newList(collection); // using gs

System.out.println(fromIterable);
System.out.println(fromIterableJDK);
System.out.println(fromIterableGS);
/* Attention: JDK create list only from Collection, but guava and gs can create list from
Iterable and Collection */

// Create list from any Iterator


Iterator<String> iterator = collection.iterator();
List<String> fromIterator = Lists.newArrayList(iterator); // using guava
System.out.println(fromIterator);

// Create list from any array


String[] array = {"4", "5", "6"};
List<String> fromArray = Lists.newArrayList(array); // using guava
List<String> fromArrayJDK = Arrays.asList(array); // using JDK
MutableList<String> fromArrayGS = FastList.newListWith(array); // using gs
System.out.println(fromArray);
System.out.println(fromArrayJDK);
System.out.println(fromArrayGS);

// Create list using fabric


MutableList<String> fromFabricGS = FastList.newWithNValues(10, () ->
String.valueOf(Math.random())); // using gs
System.out.println(fromFabricGS);

System.out.println("createArrayList end");

2 Создать набор

Описание JDK гуайява GS-коллекции

Создать
new HashSet<>() Sets.newHashSet() UnifiedSet.newSet()
пустой набор

https://riptutorial.com/ru/home 241
Описание JDK гуайява GS-коллекции

Творческий new
HashSet<>(Arrays.asList("alpha", Sets.newHashSet("alpha", UnifiedSet.newSetWith
набор из "beta", "gamma") "beta", "gamma")
"beta", "gamma") )
значений

Создать набор
из любых new HashSet<>(collection) Sets.newHashSet(collection) UnifiedSet.newSet(col

коллекций

Создать набор
из любого - Sets.newHashSet(iterable) UnifiedSet.newSet(ite

Итерабельного

Создать набор
из любого - Sets.newHashSet(iterator) -
Итератора

Создать набор new


Sets.newHashSet(array) UnifiedSet.newSetWith
HashSet<>(Arrays.asList(array))
из массива

Примеры:

System.out.println("createHashSet start");
// Create empty set
Set<String> emptyGuava = Sets.newHashSet(); // using guava
Set<String> emptyJDK = new HashSet<>(); // using JDK
Set<String> emptyGS = UnifiedSet.newSet(); // using gs

// Create set with 100 element


Set<String> approx100 = Sets.newHashSetWithExpectedSize(100); // using guava
Set<String> approx100JDK = new HashSet<>(130); // using JDK
Set<String> approx100GS = UnifiedSet.newSet(130); // using gs

// Create set from some elements


Set<String> withElements = Sets.newHashSet("alpha", "beta", "gamma"); // using guava
Set<String> withElementsJDK = new HashSet<>(Arrays.asList("alpha", "beta", "gamma")); //
using JDK
Set<String> withElementsGS = UnifiedSet.newSetWith("alpha", "beta", "gamma"); // using gs

System.out.println(withElements);
System.out.println(withElementsJDK);
System.out.println(withElementsGS);

// Create set from any Iterable interface (any collection)


Collection<String> collection = new ArrayList<>(3);
collection.add("1");
collection.add("2");
collection.add("3");

Set<String> fromIterable = Sets.newHashSet(collection); // using guava


Set<String> fromIterableJDK = new HashSet<>(collection); // using JDK
Set<String> fromIterableGS = UnifiedSet.newSet(collection); // using gs

https://riptutorial.com/ru/home 242
System.out.println(fromIterable);
System.out.println(fromIterableJDK);
System.out.println(fromIterableGS);
/* Attention: JDK create set only from Collection, but guava and gs can create set from
Iterable and Collection */

// Create set from any Iterator


Iterator<String> iterator = collection.iterator();
Set<String> fromIterator = Sets.newHashSet(iterator); // using guava
System.out.println(fromIterator);

// Create set from any array


String[] array = {"4", "5", "6"};
Set<String> fromArray = Sets.newHashSet(array); // using guava
Set<String> fromArrayJDK = new HashSet<>(Arrays.asList(array)); // using JDK
Set<String> fromArrayGS = UnifiedSet.newSetWith(array); // using gs
System.out.println(fromArray);
System.out.println(fromArrayJDK);
System.out.println(fromArrayGS);

System.out.println("createHashSet end");

3 Создать карту

Описание JDK гуайява GS-коллекции

Создать
new
пустую HashMap<>()
Maps.newHashMap() UnifiedMap.newMap()

карту

Создать
карту с new
Maps.newHashMapWithExpectedSize(100) UnifiedMap.newMap(130)
HashMap<>(130)
емкостью
= 130

Создать
карту с new
Maps.newHashMap(map) UnifiedMap.newMap(map)
HashMap<>(map)
другой
карты

Создать
UnifiedMap.newWithKeysValues("1",
карту из - - "a", "2", "b")
ключей

Примеры:

System.out.println("createHashMap start");
// Create empty map
Map<String, String> emptyGuava = Maps.newHashMap(); // using guava
Map<String, String> emptyJDK = new HashMap<>(); // using JDK
Map<String, String> emptyGS = UnifiedMap.newMap(); // using gs

// Create map with about 100 element

https://riptutorial.com/ru/home 243
Map<String, String> approx100 = Maps.newHashMapWithExpectedSize(100); // using guava
Map<String, String> approx100JDK = new HashMap<>(130); // using JDK
Map<String, String> approx100GS = UnifiedMap.newMap(130); // using gs

// Create map from another map


Map<String, String> map = new HashMap<>(3);
map.put("k1","v1");
map.put("k2","v2");
Map<String, String> withMap = Maps.newHashMap(map); // using guava
Map<String, String> withMapJDK = new HashMap<>(map); // using JDK
Map<String, String> withMapGS = UnifiedMap.newMap(map); // using gs

System.out.println(withMap);
System.out.println(withMapJDK);
System.out.println(withMapGS);

// Create map from keys


Map<String, String> withKeys = UnifiedMap.newWithKeysValues("1", "a", "2", "b");
System.out.println(withKeys);

System.out.println("createHashMap end");

Дополнительные примеры: CreateCollectionTest

1. CollectionCompare
2. CollectionSearch
3. JavaTransform

Прочитайте Альтернативные коллекции онлайн: https://riptutorial.com/ru/java/topic/2958/


альтернативные-коллекции

https://riptutorial.com/ru/home 244
глава 46: Анализ XML с использованием
API JAXP
замечания
XML Parsing - это интерпретация XML-документов, чтобы манипулировать их контентом с
помощью разумных конструкций, будь то «узлы», «атрибуты», «документы», «пространства
имен» или события, связанные с этими конструкциями.

Java имеет собственный API для обработки документов XML, называемый JAXP или Java
API для обработки XML . JAXP и эталонная реализация были включены в каждую версию
Java после Java 1.4 (JAXP v1.1) и с тех пор развиваются. Java 8 поставляется с JAXP
версии 1.6.

API предоставляет различные способы взаимодействия с XML-документами, которые:

• Интерфейс DOM (Document Object Model)


• Интерфейс SAX (простой API для XML)
• Интерфейс StAX (Streaming API для XML)

Принципы интерфейса DOM


Интерфейс DOM предназначен для предоставления W3C DOM- совместимого способа
интерпретации XML. Различные версии JAXP поддерживают различные спецификации
DOM (до уровня 3).

В интерфейсе Document Object Model документ XML представлен как дерево, начиная с
«Элемента документа». Базовый типом API является Node типа, это позволяет
перемещаться от Node к его родителям, его детям, или его братьям (хотя, не все Node с
может иметь детей, например, Text узлы являются окончательными в дереве, и никогда не
имеют детей). Теги XML представлены как Element s, которые значительно расширяют Node с
помощью связанных с атрибутами методов.

Интерфейс DOM очень полезен, поскольку он позволяет «одну строку» анализировать


XML-документы как деревья и позволяет легко модифицировать построенное дерево
(добавление узла, подавление, копирование и т. Д.) И, наконец, его сериализацию
(обратно на диск ) после изменений. Это происходит по цене, однако: дерево находится в
памяти, поэтому деревья DOM не всегда практичны для огромных XML-документов. Кроме
того, построение дерева не всегда является самым быстрым способом работы с XML-
контентом, особенно если его не интересуют все части документа XML.

https://riptutorial.com/ru/home 245
Принципы интерфейса SAX
SAX API - это ориентированный на события API для работы с документами XML. В рамках
этой модели компоненты XML-документов интерпретируются как события (например,
«открыт тег», «тег закрыт», «встречен текстовый узел», «был встречен комментарий»). ..

API SAX использует подход «синтаксический разбор», где SAX Parser отвечает за
интерпретацию XML-документа и вызывает методы для делегата ( ContentHandler ) для
обработки любого события, которое встречается в документе XML. Обычно один никогда
не пишет парсер, но один обеспечивает обработчик для сбора всей необходимой
информации из XML-документа.

Интерфейс SAX преодолевает ограничения интерфейса DOM, сохраняя только


минимально необходимые данные на уровне анализатора (например, контексты
пространств имен, состояние проверки), поэтому только информация, ContentHandler для
которой вы, разработчик, несет ответственность, - это хранится в памяти. Компромисс
заключается в том, что при таком подходе нет возможности «вернуться во времени / XML-
документ»: в то время как DOM позволяет Node возвращаться к его родительскому объекту,
такой возможности нет в SAX.

Принципы интерфейса StAX


API StAX использует аналогичный подход для обработки XML как API SAX (т. Е.
Управляемый событиями), единственное очень существенное отличие состоит в том, что
StAX является синтаксическим анализатором (где SAX был парсером push). В SAX Parser
находится под контролем и использует обратные вызовы в ContentHandler . В Stax вы
вызываете парсер и управляете, когда / если вы хотите получить следующее «событие»
XML.

API начинается с XMLStreamReader (или XMLEventReader ), которые являются шлюзами,


через которые разработчик может спросить nextEvent() в стиле итератора.

Examples

Анализ и перемещение документа с использованием DOM API

Учитывая следующий документ:

<?xml version='1.0' encoding='UTF-8' ?>


<library>
<book id='1'>Effective Java</book>
<book id='2'>Java Concurrency In Practice</book>
</library>

https://riptutorial.com/ru/home 246
Для построения дерева DOM из String можно использовать следующий код:

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.StringReader;

public class DOMDemo {

public static void main(String[] args) throws Exception {


String xmlDocument = "<?xml version='1.0' encoding='UTF-8' ?>"
+ "<library>"
+ "<book id='1'>Effective Java</book>"
+ "<book id='2'>Java Concurrency In Practice</book>"
+ "</library>";

DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();


// This is useless here, because the XML does not have namespaces, but this option is
usefull to know in cas
documentBuilderFactory.setNamespaceAware(true);
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
// There are various options here, to read from an InputStream, from a file, ...
Document document = documentBuilder.parse(new InputSource(new StringReader(xmlDocument)));

// Root of the document


System.out.println("Root of the XML Document: " +
document.getDocumentElement().getLocalName());

// Iterate the contents


NodeList firstLevelChildren = document.getDocumentElement().getChildNodes();
for (int i = 0; i < firstLevelChildren.getLength(); i++) {
Node item = firstLevelChildren.item(i);
System.out.println("First level child found, XML tag name is: " +
item.getLocalName());
System.out.println("\tid attribute of this tag is : " +
item.getAttributes().getNamedItem("id").getTextContent());
}

// Another way would have been


NodeList allBooks = document.getDocumentElement().getElementsByTagName("book");
}
}

Код дает следующее:

Root of the XML Document: library


First level child found, XML tag name is: book
id attribute of this tag is : 1
First level child found, XML tag name is: book
id attribute of this tag is : 2

Разбор документа с использованием API StAX

https://riptutorial.com/ru/home 247
Учитывая следующий документ:

<?xml version='1.0' encoding='UTF-8' ?>


<library>
<book id='1'>Effective Java</book>
<book id='2'>Java Concurrency In Practice</book>
<notABook id='3'>This is not a book element</notABook>
</library>

Можно использовать следующий код для его анализа и построения карты названий книг
по идентификатору книги.

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamReader;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;

public class StaxDemo {

public static void main(String[] args) throws Exception {


String xmlDocument = "<?xml version='1.0' encoding='UTF-8' ?>"
+ "<library>"
+ "<book id='1'>Effective Java</book>"
+ "<book id='2'>Java Concurrency In Practice</book>"
+ "<notABook id='3'>This is not a book element </notABook>"
+ "</library>";

XMLInputFactory xmlInputFactory = XMLInputFactory.newFactory();


// Various flavors are possible, e.g. from an InputStream, a Source, ...
XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(new
StringReader(xmlDocument));

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

// We go through each event using a loop


while (xmlStreamReader.hasNext()) {
switch (xmlStreamReader.getEventType()) {
case XMLStreamConstants.START_ELEMENT:
System.out.println("Found start of element: " +
xmlStreamReader.getLocalName());
// Check if we are at the start of a <book> element
if ("book".equals(xmlStreamReader.getLocalName())) {
int bookId = Integer.parseInt(xmlStreamReader.getAttributeValue("",
"id"));
String bookTitle = xmlStreamReader.getElementText();
bookTitlesById.put(bookId, bookTitle);
}
break;
// A bunch of other things are possible : comments, processing instructions,
Whitespace...
default:
break;
}
xmlStreamReader.next();
}

System.out.println(bookTitlesById);

https://riptutorial.com/ru/home 248
}

Эти результаты:

Found start of element: library


Found start of element: book
Found start of element: book
Found start of element: notABook
{1=Effective Java, 2=Java Concurrency In Practice}

В этом примере нужно позаботиться о нескольких вещах:

1. Использование xmlStreamReader.getAttributeValue работает, потому что мы сначала


отметили, что парсер находится в состоянии START_ELEMENT . В других состояниях
(кроме ATTRIBUTES ) парсеру поручено IllegalStateException , поскольку атрибуты могут
появляться только в начале элементов.

2. xmlStreamReader.getTextContent() же самое касается xmlStreamReader.getTextContent() , он


работает, потому что мы находимся в START_ELEMENT и мы знаем в этом документе, что
элемент <book> не имеет дочерних узлов, не содержащих текст.

Для более сложных анализов документов (более глубокие, вложенные элементы, ...),
хорошая практика «делегировать» парсер под-методам или другим объектам, например,
иметь класс или метод BookParser и иметь дело с каждым элементом от START_ELEMENT
до END_ELEMENT книги XML-тега.

Можно также использовать объект Stack для хранения важных данных вверх и вниз по
дереву.

Прочитайте Анализ XML с использованием API JAXP онлайн:


https://riptutorial.com/ru/java/topic/3943/анализ-xml-с-использованием-api-jaxp

https://riptutorial.com/ru/home 249
глава 47: Аннотации
Вступление
В Java аннотация - это форма синтаксических метаданных, которые могут быть добавлены
в исходный код Java. Он предоставляет данные о программе, которая не является частью
самой программы. Аннотации не оказывают прямого влияния на работу кода, который они
комментируют. Классы, методы, переменные, параметры и пакеты могут быть
аннотированы.

Синтаксис
• @AnnotationName // «Аннотирование маркера» (без параметров)
• @AnnotationName (someValue) // устанавливает параметр с именем 'value'
• @AnnotationName (param1 = value1) // named parameter
• @AnnotationName (param1 = value1, param2 = value2) // несколько именованных
параметров
• @AnnotationName (param1 = {1, 2, 3}) // параметр имени array
• @AnnotationName ({value1}) // массив с одним элементом в качестве параметра с
именем 'value'

замечания

Типы параметров
Для параметров могут использоваться только постоянные выражения следующих типов, а
также массивы этих типов:

• String
• Class

• примитивные типы
• Типы перечислений
• Типы аннотаций

Examples

Встроенные аннотации

Стандартная версия Java содержит предопределенные аннотации. Вам не нужно


определять их самостоятельно, и вы можете использовать их немедленно. Они позволяют

https://riptutorial.com/ru/home 250
компилятору разрешить некоторую фундаментальную проверку методов, классов и кода.

@Override

Эта аннотация относится к методу и говорит, что этот метод должен переопределять
метод суперкласса или реализовать определение метода абстрактного суперкласса. Если
эта аннотация используется с любым другим способом, компилятор выдает ошибку.

Бетонный суперкласс

public class Vehicle {


public void drive() {
System.out.println("I am driving");
}
}

class Car extends Vehicle {


// Fine
@Override
public void drive() {
System.out.prinln("Brrrm, brrm");
}
}

Абстрактный класс

abstract class Animal {


public abstract void makeNoise();
}

class Dog extends Animal {


// Fine
@Override
public void makeNoise() {
System.out.prinln("Woof");
}
}

Не работает

class Logger1 {
public void log(String logString) {
System.out.prinln(logString);
}
}

class Logger2 {
// This will throw compile-time error. Logger2 is not a subclass of Logger1.
// log method is not overriding anything
@Override
public void log(String logString) {
System.out.println("Log 2" + logString);
}
}

https://riptutorial.com/ru/home 251
Основная цель - уловить туманность, где вы думаете, что вы переопределяете метод, но на
самом деле определяете новый.

class Vehicle {
public void drive() {
System.out.println("I am driving");
}
}

class Car extends Vehicle {


// Compiler error. "dirve" is not the correct method name to override.
@Override
public void dirve() {
System.out.prinln("Brrrm, brrm");
}
}

Обратите внимание, что значение @Override со временем изменилось:

• В Java 5 это означало, что аннотированный метод должен был переопределить не


абстрактный метод, объявленный в цепочке суперкласса.
• Начиная с Java 6, он также выполняется, если аннотированный метод реализует
абстрактный метод, объявленный в иерархии классов суперклассов / интерфейсов.

(Иногда это может вызвать проблемы при обратном переносе кода на Java 5.)

@Deprecated

Это означает, что метод устарел. Это может быть несколько причин:

• API является ошибочным и нецелесообразно исправлять,

• использование API, вероятно, приведет к ошибкам,

• API был заменен другим API,

• API устарел,

• API является экспериментальным и подлежит несовместимым изменениям,

• или любую комбинацию вышеуказанного.

Конкретную причину устаревания обычно можно найти в документации API.

Аннотации заставят компилятор испускать ошибку, если вы ее используете. IDE также


могут выделить этот метод как-то как устаревший

class ComplexAlgorithm {
@Deprecated
public void oldSlowUnthreadSafeMethod() {
// stuff here

https://riptutorial.com/ru/home 252
}

public void quickThreadSafeMethod() {


// client code should use this instead
}
}

@SuppressWarnings

Почти во всех случаях, когда компилятор выдает предупреждение, наиболее подходящим


действием является устранение причины. В некоторых случаях (например, код Generics,
использующий, например, нестандартный код для предварительного генерирования) это
может быть невозможно, и лучше запретить эти предупреждения, которые вы ожидаете и
не можете исправить, чтобы вы могли более четко видеть неожиданные предупреждения.

Эта аннотация может применяться ко всему классу, методу или строке. В качестве
параметра используется категория предупреждения.

@SuppressWarnings("deprecation")
public class RiddledWithWarnings {
// several methods calling deprecated code here
}

@SuppressWarning("finally")
public boolean checkData() {
// method calling return from within finally block
}

Лучше максимально ограничить объем аннотации, чтобы предотвратить непредвиденные


предупреждения. Например, ограничение объема аннотации на одну строку:

ComplexAlgorithm algorithm = new ComplexAlgorithm();


@SuppressWarnings("deprecation") algoritm.slowUnthreadSafeMethod();
// we marked this method deprecated in an example above

@SuppressWarnings("unsafe") List<Integer> list = getUntypeSafeList();


// old library returns, non-generic List containing only integers

Предупреждения, поддерживаемые этой аннотацией, могут отличаться от компилятора к


компилятору. Только unchecked и deprecation предупреждения упомянуты в JLS.
Непризнанные типы предупреждений будут игнорироваться.

@SafeVarargs

Из-за стирания типа void method(T... t) будет преобразован в void method(Object[] t) что
означает, что компилятор не всегда может проверить, что использование varargs является
безопасным по типу. Например:

private static <T> void generatesVarargsWarning(T... lists) {

https://riptutorial.com/ru/home 253
Существуют случаи, когда использование безопасно, и в этом случае вы можете
аннотировать метод с SafeVarargs аннотации SafeVarargs для подавления предупреждения.
Это явно скрывает предупреждение, если ваше использование также небезопасно.

@FunctionalInterface

Это необязательная аннотация, используемая для обозначения FunctionalInterface. Это


заставит компилятор жаловаться, если он не соответствует спецификации
FunctionalInterface (имеет один абстрактный метод)

@FunctionalInterface
public interface ITrade {
public boolean check(Trade t);
}

@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}

Проверка аннотации выполнения через отражение

API Reflection Java позволяет программисту выполнять различные проверки и операции над
полями, методами и аннотациями классов во время выполнения. Однако для того, чтобы
аннотация была видимой во время выполнения, RetentionPolicy необходимо изменить на
RUNTIME , как показано в следующем примере:

@interface MyDefaultAnnotation {

@Retention(RetentionPolicy.RUNTIME)
@interface MyRuntimeVisibleAnnotation {

public class AnnotationAtRuntimeTest {

@MyDefaultAnnotation
static class RuntimeCheck1 {
}

@MyRuntimeVisibleAnnotation
static class RuntimeCheck2 {
}

public static void main(String[] args) {


Annotation[] annotationsByType = RuntimeCheck1.class.getAnnotations();
Annotation[] annotationsByType2 = RuntimeCheck2.class.getAnnotations();

System.out.println("default retention: " + Arrays.toString(annotationsByType));


System.out.println("runtime retention: " + Arrays.toString(annotationsByType2));
}
}

https://riptutorial.com/ru/home 254
Определение типов аннотаций

Типы аннотаций определяются с помощью @interface . Параметры определяются


аналогично методам регулярного интерфейса.

@interface MyAnnotation {
String param1();
boolean param2();
int[] param3(); // array parameter
}

Значения по умолчанию

@interface MyAnnotation {
String param1() default "someValue";
boolean param2() default true;
int[] param3() default {};
}

Мета-аннотаций
Мета-аннотации - это аннотации, которые могут применяться к типам аннотаций.
Специальная предопределенная мета-аннотация определяет, как можно использовать
типы аннотаций.

@Target
Мета-аннотация @Target ограничивает типы, к которым может применяться аннотация.

@Target(ElementType.METHOD)
@interface MyAnnotation {
// this annotation can only be applied to methods
}

Несколько значений могут быть добавлены с использованием нотации массива, например


@Target({ElementType.FIELD, ElementType.TYPE})

Доступные значения

пример использования целевого


ElementType цель
элемента

@Retention(RetentionPolicy.RUNTIME)
ANNOTATION_TYPE типы аннотаций @interface MyAnnotation

https://riptutorial.com/ru/home 255
пример использования целевого
ElementType цель
элемента

@MyAnnotation
КОНСТРУКТОР конструкторы public MyClass() {}

поля, константы @XmlAttribute


Область private int count;
перечисления

for (@LoopVariable int i = 0; i < 100;


объявления i++) {
LOCAL_VARIABLE переменных внутри @Unused
String resultVariable;
методов }

пакет (в package- @Deprecated


ПАКЕТ package very.old;
info.java )

@XmlElement
МЕТОД методы public int getCount() {...}

public Rectangle(
@NamedArg("width") double
width,
параметры метода /
ПАРАМЕТР @NamedArg("height") double
конструктора height) {
...
}

классы, интерфейсы, @XmlRootElement


ТИП public class Report {}
перечисления

Java SE 8

пример использования целевого


ElementType цель
элемента

Объявление параметров public <@MyAnnotation T> void f(T t)


TYPE_PARAMETER {}
типа

https://riptutorial.com/ru/home 256
пример использования целевого
ElementType цель
элемента

Object o = "42";
TYPE_USE Использование типа String s = (@MyAnnotation String) o;

@Retention
Мета-аннотация @Retention определяет видимость аннотации во время процесса или
выполнения компиляции приложений. По умолчанию аннотации включены в .class файлы,
но не отображаются во время выполнения. Чтобы сделать аннотацию доступной во время
выполнения, в этой аннотации необходимо установить RetentionPolicy.RUNTIME .

@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
// this annotation can be accessed with reflections at runtime
}

Доступные значения

Политика
эффект
удержания

УЧЕБНЫЙ
Аннотации доступны в файле .class , но не во время выполнения
КЛАСС

Аннотации доступны во время выполнения и могут быть доступны


RUNTIME
посредством отражения

Аннотации доступны во время компиляции, но не добавляются в


ИСТОЧНИК .class . Аннотацию можно использовать, например, обработчиком
аннотации.

@Documented
Мета-аннотация @Documented используется для обозначения аннотаций, использование
которых должно быть документировано генераторами документации API, такими как
javadoc . Он не имеет значений. С помощью @Documented все классы, использующие
аннотацию, будут перечислены на их сгенерированной странице документации. Без
@Documented невозможно увидеть, какие классы используют аннотацию в документации.

@Inherited

https://riptutorial.com/ru/home 257
метаинформация @Inherited имеет отношение к аннотациям, которые
@Inherited
применяются к классам. Он не имеет значений. Пометка аннотации как @Inherited изменяет
способ обработки аннотаций.

• Для не унаследованной аннотации запрос рассматривает только исследуемый класс.


• Для унаследованной аннотации запрос также проверяет цепочку суперкласса
(рекурсивно) до тех пор, пока не будет найден экземпляр аннотации.

Обратите внимание, что запрашиваются только суперклассы: любые аннотации,


привязанные к интерфейсам в иерархии классов, будут игнорироваться.

@Repeatable
мета-аннотация @Repeatable в Java 8. Она указывает, что к @Repeatable аннотации
@Repeatable
можно добавить несколько экземпляров аннотации. Эта мета-аннотация не имеет
значений.

Получение значений аннотации во время выполнения

Вы можете получить текущие свойства аннотации, используя Reflection, чтобы получить


метод или поле или класс, к которым применена аннотация, и затем выбор желаемых
свойств.

@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
String key() default "foo";
String value() default "bar";
}

class AnnotationExample {
// Put the Annotation on the method, but leave the defaults
@MyAnnotation
public void testDefaults() throws Exception {
// Using reflection, get the public method "testDefaults", which is this method with
no args
Method method = AnnotationExample.class.getMethod("testDefaults", null);

// Fetch the Annotation that is of type MyAnnotation from the Method


MyAnnotation annotation = (MyAnnotation)method.getAnnotation(MyAnnotation.class);

// Print out the settings of the Annotation


print(annotation);
}

//Put the Annotation on the method, but override the settings


@MyAnnotation(key="baz", value="buzz")
public void testValues() throws Exception {
// Using reflection, get the public method "testValues", which is this method with no
args
Method method = AnnotationExample.class.getMethod("testValues", null);

https://riptutorial.com/ru/home 258
// Fetch the Annotation that is of type MyAnnotation from the Method
MyAnnotation annotation = (MyAnnotation)method.getAnnotation(MyAnnotation.class);

// Print out the settings of the Annotation


print(annotation);
}

public void print(MyAnnotation annotation) {


// Fetch the MyAnnotation 'key' & 'value' properties, and print them out
System.out.println(annotation.key() + " = " + annotation.value());
}

public static void main(String[] args) {


AnnotationExample example = new AnnotationExample();
try {
example.testDefaults();
example.testValues();
} catch( Exception e ) {
// Shouldn't throw any Exceptions
System.err.println("Exception [" + e.getClass().getName() + "] - " +
e.getMessage());
e.printStackTrace(System.err);
}
}
}

Выход будет

foo = bar
baz = buzz

Повторяющиеся аннотации

До Java 8 два экземпляра одной аннотации не могли быть применены к одному элементу.
Стандартное обходное решение заключалось в использовании аннотации контейнера,
содержащей массив некоторой другой аннотации:

// Author.java
@Retention(RetentionPolicy.RUNTIME)
public @interface Author {
String value();
}

// Authors.java
@Retention(RetentionPolicy.RUNTIME)
public @interface Authors {
Author[] value();
}

// Test.java
@Authors({
@Author("Mary"),
@Author("Sam")
})
public class Test {
public static void main(String[] args) {

https://riptutorial.com/ru/home 259
Author[] authors = Test.class.getAnnotation(Authors.class).value();
for (Author author : authors) {
System.out.println(author.value());
// Output:
// Mary
// Sam
}
}
}

Java SE 8

Java 8 обеспечивает более чистый, более прозрачный способ использования аннотаций


контейнеров, используя аннотацию @Repeatable . Сначала добавим это в класс Author :

@Repeatable(Authors.class)

Это говорит Java обрабатывать несколько аннотаций @Author как если бы они были
окружены контейнером @Authors . Мы также можем использовать
Class.getAnnotationsByType() для доступа к массиву @Author своим собственным классом, а не
через его контейнер:

@Author("Mary")
@Author("Sam")
public class Test {
public static void main(String[] args) {
Author[] authors = Test.class.getAnnotationsByType(Author.class);
for (Author author : authors) {
System.out.println(author.value());
// Output:
// Mary
// Sam
}
}
}

Унаследованные аннотации

По умолчанию аннотации классов не применяются к типам, расширяющим их. Это можно


изменить, добавив аннотацию @Inherited в определение аннотации

пример
Рассмотрим следующие 2 аннотации:

@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface InheritedAnnotationType {
}

https://riptutorial.com/ru/home 260
а также

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface UninheritedAnnotationType {
}

Если три класса аннотируются следующим образом:

@UninheritedAnnotationType
class A {
}

@InheritedAnnotationType
class B extends A {
}

class C extends B {
}

запуск этого кода

System.out.println(new A().getClass().getAnnotation(InheritedAnnotationType.class));
System.out.println(new B().getClass().getAnnotation(InheritedAnnotationType.class));
System.out.println(new C().getClass().getAnnotation(InheritedAnnotationType.class));
System.out.println("_________________________________");
System.out.println(new A().getClass().getAnnotation(UninheritedAnnotationType.class));
System.out.println(new B().getClass().getAnnotation(UninheritedAnnotationType.class));
System.out.println(new C().getClass().getAnnotation(UninheritedAnnotationType.class));

напечатает результат, подобный этому (в зависимости от пакетов аннотации):

null
@InheritedAnnotationType()
@InheritedAnnotationType()
_________________________________
@UninheritedAnnotationType()
null
null

Обратите внимание, что аннотации могут наследоваться только от классов, а не от


интерфейсов.

Обработка времени компиляции с использованием обработчика


аннотаций

В этом примере показано, как выполнить проверку времени компиляции аннотированного


элемента.

Аннотации
https://riptutorial.com/ru/home 261
@Setter- это маркер, который можно применить к методам. Аннотации будут отброшены во
время компиляции, которые впоследствии не будут доступны.

package annotation;

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

@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.METHOD)
public @interface Setter {
}

Обработчик аннотации
Класс SetterProcessor используется компилятором для обработки аннотаций. Он проверяет,
если методы аннотированные с @Setter аннотаций являются public , неправительственные
static методы с именем , начинающимся с set и имеющий заглавную букву как 4 буквы. Если
одно из этих условий не выполняется, в Messager записывается ошибка. Компилятор
записывает это в stderr, но другие инструменты могут использовать эту информацию по-
разному. Например, IDE NetBeans позволяет пользователю задавать обработчики
аннотаций, которые используются для отображения сообщений об ошибках в редакторе.

package annotation.processor;

import annotation.Setter;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;

@SupportedAnnotationTypes({"annotation.Setter"})
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class SetterProcessor extends AbstractProcessor {

private Messager messager;

@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv)
{
// get elements annotated with the @Setter annotation

https://riptutorial.com/ru/home 262
Set<? extends Element> annotatedElements =
roundEnv.getElementsAnnotatedWith(Setter.class);

for (Element element : annotatedElements) {


if (element.getKind() == ElementKind.METHOD) {
// only handle methods as targets
checkMethod((ExecutableElement) element);
}
}

// don't claim annotations to allow other processors to process them


return false;
}

private void checkMethod(ExecutableElement method) {


// check for valid name
String name = method.getSimpleName().toString();
if (!name.startsWith("set")) {
printError(method, "setter name must start with \"set\"");
} else if (name.length() == 3) {
printError(method, "the method name must contain more than just \"set\"");
} else if (Character.isLowerCase(name.charAt(3))) {
if (method.getParameters().size() != 1) {
printError(method, "character following \"set\" must be upper case");
}
}

// check, if setter is public


if (!method.getModifiers().contains(Modifier.PUBLIC)) {
printError(method, "setter must be public");
}

// check, if method is static


if (method.getModifiers().contains(Modifier.STATIC)) {
printError(method, "setter must not be static");
}
}

private void printError(Element element, String message) {


messager.printMessage(Diagnostic.Kind.ERROR, message, element);
}

@Override
public void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);

// get messager for printing errors


messager = processingEnvironment.getMessager();
}

упаковка
Для применения компилятором процессор обработки аннотаций должен быть доступен для
SPI (см. ServiceLoader ).

https://riptutorial.com/ru/home 263
Для этого нужно добавить текстовый файл META-
INF/services/javax.annotation.processing.Processor необходимо добавить в файл jar,
содержащий процессор аннотации, и аннотацию в дополнение к другим файлам. В файле
должно быть указано полное имя обработчика аннотаций, то есть оно должно выглядеть
так:

annotation.processor.SetterProcessor

Мы предположим, что файл jar называется AnnotationProcessor.jar ниже.

Пример аннотированного класса


Следующий класс является примером класса в пакете по умолчанию с аннотациями,
которые применяются к правильным элементам в соответствии с политикой хранения.
Однако только обработчик аннотации рассматривает второй метод как действительную
цель аннотации.

import annotation.Setter;

public class AnnotationProcessorTest {

@Setter
private void setValue(String value) {}

@Setter
public void setString(String value) {}

@Setter
public static void main(String[] args) {}

Использование обработчика аннотации с


javac
Если обработчик аннотации обнаружен с использованием SPI, он автоматически
используется для обработки аннотированных элементов. Например, компиляция класса
AnnotationProcessorTest с использованием

javac -cp AnnotationProcessor.jar AnnotationProcessorTest.java

дает следующий результат

AnnotationProcessorTest.java:6: error: setter must be public


private void setValue(String value) {}

https://riptutorial.com/ru/home 264
^
AnnotationProcessorTest.java:12: error: setter name must start with "set"
public static void main(String[] args) {}
^
2 errors

вместо компиляции в обычном режиме. Файл .class не создается.

Этого можно предотвратить, указав параметр -proc:none для javac . Вы также можете
отказаться от обычной компиляции, указав -proc:only вместо этого.

Интеграция IDE
Netbeans
Обработчики аннотаций могут использоваться в редакторе NetBeans. Для этого в
настройках проекта необходимо указать процессор аннотации:

1. перейдите в « Project Properties > « Build > « Compiling

2. добавить флажки для Enable Annotation Processing и Enable Annotation Processing in


Editor

3. нажмите « Add рядом с списком процессоров аннотаций

4. в появившемся всплывающем окне введите полное имя класса обработчика аннотации


и нажмите « Ok .

Результат

Идея аннотаций

https://riptutorial.com/ru/home 265
Спецификация языка Java описывает аннотации следующим образом:

Аннотирование - это маркер, который связывает информацию с конструкцией


программы, но не влияет на время выполнения.

Аннотации могут отображаться перед типами или объявлениями. Они могут появляться в
месте, где они могут применяться как к типу, так и к объявлению.
То, к чему относится аннотация, регулируется «мета-аннотацией» @Target .
Дополнительную информацию см. В разделе «Определение типов аннотаций» .

Аннотации используются для множества целей. Структуры, такие как Spring и Spring-MVC,
используют аннотации для определения того, где должны быть введены зависимости или
где должны быть маршрутизированы запросы.

Другие фреймворки используют аннотации для генерации кода. Ломбок и JPA - яркие
примеры, которые используют аннотации для генерации кода Java (и SQL).

Цель этой темы - предоставить полный обзор:

• Как определить свои собственные аннотации?

• Какие аннотации предоставляет Java-язык?

• Как используются аннотации на практике?

Аннотации для параметров «этого» и приемника

Когда впервые были введены аннотации Java, не было никаких условий для аннотирования
цели метода экземпляра или параметра скрытого конструктора для конструктора
внутренних классов. Это было исправлено на Java 8 с добавлением объявлений
параметров приемника ; см. JLS 8.4.1 .

Параметр получателя является необязательным синтаксическим устройством


для метода экземпляра или конструктора внутреннего класса. Для метода
экземпляра параметр приемника представляет объект, для которого вызывается
метод. Для конструктора внутреннего класса параметр-приемник представляет
собой немедленно включающий экземпляр вновь созданного объекта. В любом
случае параметр приемника существует только для того, чтобы разрешить тип
отображаемого объекта в исходном коде, чтобы тип мог быть аннотирован.
Параметр приемника не является формальным параметром; точнее, это не
объявление какой-либо переменной (§4.12.3), оно никогда не связано ни с каким
значением, переданным в качестве аргумента в выражении вызова метода или в
выражении для создания экземпляра класса, и оно не оказывает никакого
влияния на время выполнения.

Следующий пример иллюстрирует синтаксис для обоих типов параметров приемника:

https://riptutorial.com/ru/home 266
public class Outer {
public class Inner {
public Inner (Outer this) {
// ...
}
public void doIt(Inner this) {
// ...
}
}
}

Единственная цель параметров приемника - дать вам возможность добавлять аннотации.


Например, у вас может быть пользовательская аннотация @IsOpen , целью которой является
утверждение, что объект Closeable не был закрыт при вызове метода. Например:

public class MyResource extends Closeable {


public void update(@IsOpen MyResource this, int value) {
// ...
}

public void close() {


// ...
}
}

На одном уровне аннотация @IsOpen на this может просто служить документацией. Однако
мы могли бы сделать больше. Например:

• Обработчик аннотации может вставить проверку времени выполнения, что this не в


закрытом состоянии при вызове update .
• Средство проверки кода может выполнять статический анализ кода, чтобы найти
случаи, когда this может быть закрыто при вызове update .

Добавить несколько значений аннотации

Параметр Annotation может принимать несколько значений, если он определен как массив.
Например, стандартная аннотация @SuppressWarnings определяется следующим образом:

public @interface SuppressWarnings {


String[] value();
}

Параметр value представляет собой массив строк. Вы можете установить несколько


значений, используя нотацию, похожую на инициализаторы массива:

@SuppressWarnings({"unused"})
@SuppressWarnings({"unused", "javadoc"})

Если вам нужно только установить одно значение, скобки можно опустить:

https://riptutorial.com/ru/home 267
@SuppressWarnings("unused")

Прочитайте Аннотации онлайн: https://riptutorial.com/ru/java/topic/157/аннотации

https://riptutorial.com/ru/home 268
глава 48: Апплеты
Вступление
Апплеты были частью Java с момента его официального выпуска и были использованы для
обучения Java и программирования в течение ряда лет.

В последние годы наблюдается активный толчок к удалению от апплетов и других


плагинов браузеров, причем некоторые браузеры блокируют их или активно не
поддерживают их.

В 2016 году Oracle объявила о своих планах отказаться от плагина, перейдя в плагиновую
сеть

Теперь доступны новые и лучшие API-интерфейсы

замечания
Апплет - это приложение Java, которое обычно запускается внутри веб-браузера.
Основная идея заключается в том, чтобы взаимодействовать с пользователем без
необходимости взаимодействия с сервером и передачи информации. Эта концепция была
очень успешной в 2000 году, когда интернет-общение было медленным и дорогостоящим.

Апплет предлагает пять методов контроля жизненного цикла.

имя
описание
метода

init() вызывается один раз при загрузке апплета

destroy() вызывается один раз, когда апплет удаляется из памяти

start() вызывается всякий раз, когда апплет становится видимым

stop() вызывается всякий раз, когда апплет накладывается другими окнами

paint() вызывается при необходимости или вручную запускается вызовом


repaint()

Examples

Минимальный апплет

https://riptutorial.com/ru/home 269
Очень простой апплет рисует прямоугольник и печатает строку на экране.

public class MyApplet extends JApplet{

private String str = "StackOverflow";

@Override
public void init() {
setBackground(Color.gray);
}
@Override
public void destroy() {}
@Override
public void start() {}
@Override
public void stop() {}
@Override
public void paint(Graphics g) {
g.setColor(Color.yellow);
g.fillRect(1,1,300,150);
g.setColor(Color.red);
g.setFont(new Font("TimesRoman", Font.PLAIN, 48));
g.drawString(str, 10, 80);
}
}

Основной класс апплета простирается от javax.swing.JApplet .

Java SE 1.2

До появления Java 1.2 и внедрения апплетов swing API были расширены из


java.applet.Applet .

Апплеты не требуют основного метода. Точка входа контролируется жизненным циклом.


Чтобы использовать их, они должны быть встроены в HTML-документ. Это также точка, в
которой определяется их размер.

<html>
<head></head>
<body>
<applet code="MyApplet.class" width="400" height="200"></applet>
</body>
</html>

Создание графического интерфейса

Апплеры могут быть легко использованы для создания графического интерфейса. Они
действуют как Container и имеют метод add() который принимает любой компонент awt или
swing .

public class MyGUIApplet extends JApplet{

private JPanel panel;

https://riptutorial.com/ru/home 270
private JButton button;
private JComboBox<String> cmbBox;
private JTextField textField;

@Override
public void init(){
panel = new JPanel();
button = new JButton("ClickMe!");
button.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent ae) {
if(((String)cmbBox.getSelectedItem()).equals("greet")) {
JOptionPane.showMessageDialog(null,"Hello " + textField.getText());
} else {
JOptionPane.showMessageDialog(null,textField.getText() + " stinks!");
}
}
});
cmbBox = new JComboBox<>(new String[]{"greet", "offend"});
textField = new JTextField("John Doe");
panel.add(cmbBox);
panel.add(textField);
panel.add(button);
add(panel);
}
}

Открытые ссылки из апплета

Вы можете использовать метод getAppletContext() чтобы получить объект AppletContext


который позволяет запросить браузер, чтобы открыть ссылку. Для этого вы используете
метод showDocument() . Второй параметр указывает браузеру использовать новое окно _blank
или тот, который показывает апплет _self .

public class MyLinkApplet extends JApplet{


@Override
public void init(){
JButton button = new JButton("ClickMe!");
button.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent ae) {
AppletContext a = getAppletContext();
try {
URL url = new URL("http://stackoverflow.com/");
a.showDocument(url,"_blank");
} catch (Exception e) { /* omitted for brevity */ }
}
});
add(button);
}
}

Загрузка изображений, аудио и других ресурсов

Java-апплеты могут загружать разные ресурсы. Но поскольку они работают в веб-браузере

https://riptutorial.com/ru/home 271
клиента, вам необходимо убедиться, что эти ресурсы доступны. Апплеты не могут
обращаться к клиентским ресурсам как к локальной файловой системе.

Если вы хотите загружать ресурсы с одного и того же URL-адреса, Applet хранится, вы


можете использовать метод getCodeBase() для извлечения базового URL-адреса. Для
загрузки ресурсов апплеты предлагают методы getImage() и getAudioClip() для загрузки
изображений или аудиофайлов.

Загрузите и покажите изображение

public class MyImgApplet extends JApplet{

private Image img;

@Override
public void init(){
try {
img = getImage(new URL("http://cdn.sstatic.net/stackexchange/img/logos/so/so-
logo.png"));
} catch (MalformedURLException e) { /* omitted for brevity */ }
}
@Override
public void paint(Graphics g) {
g.drawImage(img, 0, 0, this);
}
}

Загрузка и воспроизведение аудиофайла

public class MyAudioApplet extends JApplet{

private AudioClip audioClip;

@Override
public void init(){
try {
audioClip = getAudioClip(new URL("URL/TO/AN/AUDIO/FILE.WAV"));
} catch (MalformedURLException e) { /* omitted for brevity */ }
}
@Override
public void start() {
audioClip.play();
}
@Override
public void stop(){
audioClip.stop();
}
}

https://riptutorial.com/ru/home 272
Загрузка и отображение текстового файла

public class MyTextApplet extends JApplet{


@Override
public void init(){
JTextArea textArea = new JTextArea();
JScrollPane sp = new JScrollPane(textArea);
add(sp);
// load text
try {
URL url = new URL("http://www.textfiles.com/fun/quotes.txt");
InputStream in = url.openStream();
BufferedReader bf = new BufferedReader(new InputStreamReader(in));
String line = "";
while((line = bf.readLine()) != null) {
textArea.append(line + "\n");
}
} catch(Exception e) { /* omitted for brevity */ }
}
}

Прочитайте Апплеты онлайн: https://riptutorial.com/ru/java/topic/5503/апплеты

https://riptutorial.com/ru/home 273
глава 49: Атомные типы
Вступление
Java Atomic Types - это простые переменные типы, которые обеспечивают основные
операции, которые являются потокобезопасными и атомными, не прибегая к блокировке.
Они предназначены для использования в тех случаях, когда блокировка является узким
местом параллелизма или существует риск взаимоблокировки или оживления.

параметры

параметр Описание

задавать Неустойчивый набор полей

получить Неустойчивое чтение поля

lazySet Это упорядоченная операция в полевых условиях

Если значение представляет собой значение expeed, оно


compareAndSet
отправляется на новое значение

getAndSet получить текущее значение и обновить

замечания
Многие из них по существу сочетают волатильные чтения или записи и операции CAS .
Лучший способ понять это - посмотреть исходный код напрямую. Например, AtomicInteger ,
Unsafe.getAndSet

Examples

Создание атомных типов

Для простого многопоточного кода приемлема синхронизация . Однако использование


синхронизации имеет сильное влияние, и по мере того, как кодовая база становится более
сложной, вероятность возрастает, и в конечном итоге вы столкнетесь с Deadlock ,
Starvation или Livelock .

В случаях более сложного параллелизма использование Atomic Variables часто является


лучшей альтернативой, так как позволяет доступ к отдельной переменной поточно-

https://riptutorial.com/ru/home 274
безопасным образом без накладных расходов на использование синхронизированных
методов или кодовых блоков.

Создание типа AtomicInteger :

AtomicInteger aInt = new AtomicInteger() // Create with default value 0

AtomicInteger aInt = new AtomicInteger(1) // Create with initial value 1

Аналогично для других типов экземпляров.

AtomicIntegerArray aIntArray = new AtomicIntegerArray(10) // Create array of specific length


AtomicIntegerArray aIntArray = new AtomicIntegerArray(new int[] {1, 2, 3}) // Initialize array
with another array

Аналогично для других типов атомов.

Есть заметное исключение, что нет типов float и double . Их можно моделировать с
помощью Float.floatToIntBits(float) и Float.intBitsToFloat(int) для float а также
Double.doubleToLongBits(double) и Double.longBitsToDouble(long) для удвоений.

Если вы хотите использовать sun.misc.Unsafe вы можете использовать любую примитивную


переменную в качестве атома, используя атомную операцию в sun.misc.Unsafe . Все
примитивные типы должны быть преобразованы или закодированы в int или longs, чтобы
таким образом использовать его. Подробнее об этом см .: sun.misc.Unsafe .

Мотивация для атомных типов

Простым способом реализации многопоточных приложений является использование


встроенных синхронизирующих и блокирующих примитивов Java; например synchronized
ключевое слово. В следующем примере показано, как мы можем использовать synchronized
для накопления счетчиков.

public class Counters {


private final int[] counters;

public Counters(int nosCounters) {


counters = new int[nosCounters];
}

/**
* Increments the integer at the given index
*/
public synchronized void count(int number) {
if (number >= 0 && number < counters.length) {
counters[number]++;
}
}

/**
* Obtains the current count of the number at the given index,

https://riptutorial.com/ru/home 275
* or if there is no number at that index, returns 0.
*/
public synchronized int getCount(int number) {
return (number >= 0 && number < counters.length) ? counters[number] : 0;
}
}

Эта реализация будет работать правильно. Однако, если у вас есть большое количество
потоков, делающих много одновременных вызовов на одном и том же объекте Counters ,
синхронизация может быть узким местом. В частности:

1. Каждый вызов synchronized метода начинается с текущего потока, который получает


блокировку для экземпляра Counters .
2. Поток будет удерживать блокировку, пока он проверяет значение number и обновляет
счетчик.
3. Наконец, он освободит блокировку, позволяя другим потокам получить доступ.

Если один поток пытается захватить блокировку, а другой удерживает ее, то попытка
попытки будет заблокирована (остановлена) на шаге 1 до тех пор, пока блокировка не
будет отпущена. Если несколько потоков ждут, один из них получит его, а остальные будут
заблокированы.

Это может привести к возникновению нескольких проблем:

• Если для блокировки много споров (т. Е. Много потоков пытаются ее приобрести), то
некоторые потоки могут быть заблокированы в течение длительного времени.

• Когда поток блокируется в ожидании блокировки, операционная система, как


правило, пытается переключиться на другой поток. Такое переключение контекста
оказывает относительно большое влияние на производительность процессора.

• Когда есть несколько потоков, заблокированных на одном замке, нет никаких


гарантий, что любой из них будет обрабатываться «честно» (т. Е. Каждый поток, как
гарантируется, планируется запустить). Это может привести к голоданию нитей .

Как реализовать Atomic Types?


Начнем с перезаписи приведенного выше примера с AtomicInteger счетчиков AtomicInteger :

public class Counters {


private final AtomicInteger[] counters;

public Counters(int nosCounters) {


counters = new AtomicInteger[nosCounters];
for (int i = 0; i < nosCounters; i++) {
counters[i] = new AtomicInteger();
}
}

https://riptutorial.com/ru/home 276
/**
* Increments the integer at the given index
*/
public void count(int number) {
if (number >= 0 && number < counters.length) {
counters[number].incrementAndGet();
}
}

/**
* Obtains the current count of the object at the given index,
* or if there is no number at that index, returns 0.
*/
public int getCount(int number) {
return (number >= 0 && number < counters.length) ?
counters[number].get() : 0;
}
}

Мы заменили int[] на AtomicInteger[] и инициализировали его экземпляром в каждом


элементе. Мы также добавили вызовы incrementAndGet() и get() вместо операций над
значениями int .

Но самое главное, что мы можем удалить synchronized ключевое слово, потому что
блокировка больше не требуется. Это работает, потому что операции incrementAndGet() и
get() являются атомарными и потокобезопасными . В этом контексте это означает, что:

• Каждый счетчик в массиве будет наблюдаться только в состоянии «перед» для


операции (например, «приращение») или в состоянии «после».

• Предполагая, что операция происходит в момент времени T , нить не сможет увидеть


состояние «раньше» после времени T

Кроме того, хотя два потока могут фактически попытаться обновить один и тот же
экземпляр AtomicInteger одновременно, реализации операций гарантируют, что только одно
приращение происходит одновременно на данном экземпляре. Это делается без
блокировки, что часто приводит к повышению производительности.

Как работают Atomic Types?


Атомные типы обычно полагаются на специализированные аппаратные команды в наборе
команд целевой машины. Например, наборы инструкций на базе Intel предоставляют
инструкцию CAS ( Compare and Swap ), которая будет выполнять определенную
последовательность операций с памятью атомарно.

Эти низкоуровневые инструкции используются для реализации операций более высокого


уровня в API соответствующих классов AtomicXxx . Например, (опять же, в C-подобном
псевдокоде):

https://riptutorial.com/ru/home 277
private volatile num;

int increment() {
while (TRUE) {
int old = num;
int new = old + 1;
if (old == compare_and_swap(&num, old, new)) {
return new;
}
}
}

Если на AtomicXxxx нет споров, тест if будет успешным, и цикл завершится немедленно.
Если есть конфликт, то if будет терпеть неудачу для всех, кроме одного из потоков, и они
будут «вращаться» в цикле для небольшого числа циклов цикла. На практике скорость
вращения на несколько порядков (за исключением нереалистично высоких уровней
конкуренции, когда синхронизация работает лучше, чем атомные классы, потому что, когда
операция CAS завершается с ошибкой, повтор будет только увеличивать конкуренцию),
чем приостановка потока и переход на другой один.

Кстати, инструкции CAS обычно используются JVM для реализации незащищенной


блокировки . Если JVM может видеть, что блокировка в настоящий момент не
заблокирована, она попытается использовать CAS для получения блокировки. Если CAS
преуспевает, тогда нет необходимости выполнять дорогостоящее планирование потоков,
переключение контекста и так далее. Дополнительные сведения об используемых методах
см. В разделе Блокировка смещения в HotSpot .

Прочитайте Атомные типы онлайн: https://riptutorial.com/ru/java/topic/5963/атомные-типы

https://riptutorial.com/ru/home 278
глава 50: аудио
замечания
Вместо использования javax.sound.sampled Clip вы также можете использовать AudioClip
который находится из API апплета. Тем не менее рекомендуется использовать Clip
поскольку AudioClip только старше и представляет собой ограниченную функциональность.

Examples

Воспроизведение аудиофайла

Необходимый импорт:

import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;

Этот код будет создавать клип и воспроизводить его непрерывно после запуска:

Clip clip = AudioSystem.getClip();


clip.open(AudioSystem.getAudioInputStream(new URL(filename)));
clip.start();
clip.loop(Clip.LOOP_CONTINUOUSLY);

Получите массив со всеми поддерживаемыми типами файлов:

AudioFileFormat.Type [] audioFileTypes = AudioSystem.getAudioFileTypes();

Воспроизведение MIDI-файла

Файлы MIDI можно воспроизводить с помощью нескольких классов из пакета


javax.sound.midi . Sequencer выполняет воспроизведение MIDI-файла, и многие его методы
могут использоваться для установки элементов управления воспроизведением, таких как
подсчет циклов, темп, отключение звука и другие.

Общее воспроизведение MIDI-данных может быть выполнено следующим образом:

import java.io.File;
import java.io.IOException;
import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Sequence;
import javax.sound.midi.Sequencer;

public class MidiPlayback {

https://riptutorial.com/ru/home 279
public static void main(String[] args) {
try {
Sequencer sequencer = MidiSystem.getSequencer(); // Get the default Sequencer
if (sequencer==null) {
System.err.println("Sequencer device not supported");
return;
}
sequencer.open(); // Open device
// Create sequence, the File must contain MIDI file data.
Sequence sequence = MidiSystem.getSequence(new File(args[0]));
sequencer.setSequence(sequence); // load it into sequencer
sequencer.start(); // start the playback
} catch (MidiUnavailableException | InvalidMidiDataException | IOException ex) {
ex.printStackTrace();
}
}
}

Чтобы остановить воспроизведение, используйте:

sequencer.stop(); // Stop the playback

Секвенсер может быть настроен на отключение одной или нескольких дорожек


последовательности во время воспроизведения, поэтому ни один из инструментов в
указанных играх не воспроизводится. Следующий пример устанавливает первый трек в
последовательности, которая должна быть отключена:

import javax.sound.midi.Track;
// ...

Track[] track = sequence.getTracks();


sequencer.setTrackMute(track[0]);

Секвенсор может воспроизводить последовательность несколько раз, если задано


количество циклов. Следующее устанавливает секвенсер для воспроизведения
последовательности четыре раза и бесконечно:

sequencer.setLoopCount(3);
sequencer.setLoopCount(Sequencer.LOOP_CONTINUOUSLY);

Секвенсер не всегда должен играть последовательность с самого начала и не должен


играть последовательность до конца. Он может начинаться и заканчиваться в любой
момент, указав галочку в последовательности, чтобы начать и завершить. Также можно
указать вручную, какой тик в последовательности, которую должен играть секвенсор:

sequencer.setLoopStartPoint(512);
sequencer.setLoopEndPoint(32768);
sequencer.setTickPosition(8192);

Секвенсоры также могут играть MIDI-файл с определенным темпом, который можно


контролировать, указав темп в битах в минуту (BPM) или микросекундах на четвертную

https://riptutorial.com/ru/home 280
ноту (MPQ). Можно также скорректировать коэффициент, в котором воспроизводится
последовательность.

sequencer.setTempoInBPM(1250f);
sequencer.setTempoInMPQ(4750f);
sequencer.setTempoFactor(1.5f);

Когда вы закончите использовать Sequencer , помните, чтобы закрыть его

sequencer.close();

Звук из чистого металла

Вы также можете пойти почти голыми металлами при создании звука с помощью java. Этот
код будет записывать необработанные двоичные данные в звуковой буфер OS для
генерации звука. Чрезвычайно важно понимать ограничения и необходимые вычисления
для генерации звука, подобного этому. Поскольку воспроизведение в основном
мгновенное, расчеты должны выполняться почти в режиме реального времени.

Таким образом, этот метод непригоден для более сложной выборки звука. Для таких целей
использование специализированных инструментов - лучший подход.

Следующий метод генерирует и непосредственно выводит прямоугольную волну заданной


частоты в заданном объеме для заданной продолжительности.

public void rectangleWave(byte volume, int hertz, int msecs) {


final SourceDataLine dataLine;
// 24 kHz x 8bit, single-channel, signed little endian AudioFormat
AudioFormat af = new AudioFormat(24_000, 8, 1, true, false);
try {
dataLine = AudioSystem.getSourceDataLine(af);
dataLine.open(af, 10_000); // audio buffer size: 10k samples
} catch (LineUnavailableException e) {
throw new RuntimeException(e);
}

int waveHalf = 24_000 / hertz; // samples for half a period


byte[] buffer = new byte[waveHalf * 20];
int samples = msecs * (24_000 / 1000); // 24k (samples / sec) / 1000 (ms/sec) * time(ms)

dataLine.start(); // starts playback


int sign = 1;

for (int i = 0; i < samples; i += buffer.length) {


for (int j = 0; j < 20; j++) { // generate 10 waves into buffer
sign *= -1;
// fill from the jth wave-half to the j+1th wave-half with volume
Arrays.fill(buffer, waveHalf * j, waveHalf * (j+1), (byte) (volume * sign));
}
dataLine.write(buffer, 0, buffer.length); //
}
dataLine.drain(); // forces buffer drain to hardware
dataLine.stop(); // ends playback

https://riptutorial.com/ru/home 281
}

Для более дифференцированного способа генерации различных звуковых волн


необходимы синусные расчеты и, возможно, больший размер выборки. Это приводит к
значительно более сложному коду и соответственно опущено.

Базовый аудиовыход

Привет, аудио! Java, воспроизводящий звуковой файл из локального или интернет-


хранилища, выглядит следующим образом. Он работает с несжатыми файлами .wav и не
должен использоваться для воспроизведения mp3 или сжатых файлов.

import java.io.*;
import java.net.URL;
import javax.sound.sampled.*;

public class SoundClipTest {

// Constructor
public SoundClipTest() {
try {
// Open an audio input stream.
File soundFile = new File("/usr/share/sounds/alsa/Front_Center.wav"); //you could
also get the sound file with an URL
AudioInputStream audioIn = AudioSystem.getAudioInputStream(soundFile);
AudioFormat format = audioIn.getFormat();
// Get a sound clip resource.
DataLine.Info info = new DataLine.Info(Clip.class, format);
Clip clip = (Clip)AudioSystem.getLine(info);
// Open audio clip and load samples from the audio input stream.
clip.open(audioIn);
clip.start();
} catch (UnsupportedAudioFileException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (LineUnavailableException e) {
e.printStackTrace();
}
}

public static void main(String[] args) {


new SoundClipTest();
}
}

Прочитайте аудио онлайн: https://riptutorial.com/ru/java/topic/160/аудио

https://riptutorial.com/ru/home 282
глава 51: Безопасность и криптография
Examples

Вычислить криптографические хэши

Для вычисления хэшей относительно небольших блоков данных с использованием разных


алгоритмов:

final MessageDigest md5 = MessageDigest.getInstance("MD5");


final MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
final MessageDigest sha256 = MessageDigest.getInstance("SHA-256");

final byte[] data = "FOO BAR".getBytes();

System.out.println("MD5 hash: " + DatatypeConverter.printHexBinary(md5.digest(data)));


System.out.println("SHA1 hash: " + DatatypeConverter.printHexBinary(sha1.digest(data)));
System.out.println("SHA256 hash: " + DatatypeConverter.printHexBinary(sha256.digest(data)));

Производит этот вывод:

MD5 hash: E99E768582F6DD5A3BA2D9C849DF736E


SHA1 hash: 0135FAA6323685BA8A8FF8D3F955F0C36949D8FB
SHA256 hash: 8D35C97BCD902B96D1B551741BBE8A7F50BB5A690B4D0225482EAA63DBFB9DED

Дополнительные алгоритмы могут быть доступны в зависимости от вашей реализации


платформы Java.

Создание криптографически случайных данных

Для генерации выборок криптографически случайных данных:

final byte[] sample = new byte[16];

new SecureRandom().nextBytes(sample);

System.out.println("Sample: " + DatatypeConverter.printHexBinary(sample));

Производит вывод, аналогичный:

Sample: E4F14CEA2384F70B706B53A6DF8C5EFE

Обратите внимание, что вызов nextBytes() может блокироваться при nextBytes() энтропии в
зависимости от используемого алгоритма.

Чтобы указать алгоритм и поставщик:

https://riptutorial.com/ru/home 283
final byte[] sample = new byte[16];
final SecureRandom randomness = SecureRandom.getInstance("SHA1PRNG", "SUN");

randomness.nextBytes(sample);

System.out.println("Provider: " + randomness.getProvider());


System.out.println("Algorithm: " + randomness.getAlgorithm());
System.out.println("Sample: " + DatatypeConverter.printHexBinary(sample));

Производит вывод, аналогичный:

Provider: SUN version 1.8


Algorithm: SHA1PRNG
Sample: C80C44BAEB352FD29FBBE20489E4C0B9

Создание пар общих / закрытых ключей

Для генерации пар ключей с использованием разных алгоритмов и размеров ключей:

final KeyPairGenerator dhGenerator = KeyPairGenerator.getInstance("DiffieHellman");


final KeyPairGenerator dsaGenerator = KeyPairGenerator.getInstance("DSA");
final KeyPairGenerator rsaGenerator = KeyPairGenerator.getInstance("RSA");

dhGenerator.initialize(1024);
dsaGenerator.initialize(1024);
rsaGenerator.initialize(2048);

final KeyPair dhPair = dhGenerator.generateKeyPair();


final KeyPair dsaPair = dsaGenerator.generateKeyPair();
final KeyPair rsaPair = rsaGenerator.generateKeyPair();

Дополнительные алгоритмы и размеры ключей могут быть доступны для вашей реализации
платформы Java.

Чтобы указать источник случайности для использования при создании ключей:

final KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");

generator.initialize(2048, SecureRandom.getInstance("SHA1PRNG", "SUN"));

final KeyPair pair = generator.generateKeyPair();

Вычислить и проверить цифровые подписи

Чтобы вычислить подпись:

final PrivateKey privateKey = keyPair.getPrivate();


final byte[] data = "FOO BAR".getBytes();
final Signature signer = Signature.getInstance("SHA1withRSA");

signer.initSign(privateKey);
signer.update(data);

https://riptutorial.com/ru/home 284
final byte[] signature = signer.sign();

Обратите внимание, что алгоритм подписи должен быть совместим с алгоритмом,


используемым для генерации пары ключей.

Чтобы проверить подпись:

final PublicKey publicKey = keyPair.getPublic();


final Signature verifier = Signature.getInstance("SHA1withRSA");

verifier.initVerify(publicKey);
verifier.update(data);

System.out.println("Signature: " + verifier.verify(signature));

Производит этот вывод:

Signature: true

Шифрование и расшифровка данных с помощью открытых / закрытых


ключей

Для шифрования данных с помощью открытого ключа:

final Cipher rsa = Cipher.getInstance("RSA");

rsa.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());
rsa.update(message.getBytes());
final byte[] result = rsa.doFinal();

System.out.println("Message: " + message);


System.out.println("Encrypted: " + DatatypeConverter.printHexBinary(result));

Производит вывод, аналогичный:

Message: Hello
Encrypted: 5641FBB9558ECFA9ED...

Обратите внимание, что при создании объекта Cipher вам нужно указать преобразование,
совместимое с типом используемого ключа. (См. Стандартные имена алгоритмов JCA для
списка поддерживаемых преобразований.). Для данных шифрования RSA длина
message.getBytes() должна быть меньше размера ключа. См. Этот SO-ответ для
подробностей.

Чтобы расшифровать данные:

final Cipher rsa = Cipher.getInstance("RSA");

rsa.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());

https://riptutorial.com/ru/home 285
rsa.update(cipherText);
final String result = new String(rsa.doFinal());

System.out.println("Decrypted: " + result);

Производит следующий вывод:

Decrypted: Hello

Прочитайте Безопасность и криптография онлайн: https://riptutorial.com/ru/java/topic/7529/


безопасность-и-криптография

https://riptutorial.com/ru/home 286
глава 52: Безопасность и криптография
Вступление
Практики безопасности на Java можно разделить на две широкие, неопределенно
определенные категории; Безопасность платформы Java и защищенное программирование
на Java.

Практики безопасности платформы Java имеют дело с управлением безопасностью и


целостностью JVM. Он включает такие темы, как управление поставщиками JCE и
политиками безопасности.

Безопасные методы программирования Java касаются лучших способов написания


защищенных программ Java. Он включает такие темы, как использование случайных чисел
и криптография, а также предотвращение уязвимостей.

замечания
В то время как примеры должны быть четко сформулированы, некоторые темы, которые
необходимо охватить, следующие:

1. Концепция / структура поставщика JCE


2. Элемент списка

Examples
JCE

Расширение Java Cryptography Extension (JCE) - это структура, встроенная в JVM,


позволяющая разработчикам легко и безопасно использовать криптографию в своих
программах. Он делает это, предоставляя простой, портативный интерфейс для
программистов, используя систему JCE Providers для безопасного осуществления основных
криптографических операций.

Ключи и управление ключами

В то время как JCE обеспечивает криптографические операции и генерирование ключей,


разработчик фактически может управлять своими ключами. Здесь необходимо
предоставить дополнительную информацию.

Одной из общепринятых рекомендаций по управлению ключами во время выполнения


является сохранение их только в byte массивов byte и никогда не как строки. Это связано с

https://riptutorial.com/ru/home 287
тем, что строки Java неизменяемы и не могут быть вручную «очищены» или «обнулены» в
памяти; в то время как ссылка на строку может быть удалена, точная строка останется в
памяти, пока ее сегмент памяти не будет собран и повторно использован для сбора мусора.
У злоумышленника будет большое окно, в котором они могут сбросить память программы и
легко найти ключ. Напротив, массивы byte изменяемы, и их содержимое может быть
перезаписано на месте; это хорошая идея «обнулить» ваши ключи, как только они вам
больше не понадобятся.

Общие уязвимости Java

Нужен контент

Проблемы с сетью

Нужен контент

Случайность и вы

Нужен контент

Для большинства приложений класс java.utils.Random является прекрасным источником


«случайных» данных. Если вам нужно выбрать случайный элемент из массива или создать
случайную строку или создать временный «уникальный» идентификатор, вероятно, вы
должны использовать Random .

Однако многие криптографические системы полагаются на случайность для своей


безопасности, а случайность, предоставляемая Random не имеет достаточно высокого
качества. Для любой криптографической операции, требующей случайного ввода, вы
должны использовать SecureRandom .

Хеширование и проверка

Необходима дополнительная информация.

Криптографическая хеш-функция является членом класса функций с тремя важными


свойствами; последовательности, уникальности и необратимости.

Согласованность: при одинаковых данных хеш-функция всегда возвращает одно и то же


значение. То есть, если X = Y, f (x) всегда будет равно f (y) для хэш-функции f.

Уникальность: никакие два входа хеш-функции никогда не приведут к одному и тому же


выводу. То есть, если X! = Y, f (x)! = F (y), для любых значений X и Y.

Необратимость. Неправдоподобно, если не невозможно, «перевернуть» хэш-функцию. То


есть, учитывая только f (X), не должно быть способа найти исходный X, чтобы не

https://riptutorial.com/ru/home 288
поставить все возможные значения X через функцию f (грубая сила). Не должно быть
функции f1, для которой f1 (f (X)) = X.

Во многих функциях отсутствует хотя бы один из этих атрибутов. Например, известно, что
MD5 и SHA1 имеют коллизии, т. Е. Два входа, которые имеют одинаковый выход, поэтому
им не хватает уникальности. Некоторые функции, которые в настоящее время считаются
безопасными, это SHA-256 и SHA-512.

Прочитайте Безопасность и криптография онлайн: https://riptutorial.com/ru/java/topic/9371/


безопасность-и-криптография

https://riptutorial.com/ru/home 289
глава 53: Бит-манипуляция
замечания
• В отличие от C / C ++, Java полностью нейтральна по отношению к базовому
аппарату. По умолчанию вы не становитесь большим или маленьким поведением; вы
должны явно указать, какое поведение вы хотите.

• Тип byte подписан, диапазон от -128 до +127. Чтобы преобразовать значение байта в
его беззнаковый эквивалент, замаскируйте его с помощью 0xFF следующим образом:
(b & 0xFF) .

Examples

Упаковка / распаковка значений в виде фрагментов

Обычно производительность памяти сводит несколько значений в одно примитивное


значение. Это может быть полезно для передачи различной информации в одну
переменную.

Например, можно упаковать 3 байта - например, цветовой код в RGB - в один int.

Упаковка значений

// Raw bytes as input


byte[] b = {(byte)0x65, (byte)0xFF, (byte)0x31};

// Packed in big endian: x == 0x65FF31


int x = (b[0] & 0xFF) << 16 // Red
| (b[1] & 0xFF) << 8 // Green
| (b[2] & 0xFF) << 0; // Blue

// Packed in little endian: y == 0x31FF65


int y = (b[0] & 0xFF) << 0
| (b[1] & 0xFF) << 8
| (b[2] & 0xFF) << 16;

Распаковка значений

// Raw int32 as input


int x = 0x31FF65;

// Unpacked in big endian: {0x65, 0xFF, 0x31}


byte[] c = {
(byte)(x >> 16),
(byte)(x >> 8),
(byte)(x & 0xFF)
};

https://riptutorial.com/ru/home 290
// Unpacked in little endian: {0x31, 0xFF, 0x65}
byte[] d = {
(byte)(x & 0xFF),
(byte)(x >> 8),
(byte)(x >> 16)
};

Проверка, настройка, очистка и переключение отдельных битов.


Использование длинной битовой маски

Предполагая, что мы хотим изменить бит n целочисленного примитива, i (байт, короткий,


char, int или long):

(i & 1 << n) != 0 // checks bit 'n'


i |= 1 << n; // sets bit 'n' to 1
i &= ~(1 << n); // sets bit 'n' to 0
i ^= 1 << n; // toggles the value of bit 'n'

Использование long / int / short / byte в качестве битовой маски:

public class BitMaskExample {


private static final long FIRST_BIT = 1L << 0;
private static final long SECOND_BIT = 1L << 1;
private static final long THIRD_BIT = 1L << 2;
private static final long FOURTH_BIT = 1L << 3;
private static final long FIFTH_BIT = 1L << 4;
private static final long BIT_55 = 1L << 54;

public static void main(String[] args) {


checkBitMask(FIRST_BIT | THIRD_BIT | FIFTH_BIT | BIT_55);
}

private static void checkBitMask(long bitmask) {


System.out.println("FIRST_BIT: " + ((bitmask & FIRST_BIT) != 0));
System.out.println("SECOND_BIT: " + ((bitmask & SECOND_BIT) != 0));
System.out.println("THIRD_BIT: " + ((bitmask & THIRD_BIT) != 0));
System.out.println("FOURTh_BIT: " + ((bitmask & FOURTH_BIT) != 0));
System.out.println("FIFTH_BIT: " + ((bitmask & FIFTH_BIT) != 0));
System.out.println("BIT_55: " + ((bitmask & BIT_55) != 0));
}
}

Печать

FIRST_BIT: true
SECOND_BIT: false
THIRD_BIT: true
FOURTh_BIT: false
FIFTH_BIT: true
BIT_55: true

который соответствует этой маске мы прошли в качестве checkBitMask параметра: FIRST_BIT |


THIRD_BIT | FIFTH_BIT | BIT_55 .

https://riptutorial.com/ru/home 291
Выражая силу 2

Для выражения степени 2 (2 ^ n) целых чисел можно использовать операцию бит-сдвига,


которая позволяет явно указать n .

Синтаксис в основном:

int pow2 = 1<<n;

Примеры:

int twoExp4 = 1<<4; //2^4


int twoExp5 = 1<<5; //2^5
int twoExp6 = 1<<6; //2^6
...
int twoExp31 = 1<<31; //2^31

Это особенно полезно при определении постоянных значений, которые должны сделать
очевидным, что используется сила 2, вместо использования шестнадцатеричных или
десятичных значений.

int twoExp4 = 0x10; //hexadecimal


int twoExp5 = 0x20; //hexadecimal
int twoExp6 = 64; //decimal
...
int twoExp31 = -2147483648; //is that a power of 2?

Простым методом вычисления мощности int 2 будет

int pow2(int exp){


return 1<<exp;
}

Проверка того, является ли число мощностью 2

Если целое число x равно 2, устанавливается только один бит, тогда как x-1 имеет все
биты, установленные после этого. Например: 4 равно 100 и 3 равно 011 как двоичное число,
которое удовлетворяет вышеупомянутому условию. Ноль не равен 2 и должен быть
проверен явно.

boolean isPowerOfTwo(int x)
{
return (x != 0) && ((x & (x - 1)) == 0);
}

Использование левого и правого сдвига

Предположим, у нас есть три вида разрешений: READ , WRITE и EXECUTE . Каждое

https://riptutorial.com/ru/home 292
разрешение может варьироваться от 0 до 7. (Предположим, что система с четырьмя
битами)

RESOURCE = READ WRITE EXECUTE (12-разрядное число)

RESOURCE = 0100 0110 0101 = 4 6 5 (12-разрядное число)

Как мы можем получить разрешения (12-разрядного номера), установленные выше (12-


разрядное число)?

0100 0110 0101

0000 0000 0111 (&)

0000 0000 0101 = 5

Таким образом, мы можем получить разрешения EXECUTE RESOURCE . Теперь, что, если
мы хотим получить READ- разрешения RESOURCE ?

0100 0110 0101

0111 0000 0000 (&)

0100 0000 0000 = 1024

Правильно? Вероятно, вы это принимаете? Но разрешения приведены в 1024. Мы хотим


получить только разрешения READ для ресурса. Не волнуйтесь, поэтому у нас были
операторы смены. Если мы увидим, разрешения READ на 8 бит превысят фактический
результат, поэтому, если применить некоторый оператор сдвига, который приведет к
разрешению READ до самого правильного результата? Что делать, если мы это сделаем:

0100 0000 0000 >> 8 => 0000 0000 0100 (потому что это положительное число,
замененное на 0, если вы не заботитесь о знаке, просто используйте
беззнаковый оператор сдвига вправо)

Теперь у нас есть разрешения READ, которые равны 4.

Теперь, например, нам предоставлены разрешения READ , WRITE , EXECUTE для


RESOURCE , что мы можем сделать, чтобы сделать разрешения для этого РЕСУРСА ?

Давайте сначала рассмотрим пример двоичных разрешений. (Все еще предполагая систему
с 4-разрядными номерами)

READ = 0001

WRITE = 0100

EXECUTE = 0110

https://riptutorial.com/ru/home 293
Если вы думаете, что мы просто сделаем это:

, вы несколько правы, но не совсем. Смотрите, что произойдет, если


READ | WRITE | EXECUTE
мы будем выполнять READ | НАПИСАТЬ | ВЫПОЛНИТЬ

0001 | 0100 | 0110 => 0111

Но разрешения фактически представлены (в нашем примере) как 0001 0100 0110

Итак, чтобы сделать это, мы знаем, что READ размещен на 8 бит позади, WRITE
помещается на 4 бита, а PERMISSIONS помещается последним. Система номеров,
используемая для разрешений RESOURCE, на самом деле составляет 12 бит (в нашем
примере). Он может (будет) отличаться в разных системах.

(READ << 8) | (WRITE << 4) | (EXECUTE)

0000 0000 0001 << 8 (READ)

0001 0000 0000 (сдвиг влево на 8 бит)

0000 0000 0100 << 4 (WRITE)

0000 0100 0000 (сдвиг влево на 4 бита)

0000 0000 0001 (ВЫПОЛНИТЬ)

Теперь, если мы добавим результаты вышеперечисленного, это будет нечто подобное;

0001 0000 0000 (READ)

0000 0100 0000 (ЗАПИСЬ)

0000 0000 0001 (ВЫПОЛНИТЬ)

0001 0100 0001 (РАЗРЕШЕНИЯ)

Класс java.util.BitSet

Начиная с версии 1.7 существует класс java.util.BitSet, который обеспечивает простой и


удобный интерфейс хранения и манипулирования битами:

final BitSet bitSet = new BitSet(8); // by default all bits are unset

IntStream.range(0, 8).filter(i -> i % 2 == 0).forEach(bitSet::set); // {0, 2, 4, 6}

bitSet.set(3); // {0, 2, 3, 4, 6}

bitSet.set(3, false); // {0, 2, 4, 6}

final boolean b = bitSet.get(3); // b = false

https://riptutorial.com/ru/home 294
bitSet.flip(6); // {0, 2, 4}

bitSet.set(100); // {0, 2, 4, 100} - expands automatically

BitSet реализует Clonable и Serializable , а под капотом все значения бит хранятся в long[]
words поле long[] words , которое автоматически расширяется.

Он также поддерживает целые логические операции and , or , xor , andNot :

bitSet.and(new BitSet(8));
bitSet.or(new BitSet(8));
bitSet.xor(new BitSet(8));
bitSet.andNot(new BitSet(8));

Подписанный беззнаковый сдвиг

В Java все примитивы числа подписаны. Например, int всегда представляет значения из [-2
^ 31 - 1, 2 ^ 31], сохраняя первый бит для подписи значения - 1 для отрицательного
значения, 0 для положительного.

Операторы основного сдвига >> и << являются операторами-операторами. Они сохранят


знак ценности.

Но программисты часто используют номера для хранения значений без знака . Для int это
означает смещение диапазона до [0, 2 ^ 32 - 1], чтобы иметь в два раза большее значение,
чем с подписанным int.

Для тех опытных пользователей бит для знака не имеет смысла. Вот почему Java добавила
>>> , оператор с левым сдвигом, не считая этого бита знака.

initial value: 4 ( 100)


signed left-shift: 4 << 1 8 ( 1000)
signed right-shift: 4 >> 1 2 ( 10)
unsigned right-shift: 4 >>> 1 2 ( 10)
initial value: -4 ( 11111111111111111111111111111100)
signed left-shift: -4 << 1 -8 ( 11111111111111111111111111111000)
signed right-shift: -4 >> 1 -2 ( 11111111111111111111111111111110)
unsigned right-shift: -4 >>> 1 2147483646 ( 1111111111111111111111111111110)

Почему нет <<< ?

Это исходит из предполагаемого определения сдвига вправо. Когда он заполняет


опустошенные места слева, нет никакого решения принять бит за знак. Как следствие, нет
необходимости в двух разных операторах.

См. Этот вопрос для более детального ответа.

Прочитайте Бит-манипуляция онлайн: https://riptutorial.com/ru/java/topic/1177/бит-

https://riptutorial.com/ru/home 295
манипуляция

https://riptutorial.com/ru/home 296
глава 54: Валюта и деньги
Examples

Добавить пользовательскую валюту

Обязательные JAR-адреса в пути к классам:

• javax.money :money-api:1.0 (JSR354 деньги и валюта api)


• org.javamoney: moneta: 1.0 (Реализация ссылок)
• javax: аннотация-апи: 1.2. (Общие аннотации, используемые для эталонной
реализации)

// Let's create non-ISO currency, such as bitcoin

// At first, this will throw UnknownCurrencyException


MonetaryAmount moneys = Money.of(new BigDecimal("0.1"), "BTC");

// This happens because bitcoin is unknown to default currency


// providers
System.out.println(Monetary.isCurrencyAvailable("BTC")); // false

// We will build new currency using CurrencyUnitBuilder provided by org.javamoney.moneta


CurrencyUnit bitcoin = CurrencyUnitBuilder
.of("BTC", "BtcCurrencyProvider") // Set currency code and currency provider name
.setDefaultFractionDigits(2) // Set default fraction digits
.build(true); // Build new currency unit. Here 'true' means
// currency unit is to be registered and
// accessible within default monetary context

// Now BTC is available


System.out.println(Monetary.isCurrencyAvailable("BTC")); // True

Прочитайте Валюта и деньги онлайн: https://riptutorial.com/ru/java/topic/8359/валюта-и-


деньги

https://riptutorial.com/ru/home 297
глава 55: Ведение журнала (
java.util.logging)
Examples

Использование регистратора по умолчанию

В этом примере показано, как использовать атрибут api по умолчанию.

import java.util.logging.Level;
import java.util.logging.Logger;

public class MyClass {

// retrieve the logger for the current class


private static final Logger LOG = Logger.getLogger(MyClass.class.getName());

public void foo() {


LOG.info("A log message");
LOG.log(Level.INFO, "Another log message");

LOG.fine("A fine message");

// logging an exception
try {
// code might throw an exception
} catch (SomeException ex) {
// log a warning printing "Something went wrong"
// together with the exception message and stacktrace
LOG.log(Level.WARNING, "Something went wrong", ex);
}

String s = "Hello World!";

// logging an object
LOG.log(Level.FINER, "String s: {0}", s);

// logging several objects


LOG.log(Level.FINEST, "String s: {0} has length {1}", new Object[]{s, s.length()});
}

Уровни регистрации

Java Logging Api имеет 7 уровней . Уровни в порядке убывания:

• SEVERE (наибольшее значение)


• WARNING
• INFO
• CONFIG
• FINE

https://riptutorial.com/ru/home 298
• FINER

• FINEST (самое низкое значение)

Уровень по умолчанию - INFO (но это зависит от системы и используется виртуальной


машиной).

Примечание . Существуют также уровни OFF (можно использовать для отключения


регистрации) и ALL (oposite OFF ).

Пример кода для этого:

import java.util.logging.Logger;

public class Levels {


private static final Logger logger = Logger.getLogger(Levels.class.getName());

public static void main(String[] args) {

logger.severe("Message logged by SEVERE");


logger.warning("Message logged by WARNING");
logger.info("Message logged by INFO");
logger.config("Message logged by CONFIG");
logger.fine("Message logged by FINE");
logger.finer("Message logged by FINER");
logger.finest("Message logged by FINEST");

// All of above methods are really just shortcut for


// public void log(Level level, String msg):
logger.log(Level.FINEST, "Message logged by FINEST");
}
}

По умолчанию запуск этого класса будет выводить только сообщения с уровнем выше, чем
CONFIG :

Jul 23, 2016 9:16:11 PM LevelsExample main


SEVERE: Message logged by SEVERE
Jul 23, 2016 9:16:11 PM LevelsExample main
WARNING: Message logged by WARNING
Jul 23, 2016 9:16:11 PM LevelsExample main
INFO: Message logged by INFO

Регистрация сложных сообщений (эффективно)

Давайте рассмотрим пример регистрации, который вы можете увидеть во многих


программах:

public class LoggingComplex {

private static final Logger logger =


Logger.getLogger(LoggingComplex.class.getName());

private int total = 50, orders = 20;


private String username = "Bob";

https://riptutorial.com/ru/home 299
public void takeOrder() {
// (...) making some stuff
logger.fine(String.format("User %s ordered %d things (%d in total)",
username, orders, total));
// (...) some other stuff
}

// some other methods and calculations


}

Вышеприведенный пример выглядит отлично, но многие программисты забывают, что Java


VM является стековой машиной. Это означает, что все параметры метода вычисляются
перед выполнением метода.

Этот факт имеет решающее значение для ведения журнала на Java, особенно для
регистрации чего-то на низких уровнях, таких как FINE , FINER , FINEST которые по умолчанию
отключены. Давайте рассмотрим байт-код Java для takeOrder() .

Результат для javap -c LoggingComplex.class выглядит примерно так:

public void takeOrder();


Code:
0: getstatic #27 // Field logger:Ljava/util/logging/Logger;
3: ldc #45 // String User %s ordered %d things (%d in total)
5: iconst_3
6: anewarray #3 // class java/lang/Object
9: dup
10: iconst_0
11: aload_0
12: getfield #40 // Field username:Ljava/lang/String;
15: aastore
16: dup
17: iconst_1
18: aload_0
19: getfield #36 // Field orders:I
22: invokestatic #47 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
25: aastore
26: dup
27: iconst_2
28: aload_0
29: getfield #34 // Field total:I
32: invokestatic #47 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
35: aastore
36: invokestatic #53 // Method
java/lang/String.format:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
39: invokevirtual #59 // Method java/util/logging/Logger.fine:(Ljava/lang/String;)V
42: return

В строке 39 выполняется фактическое ведение журнала. Вся предыдущая работа


(загрузка переменных, создание новых объектов, объединение строк в format ) может быть
зря, если уровень ведения журнала установлен выше, чем FINE (и по умолчанию он есть).
Такое ведение журнала может быть очень неэффективным, потребляя ненужные ресурсы
памяти и процессора.

https://riptutorial.com/ru/home 300
Вот почему вы должны спросить, включен ли уровень, который вы хотите использовать.

Правильный путь должен быть:

public void takeOrder() {


// making some stuff
if (logger.isLoggable(Level.FINE)) {
// no action taken when there's no need for it
logger.fine(String.format("User %s ordered %d things (%d in total)",
username, orders, total));
}
// some other stuff
}

Поскольку Java 8:

Класс Logger имеет дополнительные методы, которые используют параметр


Supplier<String> , который может быть просто предоставлен лямбдой:

public void takeOrder() {


// making some stuff
logger.fine(() -> String.format("User %s ordered %d things (%d in total)",
username, orders, total));
// some other stuff
}

Метод get() поставщиков get() в этом случае лямбда - вызывается только тогда, когда
соответствующий уровень включен, и поэтому конструкция if больше не нужна.

Прочитайте Ведение журнала (java.util.logging) онлайн:


https://riptutorial.com/ru/java/topic/2010/ведение-журнала--java-util-logging-

https://riptutorial.com/ru/home 301
глава 56: Видимость (контроль доступа к
членам класса)
Синтаксис
• public type name [= value];
• имя частного типа [= значение];
• имя защищенного типа [= значение];
• имя типа [= значение];
• public class name {
• имя класса {

замечания
Из учебника Java :

Модификаторы уровня доступа определяют, могут ли другие классы использовать


конкретное поле или вызвать конкретный метод. Существует два уровня контроля доступа:

• На верхнем уровне - public или package-private (без явного модификатора).


• На уровне участника - public , private , protected или пакетно-закрытый (без явного
модификатора).

Класс может быть объявлен public модификатором, и в этом случае этот класс будет
виден всем классам. Если класс не имеет модификатора (по умолчанию, также известного
как private-package ), он отображается только в пределах его собственного пакета.

На уровне члена вы также можете использовать public модификатор или модификатор (


private-package ), как и классы верхнего уровня, и с тем же значением. Для участников есть
два дополнительных модификатора доступа: private и protected . private модификатор
указывает, что к члену можно получить доступ только в своем классе. protected
модификатор указывает, что к члену можно получить доступ только в своем собственном
пакете (как и в пакете private ) и, кроме того, подклассе его класса в другом пакете.

В следующей таблице показан доступ к членам, разрешенным каждым модификатором.

Уровни доступа:

Модификатор Учебный класс пакет Подкласс Мир

public Y Y Y Y

protected Y Y Y N

https://riptutorial.com/ru/home 302
Модификатор Учебный класс пакет Подкласс Мир

нет модификатора Y Y N N

private Y N N N

Examples

Элементы интерфейса

public interface MyInterface {


public void foo();
int bar();

public String TEXT = "Hello";


int ANSWER = 42;

public class X {
}

class Y {
}
}

Члены интерфейса всегда имеют общедоступную видимость, даже если ключевое слово
public опущено. Таким образом, как foo() , bar() , TEXT , ANSWER , X , так и Y имеют общую
видимость. Тем не менее, доступ по-прежнему может ограничиваться содержащимся
интерфейсом - поскольку MyInterface имеет общедоступную видимость, к его членам можно
получить доступ из любого места, но если у MyInterface была видимость пакета, его члены
были бы доступны только из одного и того же пакета.

Общественная видимость

Видно для класса, пакета и подкласса.

Давайте посмотрим пример с классом Test.

public class Test{


public int number = 2;

public Test(){

}
}

Теперь попробуем создать экземпляр класса. В этом примере мы можем получить доступ к
number потому что он является public .

public class Other{

https://riptutorial.com/ru/home 303
public static void main(String[] args){
Test t = new Test();
System.out.println(t.number);
}

Частная видимость

видимость позволяет доступ к переменной только для своего класса. Они часто
private
используются вместе с public геттерами и сеттерами.

class SomeClass {
private int variable;

public int getVariable() {


return variable;
}

public void setVariable(int variable) {


this.variable = variable;
}
}

public class SomeOtherClass {


public static void main(String[] args) {
SomeClass sc = new SomeClass();

// These statement won't compile because SomeClass#variable is private:


sc.variable = 7;
System.out.println(sc.variable);

// Instead, you should use the public getter and setter:


sc.setVariable(7);
System.out.println(sc.getVariable());
}
}

Видимость пакета

Без модификатора значение по умолчанию - видимость пакета. Из документации Java «[


видимость пакета] указывает, имеют ли классы в том же пакете, что и класс (независимо
от их происхождения), доступ к члену». В этом примере из javax.swing ,

package javax.swing;
public abstract class JComponent extends Container … {

static boolean DEBUG_GRAPHICS_LOADED;

}

DebugGraphics находится в одном пакете, поэтому DEBUG_GRAPHICS_LOADED доступен.

package javax.swing;

https://riptutorial.com/ru/home 304
public class DebugGraphics extends Graphics {

static {
JComponent.DEBUG_GRAPHICS_LOADED = true;
}

}

В этой статье приводятся некоторые сведения об этой теме.

Защищенная видимость

Защищенная видимость приводит к тому, что этот элемент видим для своего пакета вместе
с любым из его подклассов.

В качестве примера:

package com.stackexchange.docs;
public class MyClass{
protected int variable; //This is the variable that we are trying to access
public MyClass(){
variable = 2;
};
}

Теперь мы расширим этот класс и попытаемся получить доступ к одному из его protected
членов.

package some.other.pack;
import com.stackexchange.docs.MyClass;
public class SubClass extends MyClass{
public SubClass(){
super();
System.out.println(super.variable);
}
}

Вы также сможете получить доступ к protected члену без его расширения, если вы
получаете доступ к нему из одного пакета.

Обратите внимание, что этот модификатор работает только с членами класса, а не с самим
классом.

Резюме модификаторов доступа к члену класса

Модификатор доступа видимость наследование

Частный Только класс Не может быть унаследован

Нет модификатора / пакета В пакете Доступно, если подкласс в пакете

https://riptutorial.com/ru/home 305
Модификатор доступа видимость наследование

защищенный В пакете Доступно в подклассе

общественного Везде Доступно в подклассе

Когда-то был private protected (оба ключевых слова сразу), который можно было применить
к методам или переменным, чтобы сделать их доступными из подкласса вне пакета, но
сделать их закрытыми для классов в этом пакете. Однако это было удалено в выпуске Java
1.0 .

Прочитайте Видимость (контроль доступа к членам класса) онлайн:


https://riptutorial.com/ru/java/topic/134/видимость--контроль-доступа-к-членам-класса-

https://riptutorial.com/ru/home 306
глава 57: Виртуальная машина Java (JVM)
Examples

Это основы.

JVM - это абстрактная вычислительная машина или виртуальная машина, которая


находится в вашей ОЗУ. Он имеет независимую от платформы среду исполнения, которая
интерпретирует байт-код Java в собственный машинный код. (Javac - компилятор Java,
который компилирует ваш Java-код в Bytecode)

Java-программа будет запущена внутри JVM, которая затем отображается на базовую


физическую машину. Это один из инструментов программирования в JDK.

( Byte code - это независимый от платформы код, который запускается на каждой


платформе, а Machine code - это код, специфичный для платформы, который запускается
только на определенной платформе, такой как windows или linux, и зависит от
исполнения.)

Некоторые из компонентов: -

• Класс Loder - загрузить файл .class в оперативную память.


• Верификатор байтов - проверьте, есть ли в вашем коде какие-либо нарушения
ограничения доступа.
• Механизм выполнения - преобразование байтового кода в исполняемый машинный
код.
• JIT (как раз вовремя) - JIT является частью JVM, которая используется для
повышения производительности JVM. Она будет динамически компилировать или
транслировать java-байт-код в собственный машинный код во время выполнения.

(Edited)

Прочитайте Виртуальная машина Java (JVM) онлайн: https://riptutorial.com/ru/java/topic/8110/


виртуальная-машина-java--jvm-

https://riptutorial.com/ru/home 307
глава 58: Виртуальный доступ Java
Examples

Введение в JNA

Что такое JNA?


Java Native Access (JNA) - это разработанная сообществом библиотека, предоставляющая
Java-программам легкий доступ к родным общим библиотекам ( .dll файлы в Windows,
файлы .so в Unix ...)

Как я могу использовать его?


• Во-первых, загрузите последнюю версию JNA и укажите ее jna.jar в CLASSPATH
вашего проекта.

• Во-вторых, скопируйте, скомпилируйте и запустите Java-код ниже

Для целей этого введения мы предполагаем, что используемая нативная


платформа - это Windows. Если вы работаете на другой платформе, просто
замените строку "msvcrt" на строку "c" в приведенном ниже коде.

Маленькая Java-программа ниже выведет сообщение на консоль, вызвав функцию C printf


.

CRuntimeLibrary.java

package jna.introduction;

import com.sun.jna.Library;
import com.sun.jna.Native;

// We declare the printf function we need and the library containing it (msvcrt)...
public interface CRuntimeLibrary extends Library {

CRuntimeLibrary INSTANCE =
(CRuntimeLibrary) Native.loadLibrary("msvcrt", CRuntimeLibrary.class);

void printf(String format, Object... args);


}

MyFirstJNAProgram.java

package jna.introduction;

https://riptutorial.com/ru/home 308
// Now we call the printf function...
public class MyFirstJNAProgram {
public static void main(String args[]) {
CRuntimeLibrary.INSTANCE.printf("Hello World from JNA !");
}
}

Куда пойти сейчас?


Перейдите в другую тему или перейдите на официальный сайт .

Прочитайте Виртуальный доступ Java онлайн: https://riptutorial.com/ru/java/topic/5244/


виртуальный-доступ-java

https://riptutorial.com/ru/home 309
глава 59: Вложенные и внутренние классы
Вступление
Используя Java, разработчики могут определять класс в другом классе. Такой класс
называется вложенным классом . Вложенные классы называются внутренними классами,
если они были объявлены как нестатические, если нет, их просто называют статическими
вложенными классами. Эта страница предназначена для документирования и
предоставления подробных сведений о том, как использовать Java Nested и Inner Classes.

Синтаксис
• public class OuterClass {public class InnerClass {}} // Внутренние классы также могут
быть приватными
• public class OuterClass {public static class StaticNestedClass {}} // Статические
вложенные классы также могут быть приватными
• public void method () {private class LocalClass {}} // Локальные классы всегда приватные
• SomeClass anonymousClassInstance = new SomeClass () {}; // Анонимные внутренние
классы нельзя назвать, следовательно, доступ является спорным. Если «SomeClass
()» является абстрактным, тело должно реализовать все абстрактные методы.
• SomeInterface anonymousClassInstance = new SomeInterface () {}; // Тело должно
реализовать все методы интерфейса.

замечания

Терминология и классификация
Спецификация языка Java (JLS) классифицирует различные типы Java-классов следующим
образом:

Класс верхнего уровня - это класс, который не является вложенным классом.

Вложенным классом является любой класс, чье объявление происходит внутри


тела другого класса или интерфейса.

Внутренний класс представляет собой вложенный класс, который явно или


неявно не объявлен статическим.

Внутренний класс может быть не статическим классом-членом , локальным


классом или анонимным классом . Класс-член интерфейса неявно статичен,
поэтому он никогда не считается внутренним классом.

https://riptutorial.com/ru/home 310
На практике программисты ссылаются на класс верхнего уровня, который содержит
внутренний класс как «внешний класс». Кроме того, существует тенденция использовать
«вложенный класс» для обозначения только (явно или неявно) статических вложенных
классов.

Обратите внимание, что между анонимными внутренними классами и лямбдами существует


тесная связь, но лямбды - это классы.

Семантические различия
• Классы верхнего уровня - это «базовый случай». Они видны другим частям
программы, подчиненным нормальным правилам видимости, основанным на семантике
модификатора доступа. Если они не являются абстрактными, они могут быть созданы
каким-либо кодом, где соответствующие конструкторы видны на основе
модификаторов доступа.

• Статические вложенные классы следуют тем же правилам доступа и создания


экземпляров, что и классы верхнего уровня, за двумя исключениями:

○ Вложенный класс может быть объявлен как private , что делает его
недоступным вне его класса верхнего уровня.
○ Вложенный класс имеет доступ к private членам охватывающего класса верхнего
уровня и всего его тестируемого класса.

Это делает статические вложенные классы полезными, когда вам нужно


представлять несколько «типов сущностей» в пределах границы жесткой абстракции;
например, когда вложенные классы используются для скрытия «деталей
реализации».

• Внутренние классы добавляют возможность доступа к нестационарным переменным,


объявленным в охватываемых областях:

○ Нестатический класс-член может ссылаться на переменные экземпляра.


○ Локальный класс (объявленный внутри метода) также может ссылаться на
локальные переменные метода, при условии, что они являются final . (Для Java
8 и более поздних версий они могут быть фактически окончательными .)
○ Анонимный внутренний класс может быть объявлен как в классе, так и в методе
и может обращаться к переменным в соответствии с теми же правилами.

Тот факт, что экземпляр внутреннего класса может ссылаться на переменные в


экземпляре охватывающего класса, имеет последствия для экземпляра. В частности,
экземпляр-экземпляр должен быть предоставлен, как неявно, так и явно, при
создании экземпляра внутреннего класса.

https://riptutorial.com/ru/home 311
Examples

Простой стек с использованием вложенного класса

public class IntStack {

private IntStackNode head;

// IntStackNode is the inner class of the class IntStack


// Each instance of this inner class functions as one link in the
// Overall stack that it helps to represent
private static class IntStackNode {

private int val;


private IntStackNode next;

private IntStackNode(int v, IntStackNode n) {


val = v;
next = n;
}
}

public IntStack push(int v) {


head = new IntStackNode(v, head);
return this;
}

public int pop() {


int x = head.val;
head = head.next;
return x;
}
}

И их использование, которое (в частности) вовсе не признает существование вложенного


класса.

public class Main {


public static void main(String[] args) {

IntStack s = new IntStack();


s.push(4).push(3).push(2).push(1).push(0);

//prints: 0, 1, 2, 3, 4,
for(int i = 0; i < 5; i++) {
System.out.print(s.pop() + ", ");
}
}
}

Статические и нестатические вложенные классы

При создании вложенного класса вы сталкиваетесь с выбором наличия вложенного класса


static:

https://riptutorial.com/ru/home 312
public class OuterClass1 {

private static class StaticNestedClass {

Или нестатический:

public class OuterClass2 {

private class NestedClass {

По своей сути, статические вложенные классы не имеют окружающего экземпляра


внешнего класса, тогда как нестатические вложенные классы делают. Это влияет как на
то, где / когда разрешено создавать экземпляр вложенного класса, так и к каким
экземплярам этих вложенных классов разрешен доступ. Добавление к приведенному выше
примеру:

public class OuterClass1 {

private int aField;


public void aMethod(){}

private static class StaticNestedClass {


private int innerField;

private StaticNestedClass() {
innerField = aField; //Illegal, can't access aField from static context
aMethod(); //Illegal, can't call aMethod from static context
}

private StaticNestedClass(OuterClass1 instance) {


innerField = instance.aField; //Legal
}

public static void aStaticMethod() {


StaticNestedClass s = new StaticNestedClass(); //Legal, able to construct in static
context
//Do stuff involving s...
}

public class OuterClass2 {

private int aField;

public void aMethod() {}

https://riptutorial.com/ru/home 313
private class NestedClass {
private int innerField;

private NestedClass() {
innerField = aField; //Legal
aMethod(); //Legal
}
}

public void aNonStaticMethod() {


NestedClass s = new NestedClass(); //Legal
}

public static void aStaticMethod() {


NestedClass s = new NestedClass(); //Illegal. Can't construct without surrounding
OuterClass2 instance.
//As this is a static context, there is no
surrounding OuterClass2 instance
}
}

Таким образом, ваше решение статического и нестатического в основном зависит от того,


нужно ли вам напрямую обращаться к полям и методам внешнего класса, хотя это также
имеет последствия для того, когда и где вы можете построить вложенный класс.

Как правило, сделайте ваши вложенные классы статичными, если вам не нужно
обращаться к полям и методам внешнего класса. Подобно тому, как ваши поля являются
закрытыми, если они вам не нужны, это уменьшает видимость, доступную для вложенного
класса (не разрешая доступ к внешнему экземпляру), уменьшая вероятность ошибки.

Модификаторы доступа для внутренних классов

Полное описание модификаторов доступа в Java можно найти здесь . Но как они
взаимодействуют с внутренними классами?

public, как обычно, предоставляет неограниченный доступ к любой области, доступной для
доступа к типу.

public class OuterClass {

public class InnerClass {

public int x = 5;

public InnerClass createInner() {


return new InnerClass();
}
}

public class SomeOtherClass {

public static void main(String[] args) {

https://riptutorial.com/ru/home 314
int x = new OuterClass().createInner().x; //Direct field access is legal
}
}

оба protected а модификатор по умолчанию (ничего) ведет себя так же, как ожидалось, так
же, как и для не-вложенных классов.

, интересно, не ограничивает класс, к которому он принадлежит. Скорее, он


private
ограничивает блок компиляции - .java-файл. Это означает, что внешние классы имеют
полный доступ к полям и методам Inner, даже если они выделены как private .

public class OuterClass {

public class InnerClass {

private int x;
private void anInnerMethod() {}
}

public InnerClass aMethod() {


InnerClass a = new InnerClass();
a.x = 5; //Legal
a.anInnerMethod(); //Legal
return a;
}
}

Сам внутренний класс может иметь видимость, отличную от public . Пометив его private
или другим модификатором ограниченного доступа, другим (внешним) классам не
разрешается импортировать и присваивать тип. Однако они все равно могут получать
ссылки на объекты этого типа.

public class OuterClass {

private class InnerClass{}

public InnerClass makeInnerClass() {


return new InnerClass();
}
}

public class AnotherClass {

public static void main(String[] args) {


OuterClass o = new OuterClass();

InnerClass x = o.makeInnerClass(); //Illegal, can't find type


OuterClass.InnerClass x = o.makeInnerClass(); //Illegal, InnerClass has visibility
private
Object x = o.makeInnerClass(); //Legal
}
}

Анонимные внутренние классы

https://riptutorial.com/ru/home 315
Анонимный внутренний класс является формой внутреннего класса, который объявляется
и создается с помощью одного утверждения. Как следствие, нет названия для класса,
который можно использовать в другом месте программы; т.е. анонимно.

Анонимные классы обычно используются в ситуациях, когда вам нужно создать легкий
класс для передачи в качестве параметра. Обычно это делается с помощью интерфейса.
Например:

public static Comparator<String> CASE_INSENSITIVE =


new Comparator<String>() {
@Override
public int compare(String string1, String string2) {
return string1.toUpperCase().compareTo(string2.toUpperCase());
}
};

Этот анонимный класс определяет объект Comparator<String> ( CASE_INSENSITIVE ), который


сравнивает две строки, игнорируя различия в случае.

Другие интерфейсы, которые часто реализуются и создаются с использованием


анонимных классов, являются Runnable и Callable . Например:

// An anonymous Runnable class is used to provide an instance that the Thread


// will run when started.
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Hello world");
}
});
t.start(); // Prints "Hello world"

Анонимные внутренние классы также могут основываться на классах. В этом случае


анонимный класс неявно extends существующий класс. Если расширяемый класс является
абстрактным, то анонимный класс должен реализовать все абстрактные методы. Он также
может переопределять не абстрактные методы.

Конструкторы
Анонимный класс не может иметь явный конструктор. Вместо этого определяется неявный
конструктор, который использует super(...) для передачи любых параметров конструктору
в расширяемом классе. Например:

SomeClass anon = new SomeClass(1, "happiness") {


@Override
public int someMethod(int arg) {
// do something
}
};

https://riptutorial.com/ru/home 316
SomeClass конструктор для нашего анонимного подкласса SomeClass вызовет конструктор
SomeClass который соответствует сигнатуре вызова SomeClass(int, String) . Если конструктор
недоступен, вы получите ошибку компиляции. Любые исключения, создаваемые
согласованным конструктором, также выдаются неявным конструктором.

Естественно, это не работает при расширении интерфейса. Когда вы создаете анонимный


класс из интерфейса, суперкласс класса представляет собой java.lang.Object которого есть
только конструктор no-args.

Метод Местные Внутренние Классы

Класс, написанный внутри метода, называемого локальным внутренним классом метода .


В этом случае объем внутреннего класса ограничен в рамках метода.

Локальный внутренний класс метода может быть создан только внутри метода, где
определяется внутренний класс.

Пример использования локального внутреннего класса метода:

public class OuterClass {


private void outerMethod() {
final int outerInt = 1;
// Method Local Inner Class
class MethodLocalInnerClass {
private void print() {
System.out.println("Method local inner class " + outerInt);
}
}
// Accessing the inner class
MethodLocalInnerClass inner = new MethodLocalInnerClass();
inner.print();
}

public static void main(String args[]) {


OuterClass outer = new OuterClass();
outer.outerMethod();
}
}

Выполнение даст результат: Method local inner class 1 .

Доступ к внешнему классу из нестатического внутреннего класса

Ссылка на внешний класс использует имя класса, и this

public class OuterClass {


public class InnerClass {
public void method() {
System.out.println("I can access my enclosing class: " + OuterClass.this);
}
}
}

https://riptutorial.com/ru/home 317
Вы можете напрямую обращаться к полям и методам внешнего класса.

public class OuterClass {


private int counter;

public class InnerClass {


public void method() {
System.out.println("I can access " + counter);
}
}
}

Но в случае столкновения имен вы можете использовать ссылку на внешний класс.

public class OuterClass {


private int counter;

public class InnerClass {


private int counter;

public void method() {


System.out.println("My counter: " + counter);
System.out.println("Outer counter: " + OuterClass.this.counter);

// updating my counter
counter = OuterClass.this.counter;
}
}
}

Создать экземпляр нестатического внутреннего класса извне

Внутренний класс, который видим любому внешнему классу, также может быть создан из
этого класса.

Внутренний класс зависит от внешнего класса и требует ссылки на его экземпляр. Чтобы
создать экземпляр внутреннего класса, new оператор нужно вызвать только в экземпляре
внешнего класса.

class OuterClass {

class InnerClass {
}
}

class OutsideClass {

OuterClass outer = new OuterClass();

OuterClass.InnerClass createInner() {
return outer.new InnerClass();
}
}

https://riptutorial.com/ru/home 318
Обратите внимание на использование как outer.new .

Прочитайте Вложенные и внутренние классы онлайн: https://riptutorial.com/ru/java/topic/3317/


вложенные-и-внутренние-классы

https://riptutorial.com/ru/home 319
глава 60: Возможности Java SE 7
Вступление
В этом разделе вы найдете краткое описание новых функций, добавленных в язык
программирования Java в Java SE 7. В других областях, таких как JDBC и Java Virtual
Machine (JVM), есть много других новых функций, которые не будут охвачены в этой теме.

замечания
Усовершенствования в Java SE 7

Examples

Новые возможности языка программирования Java SE 7

• Бинарные литералы : интегральные типы (байт, короткий, int и long) также могут быть
выражены с использованием системы двоичных чисел. Чтобы указать бинарный
литерал, добавьте префикс 0b или 0B в число.
• Строки в операторах switch : вы можете использовать объект String в выражении
оператора switch
• Заявление try-with-resources: оператор try-with-resources представляет собой оператор
try, который объявляет один или несколько ресурсов. Ресурс - это объект, который
должен быть закрыт после завершения программы. Оператор try-with-resources
гарантирует, что каждый ресурс будет закрыт в конце инструкции. В качестве
ресурса может использоваться любой объект, реализующий java.lang.AutoCloseable,
который включает в себя все объекты, которые реализуют java.io.Closeable.
• Улавливание множественных типов исключений и исключение исключений с
улучшенным контролем типов : один блок catch может обрабатывать более одного
типа исключения. Эта функция может уменьшить дублирование кода и уменьшить
соблазн, чтобы поймать чрезмерно широкое исключение.
• Подчеркивания в числовых литералах : любое число символов подчеркивания (_)
может отображаться где угодно между цифрами в числовом литерале. Эта функция
позволяет вам, например, разделять группы цифр в числовых литералах, что может
улучшить читаемость вашего кода.
• Вывод типа для создания Generic Instance : вы можете заменить аргументы типа,
необходимые для вызова конструктора родового класса с пустым набором параметров
типа (<>), если компилятор может вывести аргументы типа из контекста. Эта пара
угловых скобок неофициально называется алмазом.
• Улучшенные предупреждения и ошибки компилятора при использовании
невосстанавливаемых формальных параметров с помощью методов Varargs

https://riptutorial.com/ru/home 320
Бинарные литералы

// An 8-bit 'byte' value:


byte aByte = (byte)0b00100001;

// A 16-bit 'short' value:


short aShort = (short)0b1010000101000101;

// Some 32-bit 'int' values:


int anInt1 = 0b10100001010001011010000101000101;
int anInt2 = 0b101;
int anInt3 = 0B101; // The B can be upper or lower case.

// A 64-bit 'long' value. Note the "L" suffix:


long aLong = 0b1010000101000101101000010100010110100001010001011010000101000101L;

Оператор try-with-resources

В примере читается первая строка из файла. Он использует экземпляр BufferedReader для


чтения данных из файла. BufferedReader - это ресурс, который должен быть закрыт после
завершения программы:

static String readFirstLineFromFile(String path) throws IOException {


try (BufferedReader br = new BufferedReader(new FileReader(path))) {
return br.readLine();
}
}

В этом примере ресурс, объявленный в инструкции try-with-resources, представляет собой


BufferedReader . Оператор объявления появляется в круглых скобках сразу после ключевого
слова try. Класс BufferedReader , в Java SE 7 и более поздних версиях, реализует интерфейс
java.lang.AutoCloseable . Поскольку экземпляр BufferedReader объявлен в инструкции try-with-
resource, он будет закрыт независимо от того, завершает ли оператор try нормально или
внезапно (в результате метода BufferedReader.readLine генерирует IOException ).

Подчеркивает числовые литералы

В следующем примере показаны другие способы использования подчеркивания в числовых


литералах:

long creditCardNumber = 1234_5678_9012_3456L;


long socialSecurityNumber = 999_99_9999L;
float pi = 3.14_15F;
long hexBytes = 0xFF_EC_DE_5E;
long hexWords = 0xCAFE_BABE;
long maxLong = 0x7fff_ffff_ffff_ffffL;
byte nybbles = 0b0010_0101;
long bytes = 0b11010010_01101001_10010100_10010010;

Вы можете разместить символы подчеркивания только между цифрами; вы не можете

https://riptutorial.com/ru/home 321
размещать символы подчеркивания в следующих местах:

• В начале или конце номера


• Рядом с десятичной точкой в литерале с плавающей запятой
• До суффикса F или L
• В позициях, где ожидается строка цифр

Тип вывода для создания общего экземпляра

Ты можешь использовать

Map<String, List<String>> myMap = new HashMap<>();

вместо

Map<String, List<String>> myMap = new HashMap<String, List<String>>();

Однако вы не можете использовать

List<String> list = new ArrayList<>();


list.add("A");

// The following statement should fail since addAll expects


// Collection<? extends String>

list.addAll(new ArrayList<>());

потому что он не может скомпилировать. Обратите внимание, что бриллиант часто


работает в методах; однако предлагается использовать алмаз в основном для объявлений
переменных.

Строки в операторах

public String getTypeOfDayWithSwitchStatement(String dayOfWeekArg) {


String typeOfDay;
switch (dayOfWeekArg) {
case "Monday":
typeOfDay = "Start of work week";
break;
case "Tuesday":
case "Wednesday":
case "Thursday":
typeOfDay = "Midweek";
break;
case "Friday":
typeOfDay = "End of work week";
break;
case "Saturday":
case "Sunday":
typeOfDay = "Weekend";
break;

https://riptutorial.com/ru/home 322
default:
throw new IllegalArgumentException("Invalid day of the week: " + dayOfWeekArg);
}
return typeOfDay;
}

Прочитайте Возможности Java SE 7 онлайн: https://riptutorial.com/ru/java/topic/8272/


возможности-java-se-7

https://riptutorial.com/ru/home 323
глава 61: Возможности Java SE 8
Вступление
В этом разделе вы найдете резюме новых функций, добавленных в язык программирования
Java в Java SE 8. В других областях, таких как JDBC и Java Virtual Machine (JVM), есть
много других новых функций, которые не будут охвачены в этой теме.

замечания
Ссылка: Усовершенствования в Java SE 8

Examples

Новые возможности языка программирования Java SE 8

• В этом выпуске была представлена новая функция языка Lambda Expressions . Они
позволяют вам рассматривать функциональность как аргумент метода или код как
данные. Лямбда-выражения позволяют более компактно выражать экземпляры
интерфейсов с одним методом (называемые функциональными интерфейсами).
○Ссылки на методы предоставляют легко читаемые лямбда-выражения для
методов, которые уже имеют имя.
○Способы по умолчанию позволяют добавлять новые функциональные
возможности в интерфейсы библиотек и обеспечивать двоичную совместимость
с кодом, написанным для более старых версий этих интерфейсов.
○Новые и усовершенствованные API-интерфейсы, которые используют
выражения лямбда-выражения и потоки в Java SE 8, описывают новые и
расширенные классы, которые используют лямбда-выражения и потоки.
• Улучшенный вывод типа. Компилятор Java использует целевую типизацию для
вывода параметров типа общего вызова метода. Целевой тип выражения - это тип
данных, который ожидает компилятор Java в зависимости от того, где выражается
выражение. Например, вы можете использовать целевой тип задания назначения для
вывода типа в Java SE 7. Однако в Java SE 8 вы можете использовать целевой тип
для вывода типа в других контекстах.
○Целевой ввод в выражениях лямбда
○Вывод типа
• Повторяющиеся аннотации предоставляют возможность применять один и тот же тип
аннотации более одного раза к одному и тому же объявлению или типу
использования.
• Типовые аннотации предоставляют возможность применять аннотацию везде, где
используется тип, а не только для объявления. Эта функция, используемая с

https://riptutorial.com/ru/home 324
подключаемой системой типа, позволяет улучшить проверку вашего кода.
• Отражение параметра метода. Вы можете получить имена формальных параметров
любого метода или конструктора с помощью метода
java.lang.reflect.Executable.getParameters . (Класс Method и Constructor расширяет класс
Executable и поэтому наследует метод Executable.getParameters ). Однако .class не
сохраняют формальные имена параметров по умолчанию. Чтобы сохранить
формальные имена параметров в конкретном .class файл, и , таким образом ,
позволяет Reflection API , чтобы получить формальные имена параметров,
компилировать исходный файл с - -parameters выбором JAVAC компилятора.
• Date-time-api - добавлено новое время api в java.time . Если это используется, вам не
нужно указывать часовой пояс.

Прочитайте Возможности Java SE 8 онлайн: https://riptutorial.com/ru/java/topic/8267/


возможности-java-se-8

https://riptutorial.com/ru/home 325
глава 62: Выбор коллекций
Вступление
Java предлагает широкий выбор коллекций. Выбор какой коллекции для использования
может быть сложным. См. Раздел «Примеры» для простой в использовании блок-схемы,
чтобы выбрать нужную коллекцию для задания.

Examples

Блок-схема Java Collections

Используйте следующую блок-схему, чтобы выбрать нужную коллекцию для задания.

Эта блок-схема была основана на [ http://i.stack.imgur.com/aSDsG.png) .

Прочитайте Выбор коллекций онлайн: https://riptutorial.com/ru/java/topic/10846/выбор-


коллекций

https://riptutorial.com/ru/home 326
глава 63: Выражения
Вступление
Выражения в Java являются основной конструкцией для выполнения вычислений.

замечания
Для справки о операторах, которые можно использовать в выражениях, см. Операторы .

Examples

Приоритет оператора

Когда выражение содержит несколько операторов, его потенциально можно читать по-
разному. Например, математическое выражение 1 + 2 x 3 можно читать двумя способами:

1. Добавьте 1 и 2 и умножьте результат на 3 . Это дает ответ 9 . Если мы добавим


круглые скобки, это будет выглядеть как ( 1 + 2 ) x 3 .
2. Добавьте 1 к результату умножения 2 и 3 . Это дает ответ 7 . Если мы добавим
круглые скобки, это будет выглядеть как 1 + ( 2 x 3 ) .

В математике соглашение состоит в том, чтобы читать выражение вторым способом.


Общее правило заключается в том, что умножение и деление выполняются до сложения и
вычитания. Когда используется более продвинутая математическая нотация, либо
значение либо «самоочевидно» (для обученного математика!), Либо круглые скобки
добавляются для устранения неоднозначности. В любом случае эффективность
обозначений для передачи смысла зависит от интеллекта и общих знаний математиков.

В Java есть четкие правила о том, как читать выражение, основанное на приоритете
используемых операторов.

В общем случае каждому оператору приписывается значение приоритета ; см. таблицу


ниже.

Например:

1 + 2 * 3

Приоритет + меньше приоритета * , поэтому результат выражения равен 7, а не 9.

https://riptutorial.com/ru/home 327
Операторы /
Описание конструкции старшинство Ассоциативность
(первичные)

спецификатор имя . название


Скобки ( expr )
Создание экземпляра new
Доступ к полям первичный . название 15 Слева направо
Доступ к массиву primary [ expr ]
Вызов метода primary ( expr, ... )
Ссылка на метод primary :: name

Пошаговый прирост expr ++ , expr -- 14 -

Предварительное ++ expr, -- expr,


-
увеличение + expr, - expr, ~ expr !
13 Справа налево
Одинарный выраж,
Справа налево
В ролях 1 ( тип ) expr

Multiplicative * /% 12 Слева направо

присадка +- 11 Слева направо

сдвиг << >> >>> 10 Слева направо

реляционный <> <=> = instanceof 9 Слева направо

равенство ==! = 8 Слева направо

Побитовое И & 7 Слева направо

Побитовое
^ 6 Слева направо
исключение ИЛИ

Побитовое включение
| 5 Слева направо
ИЛИ

Логические И && 4 Слева направо

Логический ИЛИ || 3 Слева направо

Условный 1 ?: 2 Справа налево

= * = / =% = + = - = << = >>
присваивание
= >>> = & = ^ = | = 1 Справа налево
Лямбда 1
->

https://riptutorial.com/ru/home 328
1Приоритет экспрессии Lambda является сложным, так как он также может возникать
после литья или в качестве третьей части условного тернарного оператора.

Константные выражения

Постоянное выражение является выражением, которое дает примитивный тип или String, и
значение которого может быть оценено во время компиляции до литерала. Выражение
должно оцениваться без исключения исключения и должно состоять только из
следующего:

• Примитивные и строковые литералы.

• Набирает типы для примитивных типов или String .

• Следующие унарные операторы: + , - , ~ и ! ,

• Следующие бинарные операторы: * , / , % , + , - , << , >> , >>> , < , <= , > , >= , == != , & , ^ , | ,
&& и || ,

• Тернарный условный оператор ? : .

• Ориентированные на скобки выражения.

• Простые имена, относящиеся к постоянным переменным. (Постоянная переменная -


это переменная, объявленная как final где выражение инициализатора само
является константным выражением.)

• Квалифицированные имена формы <TypeName> . <Identifier> которые относятся к


постоянным переменным.

Обратите внимание, что в приведенном выше списке исключаются ++ и -- , операторы


присваивания, class и instanceof , вызовы методов и ссылки на общие переменные или поля.

Константные выражения типа String приводят к «интернированной» String , а операции с


плавающей запятой в константных выражениях оцениваются с помощью FP-строгой
семантики.

Использование для константных выражений


Константные выражения могут использоваться (примерно) в любом месте, где может
использоваться нормальное выражение. Однако они имеют особое значение в следующих
контекстах.

Для операторов case в операторах switch требуются константные выражения. Например:

switch (someValue) {

https://riptutorial.com/ru/home 329
case 1 + 1: // OK
case Math.min(2, 3): // Error - not a constant expression
doSomething();
}

Когда выражение в правой части присваивания является постоянным выражением, тогда


назначение может выполнять примитивное сужение преобразования. Это разрешено при
условии, что значение константного выражения находится в пределах диапазона типа с
левой стороны. (См. JLS 5.1.3 и 5.2 ) Например:

byte b1 = 1 + 1; // OK - primitive narrowing conversion.


byte b2 = 127 + 1; // Error - out of range
byte b3 = b1 + 1; // Error - not a constant expession
byte b4 = (byte) (b1 + 1); // OK

Когда константное выражение используется как условие в do , while или for , то оно влияет
на анализ читаемости. Например:

while (false) {
doSomething(); // Error - statenent not reachable
}
boolean flag = false;
while (flag) {
doSomething(); // OK
}

(Обратите внимание , что это не относится , if заявления. Компилятор Java позволяет then
или else блок , if оператор будет недоступен. Это аналог Java условной компиляции в C и
C ++.)

Наконец, static final поля в классе или интерфейсе с постоянными инициализаторами


выражения инициализируются с нетерпением. Таким образом, гарантируется, что эти
константы будут наблюдаться в инициализированном состоянии, даже если в графике
зависимостей инициализации класса есть цикл.

Для получения дополнительной информации см. JLS 15.28. Константные выражения .

Порядок оценки выражений

Выражения Java оцениваются по следующим правилам:

• Операнды оцениваются слева направо.


• Операторы оператора оцениваются перед оператором.
• Операторы оцениваются в соответствии с приоритетом оператора
• Списки аргументов оцениваются слева направо.

Простой пример

https://riptutorial.com/ru/home 330
В следующем примере:

int i = method1() + method2();

порядок оценки:

1. Левый операнд оператора = вычисляется по адресу i .


2. Вычисляется левый операнд оператора + ( method1() ).
3. method2() правый операнд оператора + ( method2() ).
4. + операция + .
5. Операция = вычисляется, присваивая результат добавления к i .

Обратите внимание, что если эффекты вызовов наблюдаемы, вы сможете заметить, что
вызов method1 происходит до вызова method2 .

Пример с оператором, который имеет побочный эффект


В следующем примере:

int i = 1;
intArray[i] = ++i + 1;

порядок оценки:

1. Вычисляется левый операнд оператора = . Это дает адрес intArray[1] .


2. Оценивается предварительный прирост. Это добавляет 1 к i и оценивает до 2 .
3. Проверяется правый операнд + .
4. Операция + оценивается как: 2 + 1 -> 3 .
5. Операция = вычисляется, присваивая значение 3 intArray[1] .

Обратите внимание, что, поскольку левый операнд = сначала оценивается, на него не


влияет побочный эффект подвыражения ++i .

Ссылка:

• JLS 15.7 - Порядок оценки

Основы экспрессии

Выражения в Java являются основной конструкцией для выполнения вычислений. Вот


некоторые примеры:

1 // A simple literal is an expression


1 + 2 // A simple expression that adds two numbers
(i + j) / k // An expression with multiple operations
(flag) ? c : d // An expression using the "conditional" operator
(String) s // A type-cast is an expression

https://riptutorial.com/ru/home 331
obj.test() // A method call is an expression
new Object() // Creation of an object is an expression
new int[] // Creation of an object is an expression

В общем случае выражение состоит из следующих форм:

• Имена выражений, которые состоят из:


Простые идентификаторы; например, someIdentifier

Квалифицированные идентификаторы; например MyClass.someField


• Первичные, состоящие из:


литералы; например, 1 , 1.0 , 'X' , "hello" , false и null

Литеральные выражения класса; например, MyClass.class


this и <TypeName> . this


Семантические выражения; например ( a + b )


Выражения создания экземпляра класса; например, new MyClass(1, 2, 3)


Выражения создания экземпляра массива; например, new int[3]


Выражения доступа к полю; например obj.someField или this.someField


Выражения доступа к массиву; например, vector[21]


Вызов метода; например obj.doIt(1, 2, 3)


Ссылки на методы (Java 8 и более поздние версии); например MyClass::doIt


• Унарные выражения оператора; eg !a или i++


• Бинарные выражения оператора; например a + b или obj == null
• Тернарные выражения оператора; например (obj == null) ? 1 : obj.getCount()
• Лямбда-выражения (Java 8 и более поздние версии); например obj -> obj.getCount()

Подробности различных форм выражений можно найти в других разделах.

• В разделе « Операторы» рассматриваются унарные, двоичные и тернарные


выражения операторов.
• В выражении лямбда-выражений рассматриваются лямбда-выражения и ссылочные
выражения методов.
• Тема « Классы и объекты» охватывает выражения создания экземпляра класса.
• В разделе « Массивы» рассматриваются выражения доступа к массиву и выражения
создания экземпляра массива.
• В литературной теме рассматриваются различные виды литературных выражений.

Тип выражения
В большинстве случаев выражение имеет статический тип, который можно определить во
время компиляции путем изучения и его подвыражений. Они называются автономными
выражениями.

Однако (в Java 8 и более поздних версиях) следующие выражения могут быть поли
выражениями :

https://riptutorial.com/ru/home 332
• Семантические выражения
• Выражения создания экземпляра класса
• Выражения вызова метода
• Справочные выражения метода
• Условные выражения
• Лямбда-выражения

Когда выражение является поли-выражением, на его тип может влиять целевой тип
выражения; т.е. для чего он используется.

Значение выражения
Значение выражения - это присвоение, совместимое с его типом. Исключением является
то, когда произошло загрязнение кучи ; например, потому что предупреждения
«небезопасного преобразования» были (ненадлежащим образом) подавлены или
проигнорированы.

Выражения выражений
В отличие от многих других языков, Java обычно не позволяет выражениям
использоваться в качестве операторов. Например:

public void compute(int i, int j) {


i + j; // ERROR
}

Поскольку результат оценки такого выражения не может быть использован, и поскольку


он не может повлиять на выполнение программы каким-либо другим способом,
разработчики Java приняли позицию, что такое использование является либо ошибкой,
либо ошибочным.

Однако это не относится ко всем выражениям. Подмножество выражений (фактически)


является законным как утверждения. Набор содержит:

• Выражение присваивания, включая операции-и- назначения.


• Предварительные и последующие выражения приращения и уменьшения.
• Вызов метода ( void или void ).
• Выражения экземпляра класса.

Прочитайте Выражения онлайн: https://riptutorial.com/ru/java/topic/8167/выражения

https://riptutorial.com/ru/home 333
глава 64: Генерация случайных чисел
замечания
Ничто не является случайным, и поэтому javadoc называет эти числа псевдослучайными.
Эти числа создаются с помощью генератора псевдослучайных чисел .

Examples

Псевдо-случайные числа

Java предоставляет в составе пакета utils базовый генератор псевдослучайных чисел,


который называется « Random . Этот объект может использоваться для генерации
псевдослучайного значения как любого из встроенных числовых типов данных ( int , float и
т. Д.). Вы также можете использовать его для генерации случайного логического значения
или случайного массива байтов. Пример использования:

import java.util.Random;

...

Random random = new Random();


int randInt = random.nextInt();
long randLong = random.nextLong();

double randDouble = random.nextDouble(); //This returns a value between 0.0 and 1.0
float randFloat = random.nextFloat(); //Same as nextDouble

byte[] randBytes = new byte[16];


random.nextBytes(randBytes); //nextBytes takes a user-supplied byte array, and fills it with
random bytes. It returns nothing.

ПРИМЕЧАНИЕ. Этот класс производит только низкокачественные псевдослучайные числа


и никогда не должен использоваться для генерации случайных чисел для
криптографических операций или в других ситуациях, где важна более качественная
случайность (для этого вы хотели бы использовать класс SecureRandom , как указано ниже).
Объяснение различия между «безопасным» и «неуверенным» случайным образом выходит
за рамки этого примера.

Псевдо случайные числа в определенном диапазоне

Метод nextInt(int bound) Random принимает верхнюю эксклюзивную границу, то есть число,
которое возвращаемое случайное значение должно быть меньше. Однако только метод
nextInt принимает nextInt ; nextLong , nextDouble и т.п. нет.

https://riptutorial.com/ru/home 334
Random random = new Random();
random.nextInt(1000); // 0 - 999

int number = 10 + random.nextInt(100); // number is in the range of 10 to 109

Начиная с Java 1.7, вы также можете использовать ThreadLocalRandom ( источник ). Этот


класс обеспечивает поточно-безопасный PRNG (генератор псевдослучайных чисел).
Обратите внимание, что метод nextInt этого класса принимает как верхнюю, так и нижнюю
границу.

import java.util.concurrent.ThreadLocalRandom;

// nextInt is normally exclusive of the top value,


// so add 1 to make it inclusive
ThreadLocalRandom.current().nextInt(min, max + 1);

Обратите внимание, что в официальной документации указано, что nextInt(int bound)


может делать странные вещи, когда bound около 2 30 +1 (выделено курсивом):

Алгоритм немного сложный. Он отклоняет значения, которые приведут к


неравномерному распределению (из-за того, что 2 ^ 31 не делится на n).
Вероятность отклонения значения зависит от n. Наихудший случай равен n = 2
^ 30 + 1, для которого вероятность отклонения равна 1/2, а ожидаемое число
итераций до окончания цикла равно 2.

Другими словами, указание границы (немного) уменьшит производительность метода


nextInt , и это снижение производительности станет более выраженным, так как bound
приближается к половине максимального значения int.

Создание криптографически безопасных псевдослучайных чисел

Randomи ThreadLocalRandom достаточно хороши для повседневного использования, но у них


есть большая проблема: они основаны на линейном конгруэнтном генераторе , алгоритме,
выход которого можно предсказать довольно легко. Таким образом, эти два класса не
подходят для криптографических целей (таких как генерация ключей).

Можно использовать java.security.SecureRandom в ситуациях, когда требуется PRNG с


java.security.SecureRandom который очень трудно предсказать. Предсказание случайных
чисел, созданных экземплярами этого класса, достаточно сложно, чтобы обозначить класс
как криптографически безопасный .

import java.security.SecureRandom;
import java.util.Arrays;

public class Foo {


public static void main(String[] args) {
SecureRandom rng = new SecureRandom();
byte[] randomBytes = new byte[64];

https://riptutorial.com/ru/home 335
rng.nextBytes(randomBytes); // Fills randomBytes with random bytes (duh)
System.out.println(Arrays.toString(randomBytes));
}
}

Помимо криптографической защиты SecureRandom имеет гигантский период в 2 160 , по


сравнению с периодом Random s 2 48 . У этого есть один недостаток быть значительно
медленнее, чем Random и другие линейные PRNG, такие как Mersenne Twister и Xorshift .

Обратите внимание, что реализация SecureRandom зависит от платформы и поставщика.


По умолчанию SecureRandom (данный поставщиком SUN в sun.security.provider.SecureRandom ):

• на Unix-подобных системах, засеянных данными из /dev/random и / или /dev/urandom .


• в Windows, засеянных вызовами CryptGenRandom() в CryptoAPI .

Выбор случайных чисел без дубликатов

/**
* returns a array of random numbers with no duplicates
* @param range the range of possible numbers for ex. if 100 then it can be anywhere from 1-
100
* @param length the length of the array of random numbers
* @return array of random numbers with no duplicates.
*/
public static int[] getRandomNumbersWithNoDuplicates(int range, int length){
if (length<range){
// this is where all the random numbers
int[] randomNumbers = new int[length];

// loop through all the random numbers to set them


for (int q = 0; q < randomNumbers.length; q++){

// get the remaining possible numbers


int remainingNumbers = range-q;

// get a new random number from the remainingNumbers


int newRandSpot = (int) (Math.random()*remainingNumbers);

newRandSpot++;

// loop through all the possible numbers


for (int t = 1; t < range+1; t++){

// check to see if this number has already been taken


boolean taken = false;
for (int number : randomNumbers){
if (t==number){
taken = true;
break;
}
}

// if it hasnt been taken then remove one from the spots


if (!taken){
newRandSpot--;

https://riptutorial.com/ru/home 336
// if we have gone though all the spots then set the value
if (newRandSpot==0){
randomNumbers[q] = t;
}
}
}
}
return randomNumbers;
} else {
// invalid can't have a length larger then the range of possible numbers
}
return null;
}

Метод работает путем циклизации, хотя массив, который имеет размер запрашиваемой
длины и находит оставшуюся длину возможных чисел. Он устанавливает случайное число
этих возможных номеров newRandSpot и находит, что число внутри оставшегося числа
осталось. Он делает это, перебирая диапазон и проверяя, было ли это число уже
выполнено.

Например, если диапазон равен 5, а длина равна 3, и мы уже выбрали число 2. Тогда у нас
есть 4 оставшихся числа, поэтому мы получаем случайное число от 1 до 4 и прокручиваем
диапазон (5), пропуская любые числа что мы уже использовали (2).

Теперь предположим, что следующее число, выбранное между 1 и 4, равно 3. В первом


цикле мы получаем 1, который еще не был взят, поэтому мы можем удалить 1 из 3, сделав
его 2. Теперь во втором цикле мы получим 2, который был взят поэтому мы ничего не
делаем. Мы следуем этой схеме до тех пор, пока не дойдем до 4, где, как только мы удалим
1, она станет 0, поэтому мы устанавливаем новый randomNumber равным 4.

Создание случайных чисел с заданным семенем

//Creates a Random instance with a seed of 12345.


Random random = new Random(12345L);

//Gets a ThreadLocalRandom instance


ThreadLocalRandom tlr = ThreadLocalRandom.current();

//Set the instance's seed.


tlr.setSeed(12345L);

Использование одного и того же семени для генерации случайных чисел будет возвращать
одинаковые числа каждый раз, поэтому установка другого семени для каждого Random
экземпляра является хорошей идеей, если вы не хотите в итоге дублировать числа.

Хорошим методом получения Long который отличается для каждого вызова, является
System.currentTimeMillis() :

https://riptutorial.com/ru/home 337
Random random = new Random(System.currentTimeMillis());
ThreadLocalRandom.current().setSeed(System.currentTimeMillis());

Создание случайного числа с использованием apache-common lang3

Мы можем использовать org.apache.commons.lang3.RandomUtils для генерации случайных


чисел с использованием одной строки.

int x = RandomUtils.nextInt(1, 1000);

Метод nextInt(int startInclusive, int endExclusive) принимает диапазон.

Помимо int, мы можем генерировать случайные long , double , float и bytes используя этот
класс.

Класс RandomUtils содержит следующие методы:

static byte[] nextBytes(int count) //Creates an array of random bytes.


static double nextDouble() //Returns a random double within 0 - Double.MAX_VALUE
static double nextDouble(double startInclusive, double endInclusive) //Returns a random double
within the specified range.
static float nextFloat() //Returns a random float within 0 - Float.MAX_VALUE
static float nextFloat(float startInclusive, float endInclusive) //Returns a random float
within the specified range.
static int nextInt() //Returns a random int within 0 - Integer.MAX_VALUE
static int nextInt(int startInclusive, int endExclusive) //Returns a random integer within the
specified range.
static long nextLong() //Returns a random long within 0 - Long.MAX_VALUE
static long nextLong(long startInclusive, long endExclusive) //Returns a random long within
the specified range.

Прочитайте Генерация случайных чисел онлайн: https://riptutorial.com/ru/java/topic/890/


генерация-случайных-чисел

https://riptutorial.com/ru/home 338
глава 65: Геттеры и сеттеры
Вступление
В этой статье обсуждаются геттеры и сеттеры; стандартный способ обеспечения доступа к
данным в Java-классах.

Examples

Добавление геттеров и сеттеров

Инкапсуляция является базовой концепцией в ООП. Речь идет об обертывании данных и


кода в виде единого блока. В этом случае рекомендуется объявлять переменные как
private а затем обращаться к ним через Getters и Setters для просмотра и / или изменения
их.

public class Sample {


private String name;
private int age;

public int getAge() {


return age;
}

public void setAge(int age) {


this.age = age;
}

public String getName() {


return name;
}

public void setName(String name) {


this.name = name;
}
}

Эти частные переменные не могут быть доступны непосредственно извне класса.


Следовательно, они защищены от несанкционированного доступа. Но если вы хотите
просмотреть или изменить их, вы можете использовать Getters и Setters.

вернет текущее значение переменной xxx , в то время как вы можете установить


getXxx()
значение переменной xxx с помощью setXxx() .

Соглашение об именах методов (в переменной example называется variableName ):

• Все boolean переменные

https://riptutorial.com/ru/home 339
getVariableName() //Getter, The variable name should start with uppercase
setVariableName(..) //Setter, The variable name should start with uppercase

• boolean переменные

isVariableName() //Getter, The variable name should start with uppercase


setVariableName(...) //Setter, The variable name should start with uppercase

Публичные Getters и Setters являются частью определения свойства Java Bean.

Использование сеттера или геттера для реализации ограничения

Setters и Getters позволяют объекту содержать частные переменные, к которым можно


получить доступ и изменить с ограничениями. Например,

public class Person {

private String name;

public String getName() {


return name;
}

public void setName(String name) {


if(name!=null && name.length()>2)
this.name = name;
}
}

В этом классе Person есть единственная переменная: name . К этой переменной можно
обратиться с помощью getName() и изменить с помощью setName(String) , однако для
установки имени требуется, чтобы новое имя имеет длину более 2 символов и не должно
быть нулевым. Использование метода setter вместо того, чтобы публиковать name
переменной, позволяет другим устанавливать значение name с определенными
ограничениями. То же самое можно применить к методу геттера:

public String getName(){


if(name.length()>16)
return "Name is too large!";
else
return name;
}

В модифицированном getName() выше name возвращается, только если его длина меньше или
равна 16. В противном случае возвращается "Name is too large" . Это позволяет
программисту создавать переменные, которые достижимы и могут быть изменены, но, тем
не менее, они препятствуют нежелательным редактированию переменных.

Зачем использовать Getters и Setters?

https://riptutorial.com/ru/home 340
Рассмотрим базовый класс, содержащий объект с геттерами и сеттерами в Java:

public class CountHolder {


private int count = 0;

public int getCount() { return count; }


public void setCount(int c) { count = c; }
}

Мы не можем получить доступ к переменной count потому что она закрыта. Но мы можем
получить доступ к методам getCount() и setCount(int) потому что они общедоступны. Для
некоторых это может поставить вопрос; зачем вводить посредника? Почему бы просто
просто не считать их общедоступными?

public class CountHolder {


public int count = 0;
}

Для всех целей и задач эти два являются точно такими же, функционально. Разница
между ними - расширяемость. Подумайте, что говорит каждый класс:

• Во-первых : «У меня есть метод, который даст вам значение int и метод, который
установит это значение для другого int ».
• Во-вторых : «У меня есть int который вы можете установить и получить, как
пожелаете».

Они могут казаться похожими, но первый на самом деле гораздо более защищен по своей
природе; он только позволяет вам взаимодействовать с его внутренней природой, как она
диктует. Это оставляет мяч в его суде; он выбирает, как происходят внутренние
взаимодействия. Вторая сторона внесла свою внутреннюю реализацию извне и теперь не
только подвержена внешним пользователям, но, в случае API, привержена поддержке
этой реализации (или иным образом освобождает API, не поддерживающий обратную
совместимость).

Давайте рассмотрим, хотим ли мы синхронизировать доступ к изменению и доступу к


счету. Во-первых, это просто:

public class CountHolder {


private int count = 0;

public synchronized int getCount() { return count; }


public synchronized void setCount(int c) { count = c; }
}

но во втором примере это становится практически невозможным без прохождения и


изменения каждого места, на которое ссылается переменная count . Что еще хуже, если это
элемент, который вы предоставляете в библиотеке, которую вы будете потреблять
другими, у вас нет способа выполнить эту модификацию и вынуждены сделать жесткий

https://riptutorial.com/ru/home 341
выбор, упомянутый выше.

Поэтому он задает вопрос; являются ли общедоступные переменные когда-либо хорошей


(или, по крайней мере, не злой)?

Я не уверен. С одной стороны, вы можете увидеть примеры открытых переменных, которые


выдержали проверку времени (IE: переменная out ссылается System.out ). С другой стороны,
предоставление публичной переменной не приносит пользы за пределы чрезвычайно
минимальных накладных расходов и потенциального сокращения словесности. Мое
руководство здесь будет состоять в том, что если вы планируете делать переменную
публику, вы должны судить об этом против этих критериев с крайним предрассудком:

1. Переменные не должны иметь никаких мыслимых оснований когда - либо изменений


в его реализации. Это очень легко повредить (и, даже если вы все исправите,
требования могут измениться), поэтому геттеры / сеттеры - общий подход. Если у вас
будет общедоступная переменная, это действительно нужно продумать, особенно
если она будет выпущена в библиотеке / framework / API.
2. На переменную нужно ссылаться достаточно часто, чтобы гарантировать
минимальный выигрыш от сокращения подробностей. Я даже не думаю, что
накладные расходы на использование метода в сравнении с прямой ссылкой должны
рассматриваться здесь. Это слишком незначительно для того, что я с консервативной
оценкой должен составлять 99,9% приложений.

Там, наверное, больше, чем я не рассматривал с головы. Если вы когда-либо сомневаетесь,


всегда используйте геттеры / сеттеры.

Прочитайте Геттеры и сеттеры онлайн: https://riptutorial.com/ru/java/topic/3560/геттеры-и-


сеттеры

https://riptutorial.com/ru/home 342
глава 66: Даты и время (java.time. *)
Examples

Простые мануалы даты

Получить текущую дату.

LocalDate.now()

Получите вчерашнюю дату.

LocalDate y = LocalDate.now().minusDays(1);

Получить дату завтра

LocalDate t = LocalDate.now().plusDays(1);

Получите конкретную дату.

LocalDate t = LocalDate.of(1974, 6, 2, 8, 30, 0, 0);

В дополнение к методам « plus и « minus существует набор методов «с», которые можно
использовать для установки определенного поля в экземпляре LocalDate .

LocalDate.now().withMonth(6);

В приведенном выше примере возвращается новый экземпляр с месяцем, установленным в


июне (это отличается от java.util.Date где setMonth был проиндексирован 0, setMonth с 5
июня).

Поскольку манипуляции с LocalDate возвращают неизменяемые экземпляры LocalDate, эти


методы также могут быть соединены вместе.

LocalDate ld = LocalDate.now().plusDays(1).plusYears(1);

Это даст нам завтрашний день через год.

Дата и время

Дата и время без информации о часовом поясе

LocalDateTime dateTime = LocalDateTime.of(2016, Month.JULY, 27, 8, 0);

https://riptutorial.com/ru/home 343
LocalDateTime now = LocalDateTime.now();
LocalDateTime parsed = LocalDateTime.parse("2016-07-27T07:00:00");

Дата и время с информацией о часовом поясе

ZoneId zoneId = ZoneId.of("UTC+2");


ZonedDateTime dateTime = ZonedDateTime.of(2016, Month.JULY, 27, 7, 0, 0, 235, zoneId);
ZonedDateTime composition = ZonedDateTime.of(localDate, localTime, zoneId);
ZonedDateTime now = ZonedDateTime.now(); // Default time zone
ZonedDateTime parsed = ZonedDateTime.parse("2016-07-27T07:00:00+01:00[Europe/Stockholm]");

Дата и время со смещенной информацией (т. Е. Не учитываются изменения ДСТ)

ZoneOffset zoneOffset = ZoneOffset.ofHours(2);


OffsetDateTime dateTime = OffsetDateTime.of(2016, 7, 27, 7, 0, 0, 235, zoneOffset);
OffsetDateTime composition = OffsetDateTime.of(localDate, localTime, zoneOffset);
OffsetDateTime now = OffsetDateTime.now(); // Offset taken from the default ZoneId
OffsetDateTime parsed = OffsetDateTime.parse("2016-07-27T07:00:00+02:00");

Операции по датам и времени

LocalDate tomorrow = LocalDate.now().plusDays(1);


LocalDateTime anHourFromNow = LocalDateTime.now().plusHours(1);
Long daysBetween = java.time.temporal.ChronoUnit.DAYS.between(LocalDate.now(),
LocalDate.now().plusDays(3)); // 3
Duration duration = Duration.between(Instant.now(), ZonedDateTime.parse("2016-07-
27T07:00:00+01:00[Europe/Stockholm]"))

Мгновенный

Представляет мгновенное время. Можно рассматривать как оболочку вокруг метки


времени Unix.

Instant now = Instant.now();


Instant epoch1 = Instant.ofEpochMilli(0);
Instant epoch2 = Instant.parse("1970-01-01T00:00:00Z");
java.time.temporal.ChronoUnit.MICROS.between(epoch1, epoch2); // 0

Использование различных классов API Date Time

Следующий пример также содержит объяснение, необходимое для понимания примера


внутри него.

import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;

https://riptutorial.com/ru/home 344
import java.util.TimeZone;
public class SomeMethodsExamples {

/**
* Has the methods of the class {@link LocalDateTime}
*/
public static void checkLocalDateTime() {
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println("Local Date time using static now() method ::: >>> "
+ localDateTime);

LocalDateTime ldt1 = LocalDateTime.now(ZoneId.of(ZoneId.SHORT_IDS


.get("AET")));
System.out
.println("LOCAL TIME USING now(ZoneId zoneId) method ::: >>>>"
+ ldt1);

LocalDateTime ldt2 = LocalDateTime.now(Clock.system(ZoneId


.of(ZoneId.SHORT_IDS.get("PST"))));
System.out
.println("Local TIME USING now(Clock.system(ZoneId.of())) ::: >>>> "
+ ldt2);

System.out
.println("Following is a static map in ZoneId class which has mapping of short
timezone names to their Actual timezone names");
System.out.println(ZoneId.SHORT_IDS);

/**
* This has the methods of the class {@link LocalDate}
*/
public static void checkLocalDate() {
LocalDate localDate = LocalDate.now();
System.out.println("Gives date without Time using now() method. >> "
+ localDate);
LocalDate localDate2 = LocalDate.now(ZoneId.of(ZoneId.SHORT_IDS
.get("ECT")));
System.out
.println("now() is overridden to take ZoneID as parametere using this we can get
the same date under different timezones. >> "
+ localDate2);
}

/**
* This has the methods of abstract class {@link Clock}. Clock can be used
* for time which has time with {@link TimeZone}.
*/
public static void checkClock() {
Clock clock = Clock.systemUTC();
// Represents time according to ISO 8601
System.out.println("Time using Clock class : " + clock.instant());
}

/**
* This has the {@link Instant} class methods.
*/
public static void checkInstant() {
Instant instant = Instant.now();

https://riptutorial.com/ru/home 345
System.out.println("Instant using now() method :: " + instant);

Instant ins1 = Instant.now(Clock.systemUTC());

System.out.println("Instants using now(Clock clock) :: " + ins1);

/**
* This class checks the methods of the {@link Duration} class.
*/
public static void checkDuration() {
// toString() converts the duration to PTnHnMnS format according to ISO
// 8601 standard. If a field is zero its ignored.

// P is the duration designator (historically called "period") placed at


// the start of the duration representation.
// Y is the year designator that follows the value for the number of
// years.
// M is the month designator that follows the value for the number of
// months.
// W is the week designator that follows the value for the number of
// weeks.
// D is the day designator that follows the value for the number of
// days.
// T is the time designator that precedes the time components of the
// representation.
// H is the hour designator that follows the value for the number of
// hours.
// M is the minute designator that follows the value for the number of
// minutes.
// S is the second designator that follows the value for the number of
// seconds.

System.out.println(Duration.ofDays(2));
}

/**
* Shows Local time without date. It doesn't store or represenet a date and
* time. Instead its a representation of Time like clock on the wall.
*/
public static void checkLocalTime() {
LocalTime localTime = LocalTime.now();
System.out.println("LocalTime :: " + localTime);
}

/**
* A date time with Time zone details in ISO-8601 standards.
*/
public static void checkZonedDateTime() {
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId
.of(ZoneId.SHORT_IDS.get("CST")));
System.out.println(zonedDateTime);

}
}

Форматирование даты

До Java 8 в пакете java.text классы DateFormat и SimpleDateFormat и этот устаревший код

https://riptutorial.com/ru/home 346
будет продолжать использоваться некоторое время.

Но Java 8 предлагает современный подход к обработке форматирования и анализа.

При форматировании и синтаксическом анализе сначала вы передаете объект String в


DateTimeFormatter и, в свою очередь, используете его для форматирования или
синтаксического анализа.

import java.time.*;
import java.time.format.*;

class DateTimeFormat
{
public static void main(String[] args) {

//Parsing
String pattern = "d-MM-yyyy HH:mm";
DateTimeFormatter dtF1 = DateTimeFormatter.ofPattern(pattern);

LocalDateTime ldp1 = LocalDateTime.parse("2014-03-25T01:30"), //Default format


ldp2 = LocalDateTime.parse("15-05-2016 13:55",dtF1); //Custom format

System.out.println(ldp1 + "\n" + ldp2); //Will be printed in Default format

//Formatting
DateTimeFormatter dtF2 = DateTimeFormatter.ofPattern("EEE d, MMMM, yyyy HH:mm");

DateTimeFormatter dtF3 = DateTimeFormatter.ISO_LOCAL_DATE_TIME;

LocalDateTime ldtf1 = LocalDateTime.now();

System.out.println(ldtf1.format(dtF2) +"\n"+ldtf1.format(dtF3));
}
}

Важное замечание, вместо использования пользовательских шаблонов, является хорошей


практикой для использования предопределенных форматировщиков. Ваш код выглядит
более понятным, и использование ISO8061 определенно поможет вам в долгосрочной
перспективе.

Вычислить разницу между 2 локальными датами

Используйте LocalDate и ChronoUnit :

LocalDate d1 = LocalDate.of(2017, 5, 1);


LocalDate d2 = LocalDate.of(2017, 5, 18);

теперь, поскольку метод between перечислением ChronoUnit принимает 2 Temporal параметра


как параметры, поэтому вы можете без проблем LocalDate экземплярами LocalDate<